lib-ruby-parser 3.0.11

Ruby parser
Documentation
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)
                )
            }
        }
    }
}