[yunq] Add codegen for message parsing and serialization methods.
This commit is contained in:
parent
fdd2d693bc
commit
990dd4c1e1
|
@ -6,6 +6,7 @@ HEADER_PRELUDE = """
|
|||
#pragma once
|
||||
|
||||
#include <glacier/string/string.h>
|
||||
#include <ztypes.h>
|
||||
|
||||
"""
|
||||
|
||||
|
@ -18,7 +19,9 @@ class {name} {{
|
|||
{name}({name}&&) = delete;
|
||||
|
||||
void ParseFromBytes(const glcr::ByteBuffer&);
|
||||
glcr::ByteBuffer SerializeToBytes();
|
||||
void ParseFromBytes(const glcr::ByteBuffer&, const glcr::CapBuffer&);
|
||||
void SerializeToBytes(glcr::ByteBuffer&);
|
||||
void SerializeToBytes(glcr::ByteBuffer&, glcr::CapBuffer&);
|
||||
"""
|
||||
|
||||
MESSAGE_CLASS_SET_GET = """
|
||||
|
@ -37,14 +40,14 @@ MESSAGE_CLASS_FIELD = """
|
|||
"""
|
||||
|
||||
MESSAGE_CLASS_SUFFIX = """
|
||||
}
|
||||
};
|
||||
"""
|
||||
|
||||
type_to_str = {
|
||||
Type.U64: "uint64_t",
|
||||
Type.I64: "int64_t",
|
||||
Type.STRING: "glcr::String",
|
||||
Type.CAPABILITY: "zcap_t",
|
||||
Type.CAPABILITY: "z_cap_t",
|
||||
Type.BYTES: "glcr::Vector<uint8_t>"
|
||||
}
|
||||
|
||||
|
@ -89,6 +92,22 @@ struct ExtPointer {{
|
|||
uint32_t length;
|
||||
}}
|
||||
|
||||
void CheckHeader(const glcr::ByteBuffer& bytes) {{
|
||||
// TODO: Check ident.
|
||||
// TODO: Parse core size.
|
||||
// TODO: Parse extension size.
|
||||
// TODO: Check CRC32
|
||||
// TODO: Parse options.
|
||||
}}
|
||||
|
||||
void WriteHeader(glcr::ByteBuffer& bytes, uint32_t core_size, uint32_t extension_size) {{
|
||||
bytes.WriteAt<uint32_t>(0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence.
|
||||
bytes.WriteAt<uint32_t>(4, core_size);
|
||||
bytes.WriteAt<uint32_t>(8, extension_size);
|
||||
bytes.WriteAt<uint32_t>(12, 0); // TODO: Calculate CRC32.
|
||||
bytes.WriteAt<uint64_t>(16, 0); // TODO: Add options.
|
||||
}}
|
||||
|
||||
}} // namespace
|
||||
"""
|
||||
|
||||
|
@ -97,6 +116,11 @@ void {name}::ParseFromBytes(const glcr::ByteBuffer& bytes) {{
|
|||
CheckHeader();
|
||||
"""
|
||||
|
||||
IMPL_PARSE_DEF_CAP = """
|
||||
void {name}::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {{
|
||||
CheckHeader();
|
||||
"""
|
||||
|
||||
IMPL_PARSE_U64 = """
|
||||
set_{name}(bytes.At<uint64_t>(header_size + (8 * {offset})));
|
||||
"""
|
||||
|
@ -111,32 +135,128 @@ IMPL_PARSE_STRING = """
|
|||
set_{name}(bytes.StringAt({name}_pointer.offset, {name}_pointer.length));
|
||||
"""
|
||||
|
||||
IMPL_SET_CAP_EMPTY = """
|
||||
set_{name}(0);
|
||||
"""
|
||||
|
||||
IMPL_PARSE_CAP = """
|
||||
uint64_t {name}_ptr = bytes.At<uint64_t>(header_size + (8 * {offset}));
|
||||
|
||||
set_{name}(caps.at({name}_ptr));
|
||||
"""
|
||||
|
||||
IMPL_PARSE_DEF_END = """
|
||||
}
|
||||
"""
|
||||
|
||||
def _generate_message_class_impl(message: Message) -> str:
|
||||
impl = IMPL_PARSE_DEF.format(name=message.name)
|
||||
def _generate_message_parse_impl(message: Message) -> str:
|
||||
impl = ""
|
||||
|
||||
for offset, field in enumerate(message.fields):
|
||||
if field.type == Type.U64:
|
||||
impl += IMPL_PARSE_U64.format(name = field.name, offset = offset)
|
||||
elif field.type == Type.I64:
|
||||
impl += IMPL_PARSE_I64.format(name = field.name, offset = offset)
|
||||
elif field.type == Type.STRING:
|
||||
impl += IMPL_PARSE_STRING.format(name = field.name, offset = offset);
|
||||
else:
|
||||
impl += "\n{} unimplemented\n".format(field.type.name)
|
||||
for with_cap in (False, True):
|
||||
impl += IMPL_PARSE_DEF.format(name=message.name) if not with_cap else IMPL_PARSE_DEF_CAP.format(name=message.name)
|
||||
for offset, field in enumerate(message.fields):
|
||||
if field.type == Type.U64:
|
||||
impl += IMPL_PARSE_U64.format(name = field.name, offset = offset)
|
||||
elif field.type == Type.I64:
|
||||
impl += IMPL_PARSE_I64.format(name = field.name, offset = offset)
|
||||
elif field.type == Type.STRING:
|
||||
impl += IMPL_PARSE_STRING.format(name = field.name, offset = offset);
|
||||
elif field.type == Type.CAPABILITY:
|
||||
if with_cap:
|
||||
impl += IMPL_PARSE_CAP.format(name = field.name, offset = offset)
|
||||
else:
|
||||
impl += IMPL_SET_CAP_EMPTY.format(name = field.name)
|
||||
else:
|
||||
impl += "\n{} unimplemented\n".format(field.type.name)
|
||||
|
||||
impl += IMPL_PARSE_DEF_END
|
||||
impl += IMPL_PARSE_DEF_END
|
||||
|
||||
return impl
|
||||
|
||||
IMPL_SER_DEF = """
|
||||
{name}::SerializeToBytes(glcr::ByteBuffer& bytes) {{
|
||||
|
||||
uint32_t next_extension = header_size + 8 * {num_fields};
|
||||
const uint32_t core_size = next_extension;
|
||||
"""
|
||||
|
||||
IMPL_SER_CAP_DEF = """
|
||||
{name}::SerializeToBytes(glcr::ByteBuffer& bytes, glcr::CapBuffer& caps) {{
|
||||
|
||||
uint32_t next_extension = header_size + 8 * {num_fields};
|
||||
const uint32_t core_size = next_extension;
|
||||
uint64_t next_cap = 0;
|
||||
"""
|
||||
|
||||
IMPL_SER_U64 = """
|
||||
bytes.WriteAt<uint64_t>(header_size + (8 * {offset}), {name}());
|
||||
"""
|
||||
|
||||
IMPL_SER_I64 = """
|
||||
bytes.WriteAt<int64_t>(header_size + (8 * {offset}), {name}());
|
||||
"""
|
||||
|
||||
IMPL_SER_STRING = """
|
||||
ExtPointer {name}_ptr{{
|
||||
.offset = next_extension,
|
||||
// FIXME: Check downcast of str length.
|
||||
.length = {name}().length(),
|
||||
}};
|
||||
|
||||
bytes.WriteStringAt(next_extension, {name}());
|
||||
next_extension += {name}_ptr.length;
|
||||
|
||||
bytes.WriteAt<ExtPointer>(header_size + (8 * {offset}), {name}_ptr);
|
||||
"""
|
||||
|
||||
IMPL_SER_CAP_EMPTY = """
|
||||
// FIXME: Warn or error on serialization
|
||||
"""
|
||||
|
||||
IMPL_SER_CAP = """
|
||||
caps.Write(next_cap, {name}());
|
||||
bytes.WriteAt<uint64_t>(header_size + (8 * {offset}), next_cap++);
|
||||
"""
|
||||
|
||||
IMPL_SER_DEF_END = """
|
||||
// The next extension pointer is the length of the message.
|
||||
WriteHeader(bytes, core_size, next_extension);
|
||||
}
|
||||
"""
|
||||
def _generate_message_serialize_impl(message: Message) -> str:
|
||||
impl = ""
|
||||
|
||||
for with_cap in (False, True):
|
||||
if with_cap:
|
||||
impl += IMPL_SER_CAP_DEF.format(name = message.name, num_fields = len(message.fields))
|
||||
else:
|
||||
impl += IMPL_SER_DEF.format(name = message.name, num_fields = len(message.fields))
|
||||
|
||||
for offset, field in enumerate(message.fields):
|
||||
if field.type == Type.U64:
|
||||
impl += IMPL_SER_U64.format(name = field.name, offset = offset)
|
||||
elif field.type == Type.I64:
|
||||
impl += IMPL_SER_I64.format(name = field.name, offset = offset)
|
||||
elif field.type == Type.STRING:
|
||||
impl += IMPL_SER_STRING.format(name = field.name, offset = offset)
|
||||
elif field.type == Type.CAPABILITY:
|
||||
if with_cap:
|
||||
impl += IMPL_SER_CAP.format(name = field.name, offset = offset)
|
||||
else:
|
||||
impl += IMPL_SER_CAP_EMPTY
|
||||
else:
|
||||
impl += "\n{} unimplemented\n".format(field.type.name)
|
||||
impl += IMPL_SER_DEF_END
|
||||
|
||||
return impl
|
||||
|
||||
def _generate_message_class_impl(message: Message) -> str:
|
||||
return _generate_message_parse_impl(message) + _generate_message_serialize_impl(message)
|
||||
|
||||
|
||||
def generate_message_impl(file: str, ast: list[Decl]) -> str:
|
||||
impl = IMPL_PRELUDE.format(file=file)
|
||||
|
||||
|
||||
for decl in ast:
|
||||
if type(decl) != Message:
|
||||
continue
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
|
||||
#include "example.yunq.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const uint64_t header_size = 24; // 4x uint32, 1x uint64
|
||||
|
||||
struct ExtPointer {
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
}
|
||||
|
||||
void CheckHeader(const glcr::ByteBuffer& bytes) {
|
||||
// TODO: Check ident.
|
||||
// TODO: Parse core size.
|
||||
// TODO: Parse extension size.
|
||||
// TODO: Check CRC32
|
||||
// TODO: Parse options.
|
||||
}
|
||||
|
||||
void WriteHeader(glcr::ByteBuffer& bytes, uint32_t core_size, uint32_t extension_size) {
|
||||
bytes.WriteAt<uint32_t>(0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence.
|
||||
bytes.WriteAt<uint32_t>(4, core_size);
|
||||
bytes.WriteAt<uint32_t>(8, extension_size);
|
||||
bytes.WriteAt<uint32_t>(12, 0); // TODO: Calculate CRC32.
|
||||
bytes.WriteAt<uint64_t>(16, 0); // TODO: Add options.
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes) {
|
||||
CheckHeader();
|
||||
|
||||
auto path_pointer = bytes.At<ExtPointer>(header_size + (8 * 0));
|
||||
|
||||
set_path(bytes.StringAt(path_pointer.offset, path_pointer.length));
|
||||
|
||||
set_options(bytes.At<uint64_t>(header_size + (8 * 1)));
|
||||
|
||||
}
|
||||
|
||||
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {
|
||||
CheckHeader();
|
||||
|
||||
auto path_pointer = bytes.At<ExtPointer>(header_size + (8 * 0));
|
||||
|
||||
set_path(bytes.StringAt(path_pointer.offset, path_pointer.length));
|
||||
|
||||
set_options(bytes.At<uint64_t>(header_size + (8 * 1)));
|
||||
|
||||
}
|
||||
|
||||
OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes) {
|
||||
|
||||
uint32_t next_extension = header_size + 8 * 2;
|
||||
const uint32_t core_size = next_extension;
|
||||
|
||||
ExtPointer path_ptr{
|
||||
.offset = next_extension,
|
||||
// FIXME: Check downcast of str length.
|
||||
.length = path().length(),
|
||||
};
|
||||
|
||||
bytes.WriteStringAt(next_extension, path());
|
||||
next_extension += path_ptr.length;
|
||||
|
||||
bytes.WriteAt<ExtPointer>(header_size + (8 * 0), path_ptr);
|
||||
|
||||
bytes.WriteAt<uint64_t>(header_size + (8 * 1), options());
|
||||
|
||||
// The next extension pointer is the length of the message.
|
||||
WriteHeader(bytes, core_size, next_extension);
|
||||
}
|
||||
|
||||
OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, glcr::CapBuffer& caps) {
|
||||
|
||||
uint32_t next_extension = header_size + 8 * 2;
|
||||
const uint32_t core_size = next_extension;
|
||||
uint64_t next_cap = 0;
|
||||
|
||||
ExtPointer path_ptr{
|
||||
.offset = next_extension,
|
||||
// FIXME: Check downcast of str length.
|
||||
.length = path().length(),
|
||||
};
|
||||
|
||||
bytes.WriteStringAt(next_extension, path());
|
||||
next_extension += path_ptr.length;
|
||||
|
||||
bytes.WriteAt<ExtPointer>(header_size + (8 * 0), path_ptr);
|
||||
|
||||
bytes.WriteAt<uint64_t>(header_size + (8 * 1), options());
|
||||
|
||||
// The next extension pointer is the length of the message.
|
||||
WriteHeader(bytes, core_size, next_extension);
|
||||
}
|
||||
|
||||
void File::ParseFromBytes(const glcr::ByteBuffer& bytes) {
|
||||
CheckHeader();
|
||||
|
||||
auto path_pointer = bytes.At<ExtPointer>(header_size + (8 * 0));
|
||||
|
||||
set_path(bytes.StringAt(path_pointer.offset, path_pointer.length));
|
||||
|
||||
set_attrs(bytes.At<uint64_t>(header_size + (8 * 1)));
|
||||
|
||||
set_mem_cap(0);
|
||||
|
||||
}
|
||||
|
||||
void File::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {
|
||||
CheckHeader();
|
||||
|
||||
auto path_pointer = bytes.At<ExtPointer>(header_size + (8 * 0));
|
||||
|
||||
set_path(bytes.StringAt(path_pointer.offset, path_pointer.length));
|
||||
|
||||
set_attrs(bytes.At<uint64_t>(header_size + (8 * 1)));
|
||||
|
||||
uint64_t mem_cap_ptr = bytes.At<uint64_t>(header_size + (8 * 2));
|
||||
|
||||
set_mem_cap(caps.at(mem_cap_ptr));
|
||||
|
||||
}
|
||||
|
||||
File::SerializeToBytes(glcr::ByteBuffer& bytes) {
|
||||
|
||||
uint32_t next_extension = header_size + 8 * 3;
|
||||
const uint32_t core_size = next_extension;
|
||||
|
||||
ExtPointer path_ptr{
|
||||
.offset = next_extension,
|
||||
// FIXME: Check downcast of str length.
|
||||
.length = path().length(),
|
||||
};
|
||||
|
||||
bytes.WriteStringAt(next_extension, path());
|
||||
next_extension += path_ptr.length;
|
||||
|
||||
bytes.WriteAt<ExtPointer>(header_size + (8 * 0), path_ptr);
|
||||
|
||||
bytes.WriteAt<uint64_t>(header_size + (8 * 1), attrs());
|
||||
|
||||
// FIXME: Warn or error on serialization
|
||||
|
||||
// The next extension pointer is the length of the message.
|
||||
WriteHeader(bytes, core_size, next_extension);
|
||||
}
|
||||
|
||||
File::SerializeToBytes(glcr::ByteBuffer& bytes, glcr::CapBuffer& caps) {
|
||||
|
||||
uint32_t next_extension = header_size + 8 * 3;
|
||||
const uint32_t core_size = next_extension;
|
||||
uint64_t next_cap = 0;
|
||||
|
||||
ExtPointer path_ptr{
|
||||
.offset = next_extension,
|
||||
// FIXME: Check downcast of str length.
|
||||
.length = path().length(),
|
||||
};
|
||||
|
||||
bytes.WriteStringAt(next_extension, path());
|
||||
next_extension += path_ptr.length;
|
||||
|
||||
bytes.WriteAt<ExtPointer>(header_size + (8 * 0), path_ptr);
|
||||
|
||||
bytes.WriteAt<uint64_t>(header_size + (8 * 1), attrs());
|
||||
|
||||
caps.Write(next_cap, mem_cap());
|
||||
bytes.WriteAt<uint64_t>(header_size + (8 * 2), next_cap++);
|
||||
|
||||
// The next extension pointer is the length of the message.
|
||||
WriteHeader(bytes, core_size, next_extension);
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
// Generated file - DO NOT MODIFY
|
||||
#pragma once
|
||||
|
||||
#include <glacier/string/string.h>
|
||||
#include <ztypes.h>
|
||||
|
||||
|
||||
class OpenFileRequest {
|
||||
public:
|
||||
OpenFileRequest() {}
|
||||
// Delete copy and move until implemented.
|
||||
OpenFileRequest(const OpenFileRequest&) = delete;
|
||||
OpenFileRequest(OpenFileRequest&&) = delete;
|
||||
|
||||
void ParseFromBytes(const glcr::ByteBuffer&);
|
||||
void ParseFromBytes(const glcr::ByteBuffer&, const glcr::CapBuffer&);
|
||||
void SerializeToBytes(glcr::ByteBuffer&);
|
||||
void SerializeToBytes(glcr::ByteBuffer&, glcr::CapBuffer&);
|
||||
|
||||
glcr::String path() { return path_; }
|
||||
void set_path(glcr::String value) {
|
||||
path_ = value;
|
||||
}
|
||||
|
||||
uint64_t options() { return options_; }
|
||||
void set_options(uint64_t value) {
|
||||
options_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
glcr::String path_;
|
||||
|
||||
uint64_t options_;
|
||||
|
||||
};
|
||||
|
||||
class File {
|
||||
public:
|
||||
File() {}
|
||||
// Delete copy and move until implemented.
|
||||
File(const File&) = delete;
|
||||
File(File&&) = delete;
|
||||
|
||||
void ParseFromBytes(const glcr::ByteBuffer&);
|
||||
void ParseFromBytes(const glcr::ByteBuffer&, const glcr::CapBuffer&);
|
||||
void SerializeToBytes(glcr::ByteBuffer&);
|
||||
void SerializeToBytes(glcr::ByteBuffer&, glcr::CapBuffer&);
|
||||
|
||||
glcr::String path() { return path_; }
|
||||
void set_path(glcr::String value) {
|
||||
path_ = value;
|
||||
}
|
||||
|
||||
uint64_t attrs() { return attrs_; }
|
||||
void set_attrs(uint64_t value) {
|
||||
attrs_ = value;
|
||||
}
|
||||
|
||||
z_cap_t mem_cap() { return mem_cap_; }
|
||||
void set_mem_cap(z_cap_t value) {
|
||||
mem_cap_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
glcr::String path_;
|
||||
|
||||
uint64_t attrs_;
|
||||
|
||||
z_cap_t mem_cap_;
|
||||
|
||||
};
|
|
@ -10,6 +10,7 @@ def main():
|
|||
|
||||
filename = sys.argv[1]
|
||||
|
||||
ast = None
|
||||
with open(filename, mode='r') as f:
|
||||
filedata = f.read()
|
||||
lexemes = lexer(filedata)
|
||||
|
@ -18,7 +19,11 @@ def main():
|
|||
ast = parser.parse()
|
||||
type_check(ast)
|
||||
|
||||
print(generate_message_impl(filename, ast))
|
||||
|
||||
with open(filename + '.h', mode='w') as f:
|
||||
f.write(generate_message_header(ast))
|
||||
with open(filename + '.cpp', mode='w') as f:
|
||||
f.write(generate_message_impl(filename, ast))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
Loading…
Reference in New Issue