[Yunq] Add ability to namespace declarations using "package".

This commit is contained in:
Drew Galbraith 2023-11-30 08:50:15 -08:00
parent 9fdd670a23
commit f1e09b2ae6
15 changed files with 153 additions and 10 deletions

View File

@ -6,6 +6,9 @@
#include <mammoth/util/debug.h> #include <mammoth/util/debug.h>
#include <zcall.h> #include <zcall.h>
{% if package != None %}
namespace {{package.cpp_namespace()}} {
{% endif %}
{% for interface in interfaces %} {% for interface in interfaces %}
{{interface.name}}Client::~{{interface.name}}Client() { {{interface.name}}Client::~{{interface.name}}Client() {
@ -61,3 +64,7 @@ glcr::ErrorCode {{interface.name}}Client::{{method.name}}(const {{method.request
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
{% if package != None %}
} // namepace {{package.cpp_namespace()}}
{% endif %}

View File

@ -8,6 +8,9 @@
#include "{{file}}.h" #include "{{file}}.h"
{% if package != None %}
namespace {{package.cpp_namespace()}} {
{% endif %}
{% for interface in interfaces -%} {% for interface in interfaces -%}
class {{interface.name}}Client { class {{interface.name}}Client {
public: public:
@ -37,3 +40,6 @@ class {{interface.name}}Client {
{%- endfor %} {%- endfor %}
{% if package != None %}
} // namepace {{package.cpp_namespace()}}
{% endif %}

View File

@ -1,3 +1,5 @@
package srv.file;
interface VFS { interface VFS {
method open (OpenFileRequest) -> (File); method open (OpenFileRequest) -> (File);
} }

View File

@ -3,9 +3,20 @@
#include <glacier/buffer/byte_buffer.h> #include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h> #include <glacier/buffer/cap_buffer.h>
#include <mammoth/util/debug.h>
#include <zcall.h> #include <zcall.h>
namespace srv::file {
VFSClient::~VFSClient() {
if (endpoint_ != 0) {
check(ZCapRelease(endpoint_));
}
}
@ -46,3 +57,7 @@ glcr::ErrorCode VFSClient::open(const OpenFileRequest& request, File& response)
} }
} // namepace srv::file

View File

@ -8,11 +8,15 @@
#include "example.yunq.h" #include "example.yunq.h"
namespace srv::file {
class VFSClient { class VFSClient {
public: public:
VFSClient(z_cap_t VFS_cap) : endpoint_(VFS_cap) {} VFSClient(z_cap_t VFS_cap) : endpoint_(VFS_cap) {}
VFSClient(const VFSClient&) = delete; VFSClient(const VFSClient&) = delete;
VFSClient(VFSClient&& other) : endpoint_(other.endpoint_) {other.endpoint_ = 0;}; VFSClient(VFSClient&& other) : endpoint_(other.endpoint_) {other.endpoint_ = 0;};
~VFSClient();
z_cap_t Capability() { return endpoint_; } z_cap_t Capability() { return endpoint_; }
@ -28,3 +32,6 @@ class VFSClient {
uint64_t kCapBufferSize = 0x10; uint64_t kCapBufferSize = 0x10;
glcr::CapBuffer cap_buffer_{kCapBufferSize}; glcr::CapBuffer cap_buffer_{kCapBufferSize};
}; };
} // namepace srv::file

View File

@ -1,6 +1,9 @@
// Generated file -- DO NOT MODIFY. // Generated file -- DO NOT MODIFY.
#include "example.yunq.h" #include "example.yunq.h"
namespace srv::file {
namespace { namespace {
const uint64_t header_size = 24; // 4x uint32, 1x uint64 const uint64_t header_size = 24; // 4x uint32, 1x uint64
@ -202,3 +205,6 @@ uint64_t File::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::
return next_extension; return next_extension;
} }
} // namepace srv::file

View File

@ -6,6 +6,10 @@
#include <glacier/container/vector.h> #include <glacier/container/vector.h>
#include <glacier/string/string.h> #include <glacier/string/string.h>
#include <ztypes.h> #include <ztypes.h>
namespace srv::file {
class OpenFileRequest { class OpenFileRequest {
public: public:
OpenFileRequest() {} OpenFileRequest() {}
@ -55,3 +59,6 @@ class File {
// Parses everything except for caps. // Parses everything except for caps.
void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset);
}; };
} // namepace srv::file

View File

@ -4,6 +4,9 @@
#include <mammoth/util/debug.h> #include <mammoth/util/debug.h>
#include <zcall.h> #include <zcall.h>
namespace srv::file {
namespace { namespace {
const uint32_t kSentinel = 0xBEEFDEAD; const uint32_t kSentinel = 0xBEEFDEAD;
@ -29,6 +32,18 @@ void VFSServerBaseThreadBootstrap(void* server_base) {
((VFSServerBase*)server_base)->ServerThread(); ((VFSServerBase*)server_base)->ServerThread();
} }
VFSServerBase::~VFSServerBase() {
if (endpoint_ != 0) {
check(ZCapRelease(endpoint_));
}
}
glcr::ErrorOr<z_cap_t> VFSServerBase::CreateClientCap() {
uint64_t client_cap;
RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap));
return client_cap;
}
glcr::ErrorOr<VFSClient> VFSServerBase::CreateClient() { glcr::ErrorOr<VFSClient> VFSServerBase::CreateClient() {
uint64_t client_cap; uint64_t client_cap;
RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap)); RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap));
@ -101,7 +116,9 @@ glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request,
RET_ERR(Handleopen(yunq_request, yunq_response)); RET_ERR(Handleopen(yunq_request, yunq_response));
resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps); resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps);
break; break;
} }
default: { default: {
@ -110,3 +127,7 @@ glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request,
} }
return glcr::OK; return glcr::OK;
} }
} // namepace srv::file

