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