make the map/catch-all non-optional in validator

This commit is contained in:
Niko Matsakis 2017-03-29 06:43:59 -06:00
parent 61c2ce1522
commit b75669c8d6
4 changed files with 38 additions and 47 deletions

View File

@ -119,7 +119,11 @@ pub struct InternToken {
/// Set of `r"foo"` and `"foo"` literals extracted from the /// Set of `r"foo"` and `"foo"` literals extracted from the
/// grammar. Sorted by order of increasing precedence. /// grammar. Sorted by order of increasing precedence.
pub literals: Vec<TerminalLiteral>, pub literals: Vec<TerminalLiteral>,
pub match_to_user_name_map: Option<Map<TerminalLiteral, TerminalString>>,
/// 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<TerminalLiteral, TerminalString>,
pub dfa: DFA pub dfa: DFA
} }

View File

@ -90,10 +90,8 @@ impl<'s> LowerState<'s> {
}; };
// FIXME: This should be cleaner // FIXME: This should be cleaner
if let Some(ref mm) = data.match_to_user_name_map { if let Some(&m) = data.match_to_user_name_map.get(&literal) {
if let Some(m) = mm.get(&literal) { return (m, pattern);
return (m.clone(), pattern);
}
} }
(TerminalString::Literal(literal), pattern) (TerminalString::Literal(literal), pattern)

View File

@ -23,11 +23,11 @@ pub fn validate(mut grammar: Grammar) -> NormResult<Grammar> {
let (has_enum_token, all_literals, match_to_user_name_map) = { let (has_enum_token, all_literals, match_to_user_name_map) = {
let opt_match_token = grammar.match_token(); 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_name_map = map();
let mut match_to_user = map(); let mut user_name_to_match_map = map();
let mut user_to_match = map(); let mut match_catch_all = false;
let mut catch_all = false;
if let Some(mt) = opt_match_token {
// FIXME: This should probably move _inside_ the Validator // FIXME: This should probably move _inside_ the Validator
for (idx, mc) in mt.contents.iter().enumerate() { for (idx, mc) in mt.contents.iter().enumerate() {
let precedence = &mt.contents.len() - idx; let precedence = &mt.contents.len() - idx;
@ -36,23 +36,22 @@ pub fn validate(mut grammar: Grammar) -> NormResult<Grammar> {
match *item { match *item {
MatchItem::Unmapped(sym, _) => { MatchItem::Unmapped(sym, _) => {
let precedence_sym = sym.with_match_precedence(precedence); let precedence_sym = sym.with_match_precedence(precedence);
match_to_user.insert(precedence_sym, TerminalString::Literal(sym)); match_to_user_name_map.insert(precedence_sym, TerminalString::Literal(sym));
user_to_match.insert(TerminalString::Literal(sym), precedence_sym); user_name_to_match_map.insert(TerminalString::Literal(sym), precedence_sym);
}, },
MatchItem::Mapped(sym, mapping, _) => { MatchItem::Mapped(sym, mapping, _) => {
let precedence_sym = sym.with_match_precedence(precedence); let precedence_sym = sym.with_match_precedence(precedence);
match_to_user.insert(precedence_sym, mapping); match_to_user_name_map.insert(precedence_sym, mapping);
user_to_match.insert(mapping, precedence_sym); 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 { } else {
(None, None, None) // no match block is equivalent to `match { _ }`
}; match_catch_all = true;
}
let opt_enum_token = grammar.enum_token(); let opt_enum_token = grammar.enum_token();
let conversions = opt_enum_token.map(|et| { let conversions = opt_enum_token.map(|et| {
@ -94,8 +93,8 @@ struct Validator<'grammar> {
grammar: &'grammar Grammar, grammar: &'grammar Grammar,
all_literals: Map<TerminalLiteral, Span>, all_literals: Map<TerminalLiteral, Span>,
conversions: Option<Set<TerminalString>>, conversions: Option<Set<TerminalString>>,
user_name_to_match_map: Option<Map<TerminalString, TerminalLiteral>>, user_name_to_match_map: Map<TerminalString, TerminalLiteral>,
match_catch_all: Option<bool>, match_catch_all: bool,
} }
impl<'grammar> Validator<'grammar> { impl<'grammar> Validator<'grammar> {
@ -173,15 +172,10 @@ impl<'grammar> Validator<'grammar> {
// the terminal literals ("class", r"[a-z]+") into a set. // the terminal literals ("class", r"[a-z]+") into a set.
None => match term { None => match term {
// FIMXE: Should not allow undefined literals if no CatchAll // FIMXE: Should not allow undefined literals if no CatchAll
TerminalString::Bare(c) => match self.user_name_to_match_map { TerminalString::Bare(c) => match self.user_name_to_match_map.get(&term) {
Some(ref m) => { Some(&vl) => {
if let Some(&vl) = m.get(&term) { // FIXME: I don't think this span here is correct
// FIXME: I don't think this span here is correct self.all_literals.entry(vl).or_insert(span);
self.all_literals.entry(vl).or_insert(span);
} else {
return_err!(span, "terminal `{}` does not have a match mapping defined for it",
term);
}
} }
None => { None => {
@ -194,24 +188,20 @@ impl<'grammar> Validator<'grammar> {
} }
}, },
TerminalString::Literal(l) => match self.user_name_to_match_map { TerminalString::Literal(l) => match self.user_name_to_match_map.get(&term) {
Some(ref m) => { Some(&vl) => {
if let Some(&vl) = m.get(&term) { // FIXME: I don't think this span here is correct
// FIXME: I don't think this span here is correct self.all_literals.entry(vl).or_insert(span);
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);
}
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 // 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 // Construction phase -- if we are constructing a tokenizer, this
// phase builds up an internal token DFA. // phase builds up an internal token DFA.
pub fn construct(grammar: &mut Grammar, literals_map: Map<TerminalLiteral, Span>, match_to_user_name_map: Option<Map<TerminalLiteral, TerminalString>>) -> NormResult<()> { pub fn construct(grammar: &mut Grammar, literals_map: Map<TerminalLiteral, Span>, match_to_user_name_map: Map<TerminalLiteral, TerminalString>) -> NormResult<()> {
let mut literals: Vec<TerminalLiteral> = let mut literals: Vec<TerminalLiteral> =
literals_map.keys() literals_map.keys()
.cloned() .cloned()

View File

@ -81,8 +81,7 @@ impl<'grammar> TypeInferencer<'grammar> {
for &literal in &intern_token.literals { for &literal in &intern_token.literals {
let user_name = intern_token.match_to_user_name_map let user_name = intern_token.match_to_user_name_map
.as_ref() .get(&literal)
.and_then(|it| it.get(&literal))
.cloned() .cloned()
.unwrap_or(TerminalString::Literal(literal)); .unwrap_or(TerminalString::Literal(literal));
types.add_term_type(user_name, input_str.clone()); types.add_term_type(user_name, input_str.clone());