View File

@ -9,13 +9,19 @@
#include "example.yunq.client.h" #include "example.yunq.client.h"
namespace srv::file {
class VFSServerBase { class VFSServerBase {
public: public:
VFSServerBase(z_cap_t VFS_cap) : endpoint_(VFS_cap) {} VFSServerBase(z_cap_t VFS_cap) : endpoint_(VFS_cap) {}
VFSServerBase(const VFSServerBase&) = delete; VFSServerBase(const VFSServerBase&) = delete;
VFSServerBase(VFSServerBase&&) = delete; VFSServerBase(VFSServerBase&&) = delete;
virtual ~VFSServerBase();
glcr::ErrorOr<z_cap_t> CreateClientCap();
glcr::ErrorOr<VFSClient> CreateClient(); glcr::ErrorOr<VFSClient> CreateClient();
[[nodiscard]] Thread RunServer(); [[nodiscard]] Thread RunServer();
@ -37,3 +43,7 @@ class VFSServerBase {
glcr::CapBuffer& resp_caps); glcr::CapBuffer& resp_caps);
}; };
} // namepace srv::file

View File

@ -1,6 +1,9 @@
// Generated file -- DO NOT MODIFY. // Generated file -- DO NOT MODIFY.
#include "{{file}}.h" #include "{{file}}.h"
{% if package != None %}
namespace {{package.cpp_namespace()}} {
{% endif %}
namespace { namespace {
const uint64_t header_size = 24; // 4x uint32, 1x uint64 const uint64_t header_size = 24; // 4x uint32, 1x uint64
@ -188,3 +191,7 @@ uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t of
return next_extension; return next_extension;
} }
{%- endfor %} {%- endfor %}
{% if package != None %}
} // namepace {{package.cpp_namespace()}}
{% endif %}

View File

@ -7,6 +7,9 @@
#include <glacier/string/string.h> #include <glacier/string/string.h>
#include <ztypes.h> #include <ztypes.h>
{% if package != None %}
namespace {{package.cpp_namespace()}} {
{% endif %}
{%- for message in messages %} {%- for message in messages %}
class {{message.name}} { class {{message.name}} {
@ -44,3 +47,7 @@ class {{message.name}} {
void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset);
}; };
{%- endfor %} {%- endfor %}
{% if package != None %}
} // namepace {{package.cpp_namespace()}}
{% endif %}

View File

