use intern::InternedString;
use grammar::parse_tree::{ActionKind, Alternative, ExprSymbol, Symbol, SymbolKind};
#[derive(Debug)]
pub enum AlternativeAction<'a> {
User(&'a ActionKind),
Default(Symbols<'a>),
}
#[derive(Debug)]
pub enum Symbols<'a> {
Named(Vec<(usize, InternedString, &'a Symbol)>),
Anon(Vec<(usize, &'a Symbol)>),
}
pub fn analyze_action<'a>(alt: &'a Alternative) -> AlternativeAction<'a> {
if let Some(ref code) = alt.action {
return AlternativeAction::User(code);
}
AlternativeAction::Default(analyze_expr(&alt.expr))
}
pub fn analyze_expr<'a>(expr: &'a ExprSymbol) -> Symbols<'a> {
let named_symbols: Vec<_> =
expr.symbols
.iter()
.enumerate()
.filter_map(|(idx, sym)| match sym.kind {
SymbolKind::Name(id, ref sub) => Some((idx, id, &**sub)),
_ => None,
})
.collect();
if !named_symbols.is_empty() {
return Symbols::Named(named_symbols);
}
let chosen_symbol_types: Vec<_> =
expr.symbols
.iter()
.enumerate()
.filter_map(|(idx, sym)| match sym.kind {
SymbolKind::Choose(ref sub) => Some((idx, &**sub)),
_ => None,
})
.collect();
if !chosen_symbol_types.is_empty() {
return Symbols::Anon(chosen_symbol_types);
}
Symbols::Anon(expr.symbols.iter().enumerate().collect())
}