1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
mod expander; mod linker; mod matcher; use std::sync::Arc; use arret_syntax::span::Span; use crate::context::ModuleId; use crate::hir::error::{Error, ErrorKind, Result}; use crate::hir::macros::expander::expand_rule; use crate::hir::macros::linker::{link_rule_vars, VarLinks}; use crate::hir::macros::matcher::match_rule; use crate::hir::ns::{Ident, NsDatum}; use crate::hir::scope::Scope; #[derive(Debug)] pub struct Rule { pattern_span: Span, pattern: Box<[NsDatum]>, template: NsDatum, var_links: VarLinks, } #[derive(Debug)] pub struct Macro { rules: Box<[Rule]>, } impl Macro { pub fn new(rules: Box<[Rule]>) -> Arc<Self> { Arc::new(Self { rules }) } } fn starts_with_zero_or_more(data: &[NsDatum]) -> bool { match data { [_, NsDatum::Ident(_, ident), ..] => ident.is_ellipsis(), _ => false, } } fn get_escaped_ident(data: &[NsDatum]) -> Option<&Ident> { match data { [NsDatum::Ident(_, ellipsis_ident), NsDatum::Ident(_, escaped_ident)] if ellipsis_ident.is_ellipsis() => { Some(escaped_ident) } _ => None, } } fn lower_macro_rule_datum( scope: &Scope<'_>, self_ident: &Ident, rule_datum: NsDatum, ) -> Result<Rule> { let (span, mut rule_values) = if let NsDatum::Vector(span, vs) = rule_datum { (span, vs.into_vec()) } else { return Err(Error::new( rule_datum.span(), ErrorKind::ExpectedMacroRuleVec(rule_datum.description()), )); }; if rule_values.len() != 2 { return Err(Error::new( span, ErrorKind::WrongMacroRuleVecCount(rule_values.len()), )); } let template = rule_values.pop().unwrap(); let pattern_datum = rule_values.pop().unwrap(); let (pattern_span, pattern) = if let NsDatum::List(span, vs) = pattern_datum { (span, vs) } else { return Err(Error::new( pattern_datum.span(), ErrorKind::ExpectedMacroRulePatternList(pattern_datum.description()), )); }; let var_links = link_rule_vars(scope, self_ident, pattern_span, &pattern, &template)?; Ok(Rule { pattern_span, pattern, template, var_links, }) } pub fn lower_macro_rules( scope: &Scope<'_>, self_ident: &Ident, macro_rules_data: Vec<NsDatum>, ) -> Result<Arc<Macro>> { let rules = macro_rules_data .into_iter() .map(|rule_datum| lower_macro_rule_datum(scope, self_ident, rule_datum)) .collect::<Result<Box<[Rule]>>>()?; Ok(Macro::new(rules)) } pub fn expand_macro<'s, 'p>( scope: &'s mut Scope<'p>, invocation_span: Span, module_id: Option<ModuleId>, mac: &Arc<Macro>, arg_data: &[NsDatum], ) -> Result<NsDatum> { for rule in mac.rules.iter() { let match_result = match_rule(rule, arg_data); if let Ok(match_data) = match_result { return Ok(expand_rule( scope, module_id, mac, &match_data, &rule.var_links, &rule.template, )); } } Err(Error::new( invocation_span, ErrorKind::NoMacroRule(mac.rules.iter().map(|rule| rule.pattern_span).collect()), )) }