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();
}