lib-ruby-parser 3.0.11

Ruby parser
Documentation
use crate::codegen::rust::nodes::helpers::filename;
use lib_ruby_parser_nodes::{template::*, Node, NodeField};

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

crate::use_native_or_external!(Ptr);
crate::use_native_or_external!(StringPtr);
crate::use_native_or_external!(List);
crate::use_native_or_external!(Maybe);

use crate::{Node, Loc, Bytes};
#[allow(unused_imports)]
use super::{{ helper node-camelcase-name }};

fn new_loc() -> Loc {
    Loc::new(1, 2)
}

#[allow(dead_code)]
fn new_maybe_loc() -> Maybe<Loc> {
    Maybe::some(new_loc())
}

#[allow(dead_code)]
fn new_node() -> Node {
    Node::new_retry(new_loc())
}

#[allow(dead_code)]
fn new_node_ptr() -> Ptr<Node> {
    Ptr::new(new_node())
}

#[allow(dead_code)]
fn new_maybe_node_ptr() -> Maybe<Ptr<Node>> {
    Maybe::some(new_node_ptr())
}

#[allow(dead_code)]
fn new_string_ptr() -> StringPtr {
    StringPtr::from(\"foo\")
}

#[allow(dead_code)]
fn new_maybe_string_ptr() -> Maybe<StringPtr> {
    Maybe::some(new_string_ptr())
}

#[allow(dead_code)]
fn new_node_list() -> List<Node> {
    list![new_node()]
}

#[allow(dead_code)]
fn new_u8() -> u8 {
    42
}

#[allow(dead_code)]
fn new_bytes() -> Bytes {
    Bytes::new(list![1, 2, 3])
}

fn new_test_node() -> Node {
    Node::new_{{ helper node-lower-name }}(
{{ each node-field }}
        {{ helper new-field-fn }}(),
{{ end }}
    )
}

#[test]
fn test_constructor() {
    let node = new_test_node();
    drop(node);
}

#[test]
fn test_predicate() {
    let node = new_test_node();
    assert!(node.is_{{ helper node-lower-name }}());

    {{ helper compare-with-other-node-types }}
}

#[test]
fn test_debug() {
    assert_eq!(
        format!(\"{:?}\", new_test_node()),
        \"{{ helper expected-debug-output }}\"
    )
}

#[test]
fn test_partial_eq() {
    let node = new_test_node();
    let same = new_test_node();
    let other = Node::new_retry(Loc::new(100, 200));

    assert_eq!(node, same);
    assert_ne!(node, other);
}

#[test]
fn test_clone() {
    let node = new_test_node();
    assert_eq!(
        node,
        node.clone()
    );
}

#[test]
fn test_getters() {
    let node = new_test_node();
    let variant = node.into_{{ helper node-lower-name }}();

{{ each node-field }}<dnl>
    assert_eq!(variant.get_{{ helper node-field-name }}(), &{{ helper new-field-fn }}());
{{ end }}
}

#[test]
fn test_setters() {
    let node = new_test_node();
    let mut variant = node.into_{{ helper node-lower-name }}();

{{ each node-field }}
    variant.set_{{ helper node-field-name }}({{ helper new-field-fn }}());
    assert_eq!(variant.get_{{ helper node-field-name }}(), &{{ helper new-field-fn }}());
{{ end }}
}

#[test]
fn test_into_internal() {
    let node = new_test_node();
    let variant = node.into_{{ helper node-lower-name }}();
    let internal = variant.into_internal();

{{ each node-field }}
    assert_eq!(&internal.{{ helper node-field-rust-field-name }}, &{{ helper new-field-fn }}());
{{ end }}
}
";

pub(crate) fn codegen(node: &lib_ruby_parser_nodes::Node) {
    let template = NodeTemplateRoot::new(TEMPLATE).unwrap();
    let mut fns = crate::codegen::fns::default_fns!();

    fns.register::<NodeField, F::Helper>("new-field-fn", local_helpers::new_field_fn);
    fns.register::<Node, F::Helper>(
        "compare-with-other-node-types",
        local_helpers::compare_with_other_node_types,
    );
    fns.register::<Node, F::Helper>(
        "expected-debug-output",
        local_helpers::expected_debug_output,
    );

    let contents = template.render(node, &fns);

    let dir = filename(node);
    let path = format!("src/nodes/types/{}/tests.rs", dir);
    std::fs::write(&path, contents).unwrap();
}

mod local_helpers {
    use lib_ruby_parser_nodes::{Node, NodeField};

    pub(crate) fn new_field_fn(node_field: &NodeField) -> String {
        use lib_ruby_parser_nodes::NodeFieldType::*;

        match node_field.field_type {
            Node => "new_node_ptr",
            Nodes => "new_node_list",
            MaybeNode { .. } => "new_maybe_node_ptr",
            Loc => "new_loc",
            MaybeLoc => "new_maybe_loc",
            Str { .. } => "new_string_ptr",
            MaybeStr { .. } => "new_maybe_string_ptr",
            StringValue => "new_bytes",
            U8 => "new_u8",
        }
        .to_string()
    }

    pub(crate) fn compare_with_other_node_types(node: &Node) -> String {
        let mut others = lib_ruby_parser_nodes::nodes()
            .iter()
            .map(|node| node.lower_name())
            .collect::<Vec<_>>();
        others.retain(|e| e != &node.lower_name());
        others
            .iter()
            .map(|lower| format!("assert!(!node.is_{}());", lower))
            .collect::<Vec<_>>()
            .join("\n    ")
    }

    pub(crate) fn expected_debug_output(node: &Node) -> String {
        let d_loc = format!("1...2");
        let d_maybe_loc = format!("Some({})", d_loc);
        let d_node = format!("Retry(Retry {{ expression_l: {} }})", d_loc);
        let d_maybe_node = format!("Some({})", d_node);
        let d_node_list = format!("[{}]", d_node);
        let d_string_ptr = format!("\\\"foo\\\"");
        let d_maybe_string_ptr = format!("Some({})", d_string_ptr);
        let d_bytes = format!("Bytes {{ raw: [1, 2, 3] }}");
        let d_u8 = format!("42");

        let fields = node
            .fields
            .iter()
            .map(|field| {
                let key = crate::codegen::fns::rust::node_fields::rust_field_name(field);
                use lib_ruby_parser_nodes::NodeFieldType;
                let value = match field.field_type {
                    NodeFieldType::Node => &d_node,
                    NodeFieldType::Nodes => &d_node_list,
                    NodeFieldType::MaybeNode { .. } => &d_maybe_node,
                    NodeFieldType::Loc => &d_loc,
                    NodeFieldType::MaybeLoc => &d_maybe_loc,
                    NodeFieldType::Str { .. } => &d_string_ptr,
                    NodeFieldType::MaybeStr { .. } => &d_maybe_string_ptr,
                    NodeFieldType::StringValue => &d_bytes,
                    NodeFieldType::U8 => &d_u8,
                };
                format!("{}: {}", key, value)
            })
            .collect::<Vec<_>>()
            .join(", ");

        format!(
            "{node_type}({node_type} {{ {fields} }})",
            node_type = node.camelcase_name,
            fields = fields
        )
    }
}