[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 <zcall.h>
{% if package != None %}
namespace {{package.cpp_namespace()}} {
{% endif %}
{% for interface in interfaces %}
{{interface.name}}Client::~{{interface.name}}Client() {
@ -61,3 +64,7 @@ glcr::ErrorCode {{interface.name}}Client::{{method.name}}(const {{method.request
{% endfor %}
{% endfor %}
{% if package != None %}
} // namepace {{package.cpp_namespace()}}
{% endif %}

View File

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

View File

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

View File

@ -3,9 +3,20 @@
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <mammoth/util/debug.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"
namespace srv::file {
class VFSClient {
public:
VFSClient(z_cap_t VFS_cap) : endpoint_(VFS_cap) {}
VFSClient(const VFSClient&) = delete;
VFSClient(VFSClient&& other) : endpoint_(other.endpoint_) {other.endpoint_ = 0;};
~VFSClient();
z_cap_t Capability() { return endpoint_; }
@ -28,3 +32,6 @@ class VFSClient {
uint64_t kCapBufferSize = 0x10;
glcr::CapBuffer cap_buffer_{kCapBufferSize};
};
} // namepace srv::file

View File

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

View File

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

View File

@ -4,6 +4,9 @@
#include <mammoth/util/debug.h>
#include <zcall.h>
namespace srv::file {
namespace {
const uint32_t kSentinel = 0xBEEFDEAD;
@ -29,6 +32,18 @@ void VFSServerBaseThreadBootstrap(void* server_base) {
((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() {
uint64_t 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));
resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps);
break;
}
default: {
@ -110,3 +127,7 @@ glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request,
}
return glcr::OK;
}
} // namepace srv::file

View File

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

View File

@ -1,6 +1,9 @@
// Generated file -- DO NOT MODIFY.
#include "{{file}}.h"
{% if package != None %}
namespace {{package.cpp_namespace()}} {
{% endif %}
namespace {
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;
}
{%- endfor %}
{% if package != None %}
} // namepace {{package.cpp_namespace()}}
{% endif %}

View File

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

View File

@ -16,6 +16,7 @@ class LexemeType(Enum):
RIGHT_PAREN = 6
ARROW = 7
SEMICOLON = 8
DOT = 9
class Lexeme():
@ -55,6 +56,8 @@ def lexer(program: str):
tokens.append(Lexeme(LexemeType.RIGHT_PAREN))
elif curr == ';':
tokens.append(Lexeme(LexemeType.SEMICOLON))
elif curr == '.':
tokens.append(Lexeme(LexemeType.DOT))
elif curr == '-':
current += 1
if program[current] == '>':
@ -77,6 +80,12 @@ def lexer(program: str):
return tokens
class Package():
def __init__(self, names: list[str]):
self.names = names
def cpp_namespace(self):
return "::".join(self.names)
class Method():
def __init__(self, name: str, request: str, response: str):
@ -174,11 +183,25 @@ class Parser():
token = self.consume()
if token.type != LexemeType.NAME:
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":
return self.message()
elif token.value == "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):
# "interface" consumed by decl.
@ -273,6 +296,8 @@ class Parser():
return Field(field_type, name, repeated)
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:
if type(decl) is Interface:
for method in decl.methods:
@ -291,7 +316,9 @@ def type_check(decls: list[Decl]):
def print_ast(decls: list[Decl]):
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)
for method in decl.methods:
print("\t%s (%s -> %s)" % (method.name, method.request, method.response))

View File

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

View File

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

View File

@ -21,42 +21,48 @@ def main():
parser = Parser(lexemes)
ast = parser.parse()
print_ast(ast)
type_check(ast)
messages = [m for m in ast if type(m) is Message]
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()))
message_header_tmpl = jinja_env.get_template("message.h.jinja")
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)
message_impl_tmpl = jinja_env.get_template("message.cpp.jinja")
message_impl_tmpl.globals['Type'] = Type
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)
client_header_tmpl = jinja_env.get_template("client.h.jinja")
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)
client_impl_tmpl = jinja_env.get_template("client.cpp.jinja")
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)
server_header_tmpl = jinja_env.get_template("server.h.jinja")
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)
server_impl_tmpl = jinja_env.get_template("server.cpp.jinja")
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)
if __name__ == "__main__":