use super::{NormResult, NormError};
use grammar::parse_tree::*;
use util::{Set};
#[cfg(test)]
mod test;
pub fn validate(grammar: &Grammar) -> NormResult<()> {
let conversions: Set<_> =
grammar.items
.iter()
.filter_map(|item| item.as_extern_token())
.flat_map(|tt| tt.enum_token.conversions.iter().map(|conversion| conversion.from))
.collect();
let validator = Validator {
grammar: grammar,
conversions: conversions,
};
validator.validate()
}
struct Validator<'grammar> {
grammar: &'grammar Grammar,
conversions: Set<TerminalString>,
}
impl<'grammar> Validator<'grammar> {
fn validate(&self) -> NormResult<()> {
for item in &self.grammar.items {
match *item {
GrammarItem::Use(..) => { }
GrammarItem::ExternToken(_) => { }
GrammarItem::Nonterminal(ref data) => {
for alternative in &data.alternatives {
try!(self.validate_alternative(alternative));
}
}
}
}
Ok(())
}
fn validate_alternative(&self, alternative: &Alternative) -> NormResult<()> {
assert!(alternative.condition.is_none()); try!(self.validate_expr(&alternative.expr));
Ok(())
}
fn validate_expr(&self, expr: &ExprSymbol) -> NormResult<()> {
for symbol in &expr.symbols {
try!(self.validate_symbol(symbol));
}
Ok(())
}
fn validate_symbol(&self, symbol: &Symbol) -> NormResult<()> {
match symbol.kind {
SymbolKind::Expr(ref expr) => {
try!(self.validate_expr(expr));
}
SymbolKind::Terminal(term) => {
try!(self.validate_terminal(symbol.span, term));
}
SymbolKind::Nonterminal(_) => {
}
SymbolKind::Repeat(ref repeat) => {
try!(self.validate_symbol(&repeat.symbol));
}
SymbolKind::Choose(ref sym) | SymbolKind::Name(_, ref sym) => {
try!(self.validate_symbol(sym));
}
SymbolKind::Lookahead | SymbolKind::Lookbehind => {
}
SymbolKind::AmbiguousId(id) => {
panic!("ambiguous id `{}` encountered after name resolution", id)
}
SymbolKind::Macro(..) => {
panic!("macro not removed: {:?}", symbol);
}
}
Ok(())
}
fn validate_terminal(&self, span: Span, term: TerminalString) -> NormResult<()> {
if !self.conversions.contains(&term) {
return_err!(span, "terminal `{}` does not have a pattern defined for it",
term);
}
Ok(())
}
}