Add convenience methods to CodeBuilder and cleanup some WASM bindings code generation
PiperOrigin-RevId: 827916844 Change-Id: Ie382f2a5af3d7e3ec2c81cde5d6b768835da2365
This commit is contained in:
committed by
Copybara-Service
parent
740afe22b3
commit
4b79a58fa0
+545
-650
File diff suppressed because it is too large
Load Diff
@@ -56,12 +56,16 @@ class CodeBuilder:
|
||||
line += " {" if line else "{"
|
||||
self._builder.line(line)
|
||||
self._builder._indent_level += 1
|
||||
self._line_count_enter = len(self._builder._lines)
|
||||
return self._builder
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
if self._builder._indent_level > 0:
|
||||
self._builder._indent_level -= 1
|
||||
self._builder.line("}")
|
||||
if self._line_count_enter == len(self._builder._lines):
|
||||
self._builder._lines[-1] += "}"
|
||||
else:
|
||||
self._builder.line("}")
|
||||
|
||||
def block(self, header_line="") -> IndentBlock:
|
||||
"""Creates a block including braces and an optional header before the opening brace.
|
||||
@@ -75,3 +79,21 @@ class CodeBuilder:
|
||||
An IndentBlock instance that manages the indentation.
|
||||
"""
|
||||
return self.IndentBlock(self, header_line)
|
||||
|
||||
def function(self, signature="") -> IndentBlock:
|
||||
"""Creates a function."""
|
||||
return self.block(signature)
|
||||
|
||||
def struct(self, name="") -> IndentBlock:
|
||||
"""Creates a struct."""
|
||||
return self.block(f"struct {name}")
|
||||
|
||||
def private(self) -> None:
|
||||
"""Creates a private section."""
|
||||
self.newline()
|
||||
self.line("private:")
|
||||
|
||||
def public(self) -> None:
|
||||
"""Creates a public section."""
|
||||
self.newline()
|
||||
self.line("public:")
|
||||
|
||||
@@ -114,17 +114,14 @@ def should_be_wrapped(func: ast_nodes.FunctionDecl) -> bool:
|
||||
def generate_function_wrapper(func: ast_nodes.FunctionDecl) -> str:
|
||||
"""Generates C++ code for a wrapper function."""
|
||||
|
||||
builder = code_builder.CodeBuilder()
|
||||
# Build function header
|
||||
params_unpack_statements = get_params_unpack_statements(func.parameters)
|
||||
wrapper_params_list = get_params_string(func.parameters)
|
||||
not_nullable_params = get_params_notnullable(func.parameters)
|
||||
wrapper_params_str = ", ".join(wrapper_params_list)
|
||||
wrapper_params = ", ".join(wrapper_params_list)
|
||||
ret_type = get_compatible_return_type(func)
|
||||
builder.line(f"{ret_type} {func.name}_wrapper({wrapper_params_str})")
|
||||
|
||||
# Build function body
|
||||
with builder.block():
|
||||
builder = code_builder.CodeBuilder()
|
||||
with builder.function(f"{ret_type} {func.name}_wrapper({wrapper_params})"):
|
||||
invoker_params_list = get_params_string_maybe_with_conversion(
|
||||
func.parameters
|
||||
)
|
||||
@@ -136,6 +133,7 @@ def generate_function_wrapper(func: ast_nodes.FunctionDecl) -> str:
|
||||
for unpack_statement in params_unpack_statements:
|
||||
builder.line(unpack_statement)
|
||||
builder.line(f"{invoker_statement};")
|
||||
|
||||
return builder.to_string()
|
||||
|
||||
|
||||
|
||||
@@ -190,8 +190,7 @@ class FunctionUtilsTest(absltest.TestCase):
|
||||
result = functions.generate_function_wrapper(func)
|
||||
self.assertEqual(
|
||||
result,
|
||||
"""int get_id_wrapper()
|
||||
{
|
||||
"""int get_id_wrapper() {
|
||||
return get_id();
|
||||
}""",
|
||||
)
|
||||
@@ -218,8 +217,7 @@ class FunctionUtilsTest(absltest.TestCase):
|
||||
result = functions.generate_function_wrapper(func)
|
||||
self.assertEqual(
|
||||
result,
|
||||
"""int get_id_wrapper(const NumberArray& mat, int nr)
|
||||
{
|
||||
"""int get_id_wrapper(const NumberArray& mat, int nr) {
|
||||
UNPACK_ARRAY(mjtNum, mat);
|
||||
return get_id(mat_.data(), nr);
|
||||
}""",
|
||||
|
||||
@@ -73,15 +73,14 @@ class WrappedStructData:
|
||||
|
||||
|
||||
def build_primitive_type_definition(field: ast_nodes.StructFieldDecl) -> str:
|
||||
"""Builds the C++ code for a primitive type field wrapper."""
|
||||
"""Builds the C++ getter/setter code for a primitive type field wrapper."""
|
||||
if not isinstance(field.type, ast_nodes.ValueType):
|
||||
raise ValueError(f"{field.type} must be ValueType.")
|
||||
|
||||
builder = code_builder.CodeBuilder()
|
||||
# build getter for primitive type field
|
||||
with builder.block(f"{field.type.name} {field.name}() const"):
|
||||
with builder.function(f"{field.type.name} {field.name}() const"):
|
||||
builder.line(f"return ptr_->{field.name};")
|
||||
# build setter for primitive type field
|
||||
with builder.block(f"void set_{field.name}({field.type.name} value)"):
|
||||
with builder.function(f"void set_{field.name}({field.type.name} value)"):
|
||||
builder.line(f"ptr_->{field.name} = value;")
|
||||
return builder.to_string()
|
||||
|
||||
@@ -91,7 +90,7 @@ def build_memory_view_definition(
|
||||
) -> str:
|
||||
"""Builds the C++ code for a pointer type field wrapper."""
|
||||
builder = code_builder.CodeBuilder()
|
||||
with builder.block(f"emscripten::val {field.name}() const"):
|
||||
with builder.function(f"emscripten::val {field.name}() const"):
|
||||
builder.line(
|
||||
"return"
|
||||
f" emscripten::val(emscripten::typed_memory_view({array_size_str},"
|
||||
@@ -101,13 +100,13 @@ def build_memory_view_definition(
|
||||
|
||||
|
||||
def build_string_field_definition(field: ast_nodes.StructFieldDecl) -> str:
|
||||
"""Builds the C++ code for a string type field wrapper."""
|
||||
"""Builds the C++ code getter/setter for a string type field wrapper."""
|
||||
builder = code_builder.CodeBuilder()
|
||||
with builder.block(f"mjString {field.name}() const"):
|
||||
with builder.function(f"mjString {field.name}() const"):
|
||||
builder.line(
|
||||
f'return (ptr_ && ptr_->{field.name}) ? *(ptr_->{field.name}) : "";'
|
||||
)
|
||||
with builder.block(f"void set_{field.name}(const mjString& value)"):
|
||||
with builder.function(f"void set_{field.name}(const mjString& value)"):
|
||||
with builder.block(f"if (ptr_ && ptr_->{field.name})"):
|
||||
builder.line(f"*(ptr_->{field.name}) = value;")
|
||||
return builder.to_string()
|
||||
@@ -124,7 +123,7 @@ def build_mjvec_pointer_definition(
|
||||
f"*(reinterpret_cast<std::vector<uint8_t>*>(ptr_->{field.name}))"
|
||||
)
|
||||
builder = code_builder.CodeBuilder()
|
||||
with builder.block(f"{vector_type} &{field.name}() const"):
|
||||
with builder.function(f"{vector_type} &{field.name}() const"):
|
||||
builder.line(f"return {ptr_field_expr};")
|
||||
return builder.to_string()
|
||||
|
||||
@@ -453,40 +452,42 @@ def _build_struct_header_internal(
|
||||
is_mjs: bool = False,
|
||||
):
|
||||
"""Builds the C++ header file code for a struct."""
|
||||
s = struct_name
|
||||
w = common.uppercase_first_letter(s)
|
||||
|
||||
shallow_copy = use_shallow_copy(wrapped_fields)
|
||||
|
||||
wrapper_name = common.uppercase_first_letter(struct_name)
|
||||
builder = code_builder.CodeBuilder()
|
||||
with builder.block(f"struct {wrapper_name}"):
|
||||
with builder.struct(f"{w}"):
|
||||
if not is_mjs:
|
||||
builder.line(f"{wrapper_name}();")
|
||||
builder.line(f"{wrapper_name}(const {wrapper_name} &);")
|
||||
builder.line(f"{wrapper_name} &operator=(const {wrapper_name} &);")
|
||||
builder.line(f"{w}();")
|
||||
builder.line(f"{w}(const {w} &);")
|
||||
builder.line(f"{w} &operator=(const {w} &);")
|
||||
|
||||
builder.line(f"explicit {wrapper_name}({struct_name} *ptr);")
|
||||
builder.line(f"~{wrapper_name}();")
|
||||
builder.line(f"explicit {w}({s} *ptr);")
|
||||
builder.line(f"~{w}();")
|
||||
|
||||
if shallow_copy:
|
||||
builder.line(f"std::unique_ptr<{wrapper_name}> copy();")
|
||||
builder.line(f"std::unique_ptr<{w}> copy();")
|
||||
|
||||
for field in wrapped_fields:
|
||||
if field.definition and field not in fields_with_init:
|
||||
for line in field.definition.splitlines():
|
||||
builder.line(line)
|
||||
|
||||
builder.line(f"{struct_name}* get() const {{ return ptr_; }}")
|
||||
builder.line(f"void set({struct_name}* ptr) {{ ptr_ = ptr; }}")
|
||||
with builder.function(f"{s}* get() const"):
|
||||
builder.line("return ptr_;")
|
||||
|
||||
builder.newline()
|
||||
builder.line("private:")
|
||||
builder.line(f"{struct_name}* ptr_;")
|
||||
with builder.function(f"void set({s}* ptr)"):
|
||||
builder.line("ptr_ = ptr;")
|
||||
|
||||
builder.private()
|
||||
builder.line(f"{s}* ptr_;")
|
||||
if not is_mjs:
|
||||
builder.line("bool owned_ = false;")
|
||||
|
||||
if is_mjs and fields_with_init:
|
||||
builder.newline()
|
||||
builder.line("public:")
|
||||
builder.public()
|
||||
for field in fields_with_init:
|
||||
if field.definition:
|
||||
builder.line(f"{field.definition}")
|
||||
@@ -580,9 +581,9 @@ def build_struct_source(
|
||||
wrapped_fields: List[WrappedFieldData],
|
||||
):
|
||||
"""Builds the C++ .cc file code for a struct."""
|
||||
wrapper_name = common.uppercase_first_letter(struct_name)
|
||||
is_mjs_struct = "Mjs" in wrapper_name
|
||||
builder = code_builder.CodeBuilder()
|
||||
s = struct_name
|
||||
w = common.uppercase_first_letter(s)
|
||||
is_mjs = "Mjs" in w
|
||||
|
||||
fields_with_init = _find_fields_with_init(wrapped_fields)
|
||||
shallow_copy = use_shallow_copy(wrapped_fields)
|
||||
@@ -593,65 +594,49 @@ def build_struct_source(
|
||||
field_with_init.initialization for field_with_init in fields_with_init
|
||||
)
|
||||
|
||||
builder = code_builder.CodeBuilder()
|
||||
|
||||
# constructor passing native ptr
|
||||
builder.line(
|
||||
f"{wrapper_name}::{wrapper_name}({struct_name} *ptr) :"
|
||||
f" ptr_(ptr){fields_init} {{}}"
|
||||
)
|
||||
with builder.function(f"{w}::{w}({s} *ptr) : ptr_(ptr){fields_init}"):
|
||||
pass
|
||||
|
||||
# constructor with default values
|
||||
if not is_mjs_struct:
|
||||
with builder.block(
|
||||
f"{wrapper_name}::{wrapper_name}() : ptr_(new"
|
||||
f" {struct_name}){fields_init}"
|
||||
):
|
||||
if not is_mjs:
|
||||
with builder.function(f"{w}::{w}() : ptr_(new {s}){fields_init}"):
|
||||
builder.line("owned_ = true;")
|
||||
default_func = _default_function_statement(struct_name)
|
||||
default_func = _default_function_statement(s)
|
||||
if default_func:
|
||||
builder.line(default_func)
|
||||
|
||||
if shallow_copy and not is_mjs_struct:
|
||||
if shallow_copy and not is_mjs:
|
||||
# copy constructor
|
||||
with builder.block(
|
||||
f"{wrapper_name}::{wrapper_name}(const {wrapper_name} &other)"
|
||||
+ (f" : {wrapper_name}()" if not is_mjs_struct else "")
|
||||
):
|
||||
with builder.function(f"{w}::{w}(const {w} &other) : {w}()"):
|
||||
builder.line("*ptr_ = *other.get();")
|
||||
if fields_with_init:
|
||||
for field_with_init in fields_with_init:
|
||||
if field_with_init.ptr_copy_reset is not None:
|
||||
builder.line(field_with_init.ptr_copy_reset)
|
||||
for field_with_init in fields_with_init:
|
||||
if field_with_init.ptr_copy_reset is not None:
|
||||
builder.line(field_with_init.ptr_copy_reset)
|
||||
|
||||
# assignment operator
|
||||
with builder.block(
|
||||
f"{wrapper_name}&"
|
||||
f" {wrapper_name}::operator=(const"
|
||||
f" {wrapper_name} &other)"
|
||||
):
|
||||
with builder.function(f"{w}& {w}::operator=(const {w} &other)"):
|
||||
with builder.block("if (this == &other)"):
|
||||
builder.line("return *this;")
|
||||
builder.line("*ptr_ = *other.get();")
|
||||
if fields_with_init:
|
||||
for field_with_init in fields_with_init:
|
||||
if field_with_init.ptr_copy_reset is not None:
|
||||
builder.line(field_with_init.ptr_copy_reset)
|
||||
for field_with_init in fields_with_init:
|
||||
if field_with_init.ptr_copy_reset is not None:
|
||||
builder.line(field_with_init.ptr_copy_reset)
|
||||
builder.line("return *this;")
|
||||
|
||||
# destructor
|
||||
if is_mjs_struct:
|
||||
builder.line(f"{wrapper_name}::~{wrapper_name}() {{}}")
|
||||
else:
|
||||
with builder.block(f"{wrapper_name}::~{wrapper_name}()"):
|
||||
with builder.function(f"{w}::~{w}()"):
|
||||
if not is_mjs:
|
||||
with builder.block("if (owned_ && ptr_)"):
|
||||
delete_ptr = _delete_ptr_statement(struct_name)
|
||||
delete_ptr = _delete_ptr_statement(s)
|
||||
builder.line(delete_ptr)
|
||||
|
||||
# copy function
|
||||
if shallow_copy:
|
||||
with builder.block(
|
||||
f"std::unique_ptr<{wrapper_name}> {wrapper_name}::copy()"
|
||||
):
|
||||
builder.line(f"return std::make_unique<{wrapper_name}>(*this);")
|
||||
with builder.function(f"std::unique_ptr<{w}> {w}::copy()"):
|
||||
builder.line(f"return std::make_unique<{w}>(*this);")
|
||||
|
||||
return builder.to_string()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user