[Yunq] Add ability to namespace declarations using "package".
This commit is contained in:
parent
9fdd670a23
commit
f1e09b2ae6
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
package srv.file;
|
||||
|
||||
interface VFS {
|
||||
method open (OpenFileRequest) -> (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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
||||
|
|
18
yunq/yunq.py
18
yunq/yunq.py
|
@ -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__":
|
||||
|
|
Loading…
Reference in New Issue