lib-ruby-parser 3.0.5

Ruby parser
Documentation
use lib_ruby_parser_nodes::{FieldType, Node};

include!("../../tests/loc_matcher/loc_name.rs");

impl LocName {
    fn to_str(&self) -> &'static str {
        match self {
            LocName::Begin => "begin_l",
            LocName::End => "end_l",
            LocName::Expression => "expression_l",
            LocName::Keyword => "keyword_l",
            LocName::Name => "name_l",
            LocName::Assignment => "assignment_l",
            LocName::Colon => "colon_l",
            LocName::DoubleColon => "double_colon_l",
            LocName::Else => "else_l",
            LocName::HeredocBody => "heredoc_body_l",
            LocName::Operator => "operator_l",
            LocName::Selector => "selector_l",
            LocName::Assoc => "assoc_l",
            LocName::Question => "question_l",
            LocName::HeredocEnd => "heredoc_end_l",
        }
    }
}

const LOC_NAMES: &[&'static LocName] = &[
    &LocName::Begin,
    &LocName::End,
    &LocName::Expression,
    &LocName::Keyword,
    &LocName::Name,
    &LocName::Assignment,
    &LocName::Colon,
    &LocName::DoubleColon,
    &LocName::Else,
    &LocName::HeredocBody,
    &LocName::Operator,
    &LocName::Selector,
    &LocName::Assoc,
    &LocName::Question,
    &LocName::HeredocEnd,
];

pub(crate) struct GetLocFn<'a> {
    nodes: &'a [Node],
}

impl<'a> GetLocFn<'a> {
    pub(crate) fn new(nodes: &'a [Node]) -> Self {
        Self { nodes }
    }

    pub(crate) fn write(&self) {
        std::fs::write("tests/loc_matcher/loc_name_gen.rs", self.contents()).unwrap();
    }

    fn contents(&self) -> String {
        format!(
            "use super::LocName;
use lib_ruby_parser::Node;

#[cfg(feature = \"compile-with-external-structures\")]
use lib_ruby_parser::containers::ExternalMaybeLoc;
#[cfg(feature = \"compile-with-external-structures\")]
type MaybeLoc = ExternalMaybeLoc;
#[cfg(not(feature = \"compile-with-external-structures\"))]
use lib_ruby_parser::Loc;
#[cfg(not(feature = \"compile-with-external-structures\"))]
type MaybeLoc = Option<Loc>;

impl LocName {{
    pub(crate) fn get(&self, node: &Node) -> MaybeLoc {{
        match self {{
            {loc_branches}
        }}
    }}
}}
",
            loc_branches = self.loc_branches().join("\n            ")
        )
    }

    fn loc_branches(&self) -> Vec<String> {
        LOC_NAMES
            .iter()
            .map(|loc_name| {
                let fallback = if loc_name.to_str() == "expression_l" {
                    "".to_string()
                } else {
                    format!(
                        "other => panic!(\"node {{}} doesn't support {} loc\", other.str_type()),",
                        loc_name.to_str()
                    )
                };

                format!(
                    "LocName::{:?} => match node {{
                {}
                {}
            }},",
                    loc_name,
                    loc_name.match_nodes(self.nodes).join("\n                "),
                    fallback
                )
            })
            .collect()
    }
}

impl LocName {
    pub(crate) fn match_nodes(&self, nodes: &[Node]) -> Vec<String> {
        nodes
            .iter()
            .filter_map(|node| {
                let field = node.fields.iter().find(|f| f.field_name == self.to_str())?;
                match field.field_type {
                    FieldType::Loc => Some(format!(
                        "Node::{struct_name}(inner) => inner.{loc_name}.clone().into(),",
                        struct_name = node.struct_name,
                        loc_name = self.to_str()
                    )),
                    FieldType::MaybeLoc => Some(format!(
                        "Node::{struct_name}(inner) => inner.{loc_name}.clone(),",
                        struct_name = node.struct_name,
                        loc_name = self.to_str()
                    )),
                    _ => return None,
                }
            })
            .collect()
    }
}