@ -16,6 +16,7 @@ class LexemeType(Enum):
RIGHT_PAREN = 6 RIGHT_PAREN = 6
ARROW = 7 ARROW = 7
SEMICOLON = 8 SEMICOLON = 8
DOT = 9
class Lexeme(): class Lexeme():
@ -55,6 +56,8 @@ def lexer(program: str):
tokens.append(Lexeme(LexemeType.RIGHT_PAREN)) tokens.append(Lexeme(LexemeType.RIGHT_PAREN))
elif curr == ';': elif curr == ';':
tokens.append(Lexeme(LexemeType.SEMICOLON)) tokens.append(Lexeme(LexemeType.SEMICOLON))
elif curr == '.':
tokens.append(Lexeme(LexemeType.DOT))
elif curr == '-': elif curr == '-':
current += 1 current += 1
if program[current] == '>': if program[current] == '>':
@ -77,6 +80,12 @@ def lexer(program: str):
return tokens return tokens
class Package():
def __init__(self, names: list[str]):
self.names = names
def cpp_namespace(self):
return "::".join(self.names)
class Method(): class Method():
def __init__(self, name: str, request: str, response: str): def __init__(self, name: str, request: str, response: str):
@ -174,11 +183,25 @@ class Parser():
token = self.consume() token = self.consume()
if token.type != LexemeType.NAME: if token.type != LexemeType.NAME:
sys.exit("Unexpected token: %s", token) sys.exit("Unexpected token: %s", token)
if token.value == "package":
# TODO: Enforce that package decl comes before all messages and interface.
return self.package()
if token.value == "message": if token.value == "message":
return self.message() return self.message()
elif token.value == "interface": elif token.value == "interface":
return self.interface() return self.interface()
sys.exit("Unexpected identifier '%s', expected message or interface" % token.value) sys.exit("Unexpected identifier '%s', expected package, message, interface" % token.value)
def package(self):
names = [self.consume_identifier()]
while self.peektype() == LexemeType.DOT:
self.consume_check(LexemeType.DOT)
names += [self.consume_identifier()]
self.consume_check(LexemeType.SEMICOLON)
return Package(names)
def interface(self): def interface(self):
# "interface" consumed by decl. # "interface" consumed by decl.
@ -273,6 +296,8 @@ class Parser():
return Field(field_type, name, repeated) return Field(field_type, name, repeated)
def type_check(decls: list[Decl]): def type_check(decls: list[Decl]):
if sum(1 for decl in decls if type(decl) is Package) > 1:
sys.exit("Cannot have more than one package declaration")
for decl in decls: for decl in decls:
if type(decl) is Interface: if type(decl) is Interface:
for method in decl.methods: for method in decl.methods:
@ -291,7 +316,9 @@ def type_check(decls: list[Decl]):
def print_ast(decls: list[Decl]): def print_ast(decls: list[Decl]):
for decl in decls: for decl in decls:
if type(decl) is Interface: if type(decl) is Package:
print("%s (Package)" % decl.cpp_namespace())
elif type(decl) is Interface:
print("%s (Interface)" % decl.name) print("%s (Interface)" % decl.name)
for method in decl.methods: for method in decl.methods:
print("\t%s (%s -> %s)" % (method.name, method.request, method.response)) print("\t%s (%s -> %s)" % (method.name, method.request, method.response))

View File

