[Yunq] Move to using jinja for codegen.

This commit is contained in:
Drew Galbraith 2023-10-24 14:54:00 -07:00
parent 3faa19e4cb
commit 963cc0b4fa
8 changed files with 283 additions and 411 deletions

View File

@ -1,267 +0,0 @@
from parser import *
HEADER_PRELUDE = """
// Generated file - DO NOT MODIFY
#pragma once
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <glacier/string/string.h>
#include <ztypes.h>
"""
MESSAGE_CLASS_PREFIX = """
class {name} {{
public:
{name}() {{}}
// Delete copy and move until implemented.
{name}(const {name}&) = delete;
{name}({name}&&) = delete;
void ParseFromBytes(const glcr::ByteBuffer&);
void ParseFromBytes(const glcr::ByteBuffer&, const glcr::CapBuffer&);
void SerializeToBytes(glcr::ByteBuffer&);
void SerializeToBytes(glcr::ByteBuffer&, glcr::CapBuffer&);
"""
MESSAGE_CLASS_SET_GET = """
{type} {name}() {{ return {name}_; }}
void set_{name}({type} value) {{
{name}_ = value;
}}
"""
MESSAGE_CLASS_PRIVATE = """
private:
"""
MESSAGE_CLASS_FIELD = """
{type} {name}_;
"""
MESSAGE_CLASS_SUFFIX = """
};
"""
type_to_str = {
Type.U64: "uint64_t",
Type.I64: "int64_t",
Type.STRING: "glcr::String",
Type.CAPABILITY: "z_cap_t",
Type.BYTES: "glcr::Vector<uint8_t>"
}
def _type_str(field_type: Type) -> str:
return type_to_str[field_type]
def _generate_message_class(message: Message) -> str:
class_decl = MESSAGE_CLASS_PREFIX.format(name = message.name)
for field in message.fields:
class_decl += MESSAGE_CLASS_SET_GET.format(name = field.name, type = _type_str(field.type))
class_decl += MESSAGE_CLASS_PRIVATE
for field in message.fields:
class_decl += MESSAGE_CLASS_FIELD.format(name = field.name, type = _type_str(field.type))
class_decl += MESSAGE_CLASS_SUFFIX
return class_decl
def generate_message_header(ast: list[Decl]) -> str:
header = HEADER_PRELUDE
for decl in ast:
if type(decl) != Message:
continue
header += _generate_message_class(decl)
return header
IMPL_PRELUDE = """
#include "{file}.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
"""
IMPL_PARSE_DEF = """
void {name}::ParseFromBytes(const glcr::ByteBuffer& bytes) {{
CheckHeader(bytes);
"""
IMPL_PARSE_DEF_CAP = """
void {name}::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {{
CheckHeader(bytes);
"""
IMPL_PARSE_U64 = """
set_{name}(bytes.At<uint64_t>(header_size + (8 * {offset})));
"""
IMPL_PARSE_I64 = """
set_{name}(bytes.At<int64_t>(header_size + (8 * {offset})));
"""
IMPL_PARSE_STRING = """
auto {name}_pointer = bytes.At<ExtPointer>(header_size + (8 * {offset}));
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_parse_impl(message: Message) -> str:
impl = ""
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
return impl
IMPL_SER_DEF = """
void {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 = """
void {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 = (uint32_t){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.WriteAt(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
impl += _generate_message_class_impl(decl)
return impl

View File

@ -1,4 +1,3 @@
#include "example.yunq.h"
namespace {
@ -18,157 +17,95 @@ void CheckHeader(const glcr::ByteBuffer& bytes) {
// 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.
void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, uint32_t extension_size) {
bytes.WriteAt<uint32_t>(offset + 0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence.
bytes.WriteAt<uint32_t>(offset + 4, core_size);
bytes.WriteAt<uint32_t>(offset + 8, extension_size);
bytes.WriteAt<uint32_t>(offset + 12, 0); // TODO: Calculate CRC32.
bytes.WriteAt<uint64_t>(offset + 16, 0); // TODO: Add options.
}
} // namespace
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes) {
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) {
CheckHeader(bytes);
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)));
auto {field.name}_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * {loop.index}));
set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length));
set_options(bytes.At<uint64_t>(offset + header_size + (8 * 2)));
}
void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {
void {message.name}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) {
CheckHeader(bytes);
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)));
auto {field.name}_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * {loop.index}));
set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length));
set_options(bytes.At<uint64_t>(offset + header_size + (8 * 2)));
}
void 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 = (uint32_t)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 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 = (uint32_t)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) {
void File::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) {
CheckHeader(bytes);
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)));
auto {field.name}_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * {loop.index}));
set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length));
set_attrs(bytes.At<uint64_t>(offset + header_size + (8 * 2)));
// FIXME: Implement in-buffer capabilities for inprocess serialization.
set_mem_cap(0);
}
void File::ParseFromBytes(const glcr::ByteBuffer& bytes, const glcr::CapBuffer& caps) {
void {message.name}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) {
CheckHeader(bytes);
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)));
auto {field.name}_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * {loop.index}));
uint64_t mem_cap_ptr = bytes.At<uint64_t>(header_size + (8 * 2));
set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length));
set_attrs(bytes.At<uint64_t>(offset + header_size + (8 * 2)));
uint64_t mem_cap_ptr = bytes.At<uint64_t>(offset + header_size + (8 * {offset}));
set_mem_cap(caps.At(mem_cap_ptr));
}
void 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 = (uint32_t)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);
}
void 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 = (uint32_t)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.WriteAt(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);
}

View File

@ -1,4 +1,3 @@
// Generated file - DO NOT MODIFY
#pragma once
@ -8,6 +7,7 @@
#include <ztypes.h>
class OpenFileRequest {
public:
OpenFileRequest() {}
@ -15,20 +15,18 @@ class OpenFileRequest {
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&);
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset);
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&);
glcr::String path() { return path_; }
void set_path(glcr::String value) {
path_ = value;
}
void set_path(const glcr::String& value) { path_ = value; }
uint64_t options() { return options_; }
void set_options(uint64_t value) {
options_ = value;
}
void set_options(const uint64_t& value) { options_ = value; }
private:
@ -36,7 +34,8 @@ class OpenFileRequest {
uint64_t options_;
};
}
class File {
public:
@ -45,25 +44,21 @@ class File {
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&);
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset);
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&);
glcr::String path() { return path_; }
void set_path(glcr::String value) {
path_ = value;
}
void set_path(const glcr::String& value) { path_ = value; }
uint64_t attrs() { return attrs_; }
void set_attrs(uint64_t value) {
attrs_ = value;
}
void set_attrs(const uint64_t& value) { attrs_ = value; }
z_cap_t mem_cap() { return mem_cap_; }
void set_mem_cap(z_cap_t value) {
mem_cap_ = value;
}
void set_mem_cap(const z_cap_t& value) { mem_cap_ = value; }
private:
@ -73,4 +68,5 @@ class File {
z_cap_t mem_cap_;
};
}

147
yunq/message.cpp.jinja Normal file
View File

@ -0,0 +1,147 @@
// Generated file -- DO NOT MODIFY.
#include "{{file}}.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, uint64_t offset, uint32_t core_size, uint32_t extension_size) {
bytes.WriteAt<uint32_t>(offset + 0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence.
bytes.WriteAt<uint32_t>(offset + 4, core_size);
bytes.WriteAt<uint32_t>(offset + 8, extension_size);
bytes.WriteAt<uint32_t>(offset + 12, 0); // TODO: Calculate CRC32.
bytes.WriteAt<uint64_t>(offset + 16, 0); // TODO: Add options.
}
} // namespace
{%- for message in messages %}
void {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) {
CheckHeader(bytes);
{%- for field in message.fields %}
// Parse {{field.name}}.
{%- if field.type == Type.U64 %}
set_{{field.name}}(bytes.At<uint64_t>(offset + header_size + (8 * {{loop.index0}})));
{%- elif field.type == Type.I64 %}
set_{{field.name}}(bytes.At<int64_t>(offset + header_size + (8 * {{loop.index0}})));
{%- elif field.type == Type.STRING %}
auto {{field.name}}_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * {{loop.index0}}));
set_{{field.name}}(bytes.StringAt(offset + {{field.name}}_pointer.offset, {{field.name}}_pointer.length));
{%- elif field.type == Type.CAPABILITY %}
// FIXME: Implement in-buffer capabilities for inprocess serialization.
set_{{field.name}}(0);
{%- else %}
// TODO: Unimplemented parsing {{field.type}}
{%- endif %}
{%- endfor %}
}
void {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) {
CheckHeader(bytes);
{%- for field in message.fields %}
// Parse {{field.name}}.
{%- if field.type == Type.U64 %}
set_{{field.name}}(bytes.At<uint64_t>(offset + header_size + (8 * {{loop.index0}})));
{%- elif field.type == Type.I64 %}
set_{{field.name}}(bytes.At<int64_t>(offset + header_size + (8 * {{loop.index0}})));
{%- elif field.type == Type.STRING %}
auto {{field.name}}_pointer = bytes.At<ExtPointer>(offset + header_size + (8 * {{loop.index0}}));
set_{{field.name}}(bytes.StringAt(offset + {{field.name}}_pointer.offset, {{field.name}}_pointer.length));
{%- elif field.type == Type.CAPABILITY %}
uint64_t {{field.name}}_ptr = bytes.At<uint64_t>(offset + header_size + (8 * {{loop.index0}}));
set_{{field.name}}(caps.At({{field.name}}_ptr));
{%- else %}
// TODO: Unimplemented parsing {{field.type}}
{%- endif %}
{%- endfor %}
}
uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) {
uint32_t next_extension = header_size + 8 * {{ message.fields | length }};
const uint32_t core_size = next_extension;
{%- for field in message.fields %}
// Write {{field.name}}.
{%- if field.type == Type.U64 %}
bytes.WriteAt<uint64_t>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}());
{%- elif field.type == Type.I64 %}
bytes.WriteAt<int64_t>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}());
{%- elif field.type == Type.STRING %}
ExtPointer {{field.name}}_ptr{
.offset = next_extension,
// FIXME: Check downcast of str length.
.length = (uint32_t){{field.name}}().length(),
};
bytes.WriteStringAt(offset + next_extension, {{field.name}}());
next_extension += {{field.name}}_ptr.length;
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr);
{%- elif field.type == Type.CAPABILITY %}
// FIXME: Implement inbuffer capabilities.
bytes.WriteAt<uint64_t>(offset + header_size + (8 * {{loop.index0}}), 0);
{%- else %}
// TODO: Unimplemented serialization {{field.type}}
{%- endif %}
{%- endfor %}
// The next extension pointer is the length of the message.
WriteHeader(bytes, offset, core_size, next_extension);
return next_extension;
}
uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) {
uint32_t next_extension = header_size + 8 * {{ message.fields | length}};
const uint32_t core_size = next_extension;
uint64_t next_cap = 0;
{%- for field in message.fields %}
// Write {{field.name}}.
{%- if field.type == Type.U64 %}
bytes.WriteAt<uint64_t>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}());
{%- elif field.type == Type.I64 %}
bytes.WriteAt<int64_t>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}());
{%- elif field.type == Type.STRING %}
ExtPointer {{field.name}}_ptr{
.offset = next_extension,
// FIXME: Check downcast of str length.
.length = (uint32_t){{field.name}}().length(),
};
bytes.WriteStringAt(offset + next_extension, {{field.name}}());
next_extension += {{field.name}}_ptr.length;
bytes.WriteAt<ExtPointer>(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr);
{%- elif field.type == Type.CAPABILITY %}
caps.WriteAt(next_cap, {{field.name}}());
bytes.WriteAt<uint64_t>(offset + header_size + (8 * {{loop.index0}}), next_cap++);
{%- else %}
// TODO: Unimplemented serialization {{field.type}}
{%- endif %}
{%- endfor %}
// The next extension pointer is the length of the message.
WriteHeader(bytes, offset, core_size, next_extension);
return next_extension;
}
{%- endfor %}

34
yunq/message.h.jinja Normal file
View File

@ -0,0 +1,34 @@
// Generated file - DO NOT MODIFY
#pragma once
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <glacier/string/string.h>
#include <ztypes.h>
{%- for message in messages %}
class {{message.name}} {
public:
{{message.name}}() {}
// Delete copy and move until implemented.
{{message.name}}(const {{message.name}}&) = delete;
{{message.name}}({{message.name}}&&) = delete;
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset);
void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&);
{%- for field in message.fields %}
{{field.cpp_type()}} {{field.name}}() { return {{field.name}}_; }
void set_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_ = value; }
{%- endfor %}
private:
{%- for field in message.fields %}
{{field.cpp_type()}} {{field.name}}_;
{%- endfor %}
};
{%- endfor %}

View File

@ -102,11 +102,22 @@ type_str_dict = {
"capability": Type.CAPABILITY,
}
type_to_cppstr = {
Type.U64: "uint64_t",
Type.I64: "int64_t",
Type.STRING: "glcr::String",
Type.CAPABILITY: "z_cap_t",
Type.BYTES: "glcr::Vector<uint8_t>"
}
class Field():
def __init__(self, fieldtype: Type, name: str):
self.type = fieldtype
self.name = name
def cpp_type(self):
return type_to_cppstr[self.type]
class Message():
def __init__(self, name: str, fields: list[Field]):
self.name = name

1
yunq/requirements.txt Normal file
View File

@ -0,0 +1 @@
jinja2==3.1

View File

@ -1,8 +1,10 @@
#! /usr/bin/python
#! python3
import os
import pathlib
import sys
from codegen_message import *
from jinja2 import Environment, FileSystemLoader
from parser import *
def main():
@ -20,11 +22,22 @@ def main():
ast = parser.parse()
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]
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:
f.write(generate_message_header(ast))
message_header = message_header_tmpl.render(messages=messages)
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:
f.write(generate_message_impl(filename, ast))
message_impl = message_impl_tmpl.render(file=filename, messages=messages)
f.write(message_impl)
if __name__ == "__main__":
main()