use lib_ruby_parser_nodes::{template::*, Node, NodeField};
const TEMPLATE: &str = "// This file is autogenerated by {{ helper generated-by }}
#include \"bindings.hpp\"
extern \"C\"
{
// Node constructors
{{ each node }}<dnl>
{{ helper constructor-sig }}
{
{{ each node-field }}<dnl>
{{ helper unpack-field }}
{{ end }}<dnl>
return PACK_Node(Node({{ helper node-camelcase-name }}{
{{ each node-field }}<dnl>
std::move({{ helper node-field-c-name }}),
{{ end }}<dnl>
}));
}
{{ end }}<dnl>
// Node variant predicates
{{ each node }}<dnl>
{{ helper variant-predicate-sig }}
{
const Node *self = (const Node *)self_blob;
return std::holds_alternative<{{ helper node-camelcase-name }}>(self->variant);
}
{{ end }}<dnl>
// Node variant getter
{{ each node }}<dnl>
{{ helper variant-getter-sig }}
{
Node *self = (Node *)self_blob;
{{ helper node-camelcase-name }} *variant = std::get_if<{{ helper node-camelcase-name }}>(&(self->variant));
return ({{ helper node-camelcase-name }}_BLOB*)variant;
}
{{ end }}<dnl>
// Node field getters
{{ each node }}<dnl>
{{ each node-field }}<dnl>
{{ helper field-getter-sig }}
{
{{ helper node-camelcase-name }} *self = ({{ helper node-camelcase-name }} *)self_blob;
{{ helper node-field-cpp-field-type }}* field = &(self->{{ helper node-field-c-name }});
return ({{ helper node-field-cpp-blob-type }} *)field;
}
{{ end }}<dnl>
{{ end }}<dnl>
// Node field setters
{{ each node }}<dnl>
{{ each node-field }}<dnl>
{{ helper field-setter-sig }}
{
{{ helper node-camelcase-name }}* self = ({{ helper node-camelcase-name }} *)self_blob;
{{ helper unpack-field }}
self->{{ helper node-field-c-name }} = std::move({{ helper node-field-c-name }});
}
{{ end }}<dnl>
{{ end }}<dnl>
// into_variant fns
{{ each node }}<dnl>
{{ helper into-variant-sig }}
{
Node self = UNPACK_Node(self_blob);
{{ helper node-camelcase-name }} variant = std::get<{{ helper node-camelcase-name }}>(std::move(self.variant));
return PACK_{{ helper node-camelcase-name }}(std::move(variant));
}
{{ end }}<dnl>
// into_internal fns
{{ each node }}<dnl>
{{ helper into-internal-sig }}
{
{{ helper node-camelcase-name }} self = UNPACK_{{ helper node-camelcase-name }}(self_blob);
{{ each node-field }}<dnl>
{{ helper pack-field }}
{{ end }}<dnl>
Internal{{ helper node-camelcase-name }} internal = {
{{ each node-field }}<dnl>
.{{ helper node-field-c-name }} = {{ helper node-field-c-name }},
{{ end }}<dnl>
};
return internal;
}
{{ end }}<dnl>
// variant drop fns
{{ each node }}<dnl>
{{ helper drop-variant-sig }}
{
{{ helper node-camelcase-name }} *self = ({{ helper node-camelcase-name }} *)self_blob;
self->~{{ helper node-camelcase-name }}();
}
{{ end }}<dnl>
void lib_ruby_parser__external__node__drop(Node_BLOB* self_blob)
{
Node *self = (Node *)self_blob;
self->~Node();
}
}
";
pub(crate) fn codegen() {
let template = TemplateRoot::new(TEMPLATE).unwrap();
let mut fns = crate::codegen::fns::default_fns!();
fns.register::<Node, F::Helper>(
"constructor-sig",
lib_ruby_parser_bindings::helpers::nodes::constructor::sig,
);
fns.register::<NodeField, F::Helper>("pack-field", local_helpers::pack_field);
fns.register::<NodeField, F::Helper>("unpack-field", local_helpers::unpack_field);
fns.register::<Node, F::Helper>(
"variant-predicate-sig",
lib_ruby_parser_bindings::helpers::nodes::variant_predicate::sig,
);
fns.register::<Node, F::Helper>(
"variant-getter-sig",
lib_ruby_parser_bindings::helpers::nodes::variant_getter::sig,
);
fns.register::<NodeField, F::Helper>(
"field-getter-sig",
lib_ruby_parser_bindings::helpers::nodes::field_getter::sig,
);
fns.register::<NodeField, F::Helper>(
"field-setter-sig",
lib_ruby_parser_bindings::helpers::nodes::field_setter::sig,
);
fns.register::<Node, F::Helper>(
"into-variant-sig",
lib_ruby_parser_bindings::helpers::nodes::into_variant::sig,
);
fns.register::<Node, F::Helper>(
"into-internal-sig",
lib_ruby_parser_bindings::helpers::nodes::into_internal::sig,
);
fns.register::<Node, F::Helper>(
"drop-variant-sig",
lib_ruby_parser_bindings::helpers::nodes::drop_variant::sig,
);
let contents = template.render(ALL_DATA, &fns);
std::fs::write("external/cpp/bindings_nodes.cpp", contents).unwrap();
}
mod local_helpers {
use super::*;
use crate::codegen::fns;
pub(crate) fn unpack_field(node_field: &NodeField) -> String {
let field_name = fns::c::node_fields::c_name(node_field);
match node_field.field_type {
lib_ruby_parser_nodes::NodeFieldType::Node => {
format!(
"NodePtr {field_name} = std::unique_ptr<Node>((Node *)(UNPACK_Ptr({field_name}_blob).release()));",
field_name = field_name
)
}
lib_ruby_parser_nodes::NodeFieldType::MaybeNode { .. } => {
format!(
"MaybeNodePtr {field_name} = std::unique_ptr<Node>((Node *)(UNPACK_MaybePtr({field_name}_blob).release()));",
field_name = field_name
)
}
_ => {
format!(
"{field_type} {field_name} = {unpack}({field_name}_blob);",
field_type = fns::cpp::node_fields::cpp_field_type(node_field),
field_name = field_name,
unpack = fns::cpp::node_fields::cpp_unpack_fn_name(node_field)
)
}
}
}
pub(crate) fn pack_field(node_field: &NodeField) -> String {
let field_name = fns::c::node_fields::c_name(node_field);
match node_field.field_type {
lib_ruby_parser_nodes::NodeFieldType::Node => {
format!(
"Ptr_BLOB {field_name} = PACK_Ptr(Ptr((int *)(self.{field_name}.release())));",
field_name = field_name
)
}
lib_ruby_parser_nodes::NodeFieldType::MaybeNode { .. } => {
format!(
"MaybePtr_BLOB {field_name} = PACK_MaybePtr(MaybePtr((int *)(self.{field_name}.release())));",
field_name = field_name
)
}
_ => {
format!(
"{field_type}_BLOB {field_name} = {pack}(std::move(self.{field_name}));",
field_type = fns::cpp::node_fields::cpp_field_type(node_field),
field_name = field_name,
pack = fns::cpp::node_fields::cpp_pack_fn_name(node_field)
)
}
}
}
}