@ -4,6 +4,9 @@
#include <mammoth/util/debug.h> #include <mammoth/util/debug.h>
#include <zcall.h> #include <zcall.h>
{% if package != None %}
namespace {{package.cpp_namespace()}} {
{% endif %}
namespace { namespace {
const uint32_t kSentinel = 0xBEEFDEAD; const uint32_t kSentinel = 0xBEEFDEAD;
@ -133,3 +136,7 @@ glcr::ErrorCode {{interface.name}}ServerBase::HandleRequest(const glcr::ByteBuff
return glcr::OK; return glcr::OK;
} }
{% endfor %} {% endfor %}
{% if package != None %}
} // namepace {{package.cpp_namespace()}}
{% endif %}

View File

@ -8,6 +8,10 @@
#include "{{file}}.h" #include "{{file}}.h"
#include "{{file}}.client.h" #include "{{file}}.client.h"
{% if package != None %}
namespace {{package.cpp_namespace()}} {
{% endif %}
{% for interface in interfaces %} {% for interface in interfaces %}
class {{interface.name}}ServerBase { class {{interface.name}}ServerBase {
@ -44,3 +48,7 @@ class {{interface.name}}ServerBase {
}; };
{% endfor %} {% endfor %}
{% if package != None %}
} // namepace {{package.cpp_namespace()}}
{% endif %}

View File

@ -21,42 +21,48 @@ def main():
parser = Parser(lexemes) parser = Parser(lexemes)
ast = parser.parse() ast = parser.parse()
print_ast(ast)
type_check(ast) type_check(ast)
messages = [m for m in ast if type(m) is Message] messages = [m for m in ast if type(m) is Message]
interfaces = [i for i in ast if type(i) is Interface] interfaces = [i for i in ast if type(i) is Interface]
# We know there is only one package decl from the type_check.
packages = [p for p in ast if type(p) is Package]
package = None
if len(packages) == 1:
package = packages[0]
jinja_env = Environment(loader=FileSystemLoader(pathlib.Path(__file__).parent.resolve())) jinja_env = Environment(loader=FileSystemLoader(pathlib.Path(__file__).parent.resolve()))
message_header_tmpl = jinja_env.get_template("message.h.jinja") message_header_tmpl = jinja_env.get_template("message.h.jinja")
with open(filename + '.h', mode='w') as f: with open(filename + '.h', mode='w') as f:
message_header = message_header_tmpl.render(messages=messages) message_header = message_header_tmpl.render(messages=messages, package=package)
f.write(message_header) f.write(message_header)
message_impl_tmpl = jinja_env.get_template("message.cpp.jinja") message_impl_tmpl = jinja_env.get_template("message.cpp.jinja")
message_impl_tmpl.globals['Type'] = Type message_impl_tmpl.globals['Type'] = Type
with open(filename + '.cpp', mode='w') as f: with open(filename + '.cpp', mode='w') as f:
message_impl = message_impl_tmpl.render(file=filebase, messages=messages) message_impl = message_impl_tmpl.render(file=filebase, messages=messages, package=package)
f.write(message_impl) f.write(message_impl)
client_header_tmpl = jinja_env.get_template("client.h.jinja") client_header_tmpl = jinja_env.get_template("client.h.jinja")
with open(filename + '.client.h', mode='w') as f: with open(filename + '.client.h', mode='w') as f:
client_header = client_header_tmpl.render(file=filebase, interfaces=interfaces) client_header = client_header_tmpl.render(file=filebase, interfaces=interfaces, package=package)
f.write(client_header) f.write(client_header)
client_impl_tmpl = jinja_env.get_template("client.cpp.jinja") client_impl_tmpl = jinja_env.get_template("client.cpp.jinja")
with open(filename + '.client.cpp', mode='w') as f: with open(filename + '.client.cpp', mode='w') as f:
client_impl = client_impl_tmpl.render(file=filebase, interfaces=interfaces) client_impl = client_impl_tmpl.render(file=filebase, interfaces=interfaces, package=package)
f.write(client_impl) f.write(client_impl)
server_header_tmpl = jinja_env.get_template("server.h.jinja") server_header_tmpl = jinja_env.get_template("server.h.jinja")
with open(filename + '.server.h', mode='w') as f: with open(filename + '.server.h', mode='w') as f:
server_header = server_header_tmpl.render(file=filebase, interfaces=interfaces) server_header = server_header_tmpl.render(file=filebase, interfaces=interfaces, package=package)
f.write(server_header) f.write(server_header)
server_impl_tmpl = jinja_env.get_template("server.cpp.jinja") server_impl_tmpl = jinja_env.get_template("server.cpp.jinja")
with open(filename + '.server.cpp', mode='w') as f: with open(filename + '.server.cpp', mode='w') as f:
server_impl = server_impl_tmpl.render(file=filebase, interfaces=interfaces) server_impl = server_impl_tmpl.render(file=filebase, interfaces=interfaces, package=package)
f.write(server_impl) f.write(server_impl)
if __name__ == "__main__": if __name__ == "__main__":