diff --git a/lalrpop/src/grammar/parse_tree.rs b/lalrpop/src/grammar/parse_tree.rs index edbffea..551da6b 100644 --- a/lalrpop/src/grammar/parse_tree.rs +++ b/lalrpop/src/grammar/parse_tree.rs @@ -119,7 +119,11 @@ pub struct InternToken { /// Set of `r"foo"` and `"foo"` literals extracted from the /// grammar. Sorted by order of increasing precedence. pub literals: Vec, - pub match_to_user_name_map: Option>, + + /// For each item remapped in a `match` block, map from the + /// regex we match to the name the user wants to use. + pub match_to_user_name_map: Map, + pub dfa: DFA } diff --git a/lalrpop/src/normalize/lower/mod.rs b/lalrpop/src/normalize/lower/mod.rs index 18e4be4..b417ad1 100644 --- a/lalrpop/src/normalize/lower/mod.rs +++ b/lalrpop/src/normalize/lower/mod.rs @@ -90,10 +90,8 @@ impl<'s> LowerState<'s> { }; // FIXME: This should be cleaner - if let Some(ref mm) = data.match_to_user_name_map { - if let Some(m) = mm.get(&literal) { - return (m.clone(), pattern); - } + if let Some(&m) = data.match_to_user_name_map.get(&literal) { + return (m, pattern); } (TerminalString::Literal(literal), pattern) diff --git a/lalrpop/src/normalize/token_check/mod.rs b/lalrpop/src/normalize/token_check/mod.rs index a35f01b..87d9e53 100644 --- a/lalrpop/src/normalize/token_check/mod.rs +++ b/lalrpop/src/normalize/token_check/mod.rs @@ -23,11 +23,11 @@ pub fn validate(mut grammar: Grammar) -> NormResult { let (has_enum_token, all_literals, match_to_user_name_map) = { let opt_match_token = grammar.match_token(); - let (match_to_user_name_map, user_name_to_match_map, match_catch_all) = if let Some(mt) = opt_match_token { - let mut match_to_user = map(); - let mut user_to_match = map(); - let mut catch_all = false; + let mut match_to_user_name_map = map(); + let mut user_name_to_match_map = map(); + let mut match_catch_all = false; + if let Some(mt) = opt_match_token { // FIXME: This should probably move _inside_ the Validator for (idx, mc) in mt.contents.iter().enumerate() { let precedence = &mt.contents.len() - idx; @@ -36,23 +36,22 @@ pub fn validate(mut grammar: Grammar) -> NormResult { match *item { MatchItem::Unmapped(sym, _) => { let precedence_sym = sym.with_match_precedence(precedence); - match_to_user.insert(precedence_sym, TerminalString::Literal(sym)); - user_to_match.insert(TerminalString::Literal(sym), precedence_sym); + match_to_user_name_map.insert(precedence_sym, TerminalString::Literal(sym)); + user_name_to_match_map.insert(TerminalString::Literal(sym), precedence_sym); }, MatchItem::Mapped(sym, mapping, _) => { let precedence_sym = sym.with_match_precedence(precedence); - match_to_user.insert(precedence_sym, mapping); - user_to_match.insert(mapping, precedence_sym); + match_to_user_name_map.insert(precedence_sym, mapping); + user_name_to_match_map.insert(mapping, precedence_sym); }, - MatchItem::CatchAll(_) => { catch_all = true; } + MatchItem::CatchAll(_) => { match_catch_all = true; } }; } } - - (Some(match_to_user), Some(user_to_match), Some(catch_all)) } else { - (None, None, None) - }; + // no match block is equivalent to `match { _ }` + match_catch_all = true; + } let opt_enum_token = grammar.enum_token(); let conversions = opt_enum_token.map(|et| { @@ -94,8 +93,8 @@ struct Validator<'grammar> { grammar: &'grammar Grammar, all_literals: Map, conversions: Option>, - user_name_to_match_map: Option>, - match_catch_all: Option, + user_name_to_match_map: Map, + match_catch_all: bool, } impl<'grammar> Validator<'grammar> { @@ -173,15 +172,10 @@ impl<'grammar> Validator<'grammar> { // the terminal literals ("class", r"[a-z]+") into a set. None => match term { // FIMXE: Should not allow undefined literals if no CatchAll - TerminalString::Bare(c) => match self.user_name_to_match_map { - Some(ref m) => { - if let Some(&vl) = m.get(&term) { - // FIXME: I don't think this span here is correct - self.all_literals.entry(vl).or_insert(span); - } else { - return_err!(span, "terminal `{}` does not have a match mapping defined for it", - term); - } + TerminalString::Bare(c) => match self.user_name_to_match_map.get(&term) { + Some(&vl) => { + // FIXME: I don't think this span here is correct + self.all_literals.entry(vl).or_insert(span); } None => { @@ -194,24 +188,20 @@ impl<'grammar> Validator<'grammar> { } }, - TerminalString::Literal(l) => match self.user_name_to_match_map { - Some(ref m) => { - if let Some(&vl) = m.get(&term) { - // FIXME: I don't think this span here is correct - self.all_literals.entry(vl).or_insert(span); - } else { - // Unwrap should be safe as we shouldn't have match_catch_all without user_name_to_match_map - if self.match_catch_all.unwrap() { - // FIXME: I don't think this span here is correct - self.all_literals.entry(l).or_insert(span); - } else { - return_err!(span, "terminal `{}` does not have a match mapping defined for it", - term); - } + TerminalString::Literal(l) => match self.user_name_to_match_map.get(&term) { + Some(&vl) => { + // FIXME: I don't think this span here is correct + self.all_literals.entry(vl).or_insert(span); + } + None => { + if self.match_catch_all { + self.all_literals.entry(l).or_insert(span); + } else { + return_err!(span, "terminal `{}` does not have a match mapping defined for it", + term); } } - None => { self.all_literals.entry(l).or_insert(span); } }, // Error is a builtin terminal that always exists @@ -227,7 +217,7 @@ impl<'grammar> Validator<'grammar> { // Construction phase -- if we are constructing a tokenizer, this // phase builds up an internal token DFA. -pub fn construct(grammar: &mut Grammar, literals_map: Map, match_to_user_name_map: Option>) -> NormResult<()> { +pub fn construct(grammar: &mut Grammar, literals_map: Map, match_to_user_name_map: Map) -> NormResult<()> { let mut literals: Vec = literals_map.keys() .cloned() diff --git a/lalrpop/src/normalize/tyinfer/mod.rs b/lalrpop/src/normalize/tyinfer/mod.rs index 05d0543..e71189b 100644 --- a/lalrpop/src/normalize/tyinfer/mod.rs +++ b/lalrpop/src/normalize/tyinfer/mod.rs @@ -81,8 +81,7 @@ impl<'grammar> TypeInferencer<'grammar> { for &literal in &intern_token.literals { let user_name = intern_token.match_to_user_name_map - .as_ref() - .and_then(|it| it.get(&literal)) + .get(&literal) .cloned() .unwrap_or(TerminalString::Literal(literal)); types.add_term_type(user_name, input_str.clone());