lib-ruby-parser 3.0.11

Ruby parser
Documentation
use lib_ruby_parser_nodes::{template::*, Node};

const TEMPLATE: &str = "// This file is auto-generated by {{ helper generated-by }}

use crate::nodes::InnerNode;
use crate::nodes::*;

use crate::Loc;
use crate::Bytes;
crate::use_native_or_external!(Ptr);
crate::use_native_or_external!(List);
crate::use_native_or_external!(Maybe);
crate::use_native_or_external!(StringPtr);

use crate::blobs::{HasBlob, Blob};

/// Generic combination of all known nodes.
#[repr(C)]
pub struct Node {
    pub(crate) blob: Blob<Self>,
}

impl std::fmt::Debug for Node {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
{{ each node }}<dnl>
        if let Some(inner) = self.as_{{ helper node-lower-name }}() {
            return write!(f, \"{{ helper node-camelcase-name }}({:?})\", inner)
        }
{{ end }}<dnl>
        panic!(\"bug: unknown node type\")
    }
}

impl Clone for Node {
    fn clone(&self) -> Self {
{{ each node }}<dnl>
        if let Some(inner) = self.as_{{ helper node-lower-name }}() {
            return Self::new_{{ helper node-lower-name }}(
{{ each node-field }}<dnl>
                inner.get_{{ helper node-field-name }}().clone(),
{{ end }}<dnl>
            )
        }
{{ end }}<dnl>
        panic!(\"bug: unknown node type\")
    }
}

impl PartialEq for Node {
    fn eq(&self, other: &Self) -> bool {
{{ each node }}<dnl>
        if let Some(lhs) = self.as_{{ helper node-lower-name }}() {
            if let Some(rhs) = other.as_{{ helper node-lower-name }}() {
                return lhs == rhs;
            } else {
                return false;
            }
        }
{{ end }}<dnl>
        panic!(\"bug: unknown node type\")
    }
}

impl Node {
    pub(crate) fn inner_ref(&self) -> &dyn InnerNode {
{{ each node }}<dnl>
        if let Some(inner) = self.as_{{ helper node-lower-name }}() {
            return inner;
        }
{{ end }}<dnl>

        panic!(\"bug: unknown node type\")
    }

    // new_<node> FNs
{{ each node }}<dnl>
    /// Constructs `Node::{{ helper node-camelcase-name }}` variant
    pub(crate) fn new_{{ helper node-lower-name }}({{ each node-field }}{{ helper node-field-rust-field-name }}: {{ helper node-field-rust-field-type }}, {{ end }}) -> Self {
        let blob = unsafe { {{ helper extern-ctor-name }}({{ each node-field }}{{ helper node-field-rust-field-name }}.into_blob(), {{ end }}) };
        Self { blob }
    }
{{ end }}<dnl>

    // is_<node> FNs
{{ each node }}<dnl>
    /// Returns true if `self` is `Node::{{ helper node-camelcase-name }}`
    pub fn is_{{ helper node-lower-name }}(&self) -> bool {
        unsafe { {{ helper extern-is-variant-name }}(&self.blob) }
    }
{{ end }}<dnl>

    // as_<node> FNs
{{ each node }}<dnl>
    /// Casts `&Node` to `Option<&nodes::{{ helper node-camelcase-name }}>`
    pub fn as_{{ helper node-lower-name }}(&self) -> Option<&{{ helper node-camelcase-name }}> {
        unsafe { ({{ helper extern-as-variant-name }}(&self.blob) as *const {{ helper node-camelcase-name }}).as_ref() }
    }
{{ end }}<dnl>

    // as_<node>_mut FNs
{{ each node }}<dnl>
    /// Casts `&Node` to `Option<&mut nodes::{{ helper node-camelcase-name }}>`
    #[allow(non_snake_case)]
    pub fn as_{{ helper node-lower-name }}_mut(&mut self) -> Option<&mut {{ helper node-camelcase-name }}> {
        unsafe { ({{ helper extern-as-variant-name }}(&self.blob) as *mut {{ helper node-camelcase-name }}).as_mut() }
    }
{{ end }}<dnl>

    // into_<node> FNs
{{ each node }}<dnl>
    /// Casts `self` to nodes::{{ helper node-camelcase-name }}, panics if variant doesn't match
    pub fn into_{{ helper node-lower-name }}(self) -> {{ helper node-camelcase-name }} {
        let blob = unsafe { {{ helper extern-into-variant-name }}(self.into_blob()) };
        {{ helper node-camelcase-name }} { blob }
    }
{{ end }}<dnl>
}

extern \"C\"
{
{{ each node }}<dnl>
    fn {{ helper extern-ctor-name }}({{ each node-field }}{{ helper node-field-rust-field-name }}: Blob<{{ helper node-field-rust-field-type }}>, {{ end }}) -> Blob<Node>;
    fn {{ helper extern-is-variant-name }}(blob_ptr: *const Blob<Node>) -> bool;
    fn {{ helper extern-as-variant-name }}(blob_ptr: *const Blob<Node>) -> *mut Blob<{{ helper node-camelcase-name }}>;
    fn {{ helper extern-into-variant-name }}(blob: Blob<Node>) -> Blob<{{ helper node-camelcase-name }}>;
{{ end }}<dnl>

    fn lib_ruby_parser__external__node__drop(blob: *mut Blob<Node>);
}

impl Drop for Node {
    fn drop(&mut self) {
        unsafe { lib_ruby_parser__external__node__drop(&mut self.blob) }
    }
}
";

pub(crate) fn codegen() {
    let template = TemplateRoot::new(TEMPLATE).unwrap();
    let mut fns = crate::codegen::fns::default_fns!();

    fns.register::<Node, F::Helper>(
        "extern-ctor-name",
        lib_ruby_parser_bindings::helpers::nodes::constructor::name,
    );
    fns.register::<Node, F::Helper>(
        "extern-is-variant-name",
        lib_ruby_parser_bindings::helpers::nodes::variant_predicate::name,
    );
    fns.register::<Node, F::Helper>(
        "extern-as-variant-name",
        lib_ruby_parser_bindings::helpers::nodes::variant_getter::name,
    );
    fns.register::<Node, F::Helper>(
        "extern-into-variant-name",
        lib_ruby_parser_bindings::helpers::nodes::into_variant::name,
    );

    let contents = template.render(ALL_DATA, &fns);
    std::fs::write("src/nodes/node_enum/external.rs", contents).unwrap();
}