regen/dynamic/
dyn_node.rs

1use super::{DynTok, DynToken};
2use crate::core::{Language, ParamDataType, ParamDecorType, RuleValue};
3use crate::sdk::{TokenBlocks, TokenStream};
4use crate::{list, optional, required};
5
6/// Dynamic AST node
7pub enum DynAstNode {
8    /// Exterior (leaf) AST node
9    ///
10    /// This is a token node
11    Exterior(DynToken),
12    /// Interior AST node
13    ///
14    /// This corresponds to a rule. The children nodes are the members of the rule
15    Interior(String /* rule_name */, Vec<DynAstNode>),
16    /// Vector AST node
17    ///
18    /// This corresponds to a vector parameter. The children nodes are the rule type and are in the vector.
19    InteriorVec(String /* rule_name */, Vec<DynAstNode>),
20}
21
22macro_rules! impl_dyn_ast_parse_param {
23    ($param:ident, $ts:ident, $children:ident, $parse_expr:expr) => {
24        match &$param.param_type.decor {
25            ParamDecorType::None => $children.push(required!($ts, $parse_expr)?),
26            ParamDecorType::Optional => {
27                if let Some(n) = optional!($ts, $parse_expr) {
28                    $children.push(n);
29                }
30            }
31            ParamDecorType::Vec(optional) => {
32                let v = if *optional {
33                    let mut v = vec![];
34                    list!($ts, v, $parse_expr)
35                } else {
36                    let mut v = vec![required!($ts, $parse_expr)?];
37                    list!($ts, v, $parse_expr)
38                };
39                $children.push(DynAstNode::InteriorVec($param.type_name.clone(), v))
40            }
41        }
42    };
43}
44
45impl DynAstNode {
46    /// Parse a rule from the token stream.
47    ///
48    /// `rule_name` is the name of the rule to parse
49    pub fn parse_rule(
50        ts: &mut TokenStream<DynTok>,
51        lang: &Language,
52        rule_name: &str,
53    ) -> Option<Self> {
54        let rule = lang.rules.get(rule_name).unwrap();
55        match &rule.value {
56            RuleValue::Union(rules) => {
57                if !ts.push() {
58                    return None;
59                };
60                for rule in rules {
61                    let n = Self::parse_rule(ts, lang, rule);
62                    if n.is_some() {
63                        ts.pop();
64                        return n;
65                    }
66                    ts.restore();
67                }
68                ts.pop();
69                None
70            }
71            RuleValue::Function(params) => {
72                let mut children = Vec::new();
73                for param in params {
74                    let type_name = &param.type_name;
75
76                    match &param.param_type.data {
77                        ParamDataType::Rule => {
78                            impl_dyn_ast_parse_param!(
79                                param,
80                                ts,
81                                children,
82                                Self::parse_rule(ts, lang, type_name)
83                            )
84                        }
85                        ParamDataType::String => {
86                            impl_dyn_ast_parse_param!(
87                                param,
88                                ts,
89                                children,
90                                Self::parse_token(ts, type_name)
91                            )
92                        }
93                        ParamDataType::Flag(lit) => impl_dyn_ast_parse_param!(
94                            param,
95                            ts,
96                            children,
97                            Self::parse_token_lit(ts, type_name, lit)
98                        ),
99                    }
100                }
101                Some(DynAstNode::Interior(rule_name.to_string(), children))
102            }
103        }
104    }
105
106    /// Parse a token from the token stream.
107    fn parse_token(ts: &mut TokenStream<DynTok>, token_name: &str) -> Option<Self> {
108        let token_type = format!("T{}", token_name);
109        ts.consume()
110            .filter(|token| token.token_type == token_type)
111            .cloned()
112            .map(DynAstNode::Exterior)
113    }
114
115    /// Parse a token with literal match from the token stream.
116    fn parse_token_lit(
117        ts: &mut TokenStream<DynTok>,
118        token_name: &str,
119        literal: &str,
120    ) -> Option<Self> {
121        let token_type = format!("T{}", token_name);
122        ts.consume()
123            .filter(|token| token.token_type == token_type && token.value == literal)
124            .cloned()
125            .map(DynAstNode::Exterior)
126    }
127
128    /// Apply semantic to the AST node based on the language
129    pub fn apply_semantic(
130        &self,
131        lang: &Language,
132        tbs: &mut TokenBlocks<DynTok>,
133        ovr: &Option<DynTok>,
134    ) {
135        match self {
136            DynAstNode::Exterior(token) => {
137                if let Some(ovr) = ovr {
138                    tbs.set(token, ovr.clone());
139                }
140            }
141            DynAstNode::Interior(rule_name, children)
142            | DynAstNode::InteriorVec(rule_name, children) => {
143                let rule = lang.rules.get(rule_name).unwrap();
144                // param and children has 1:1 mapping
145                let params = match &rule.value {
146                    RuleValue::Union(_) => panic!("Union rules should not be in dynamic AST"),
147                    RuleValue::Function(params) => params,
148                };
149                let semantic_override = params
150                    .iter()
151                    .map(|param| match &param.semantic {
152                        None => ovr.clone(),
153                        Some(s) => Some(format!("S{}", s)),
154                    })
155                    .collect::<Vec<_>>();
156
157                for (ovr, child) in semantic_override.iter().zip(children.iter()) {
158                    child.apply_semantic(lang, tbs, ovr);
159                }
160            }
161        }
162    }
163}