use back::compiler::*;
pub struct ChoiceCompiler
{
choices: Vec<usize>,
compiler: ExprCompilerFn
}
impl ChoiceCompiler
{
pub fn recognizer(choices: Vec<usize>) -> ChoiceCompiler {
ChoiceCompiler {
choices: choices,
compiler: recognizer_compiler
}
}
pub fn parser(choices: Vec<usize>) -> ChoiceCompiler {
ChoiceCompiler {
choices: choices,
compiler: parser_compiler
}
}
}
impl CompileExpr for ChoiceCompiler
{
fn compile_expr<'a>(&self, context: &mut Context<'a>,
mut continuation: Continuation) -> syn::Expr
{
continuation = context.success_as_closure(continuation);
let mark = context.next_mark_name();
let branch_failed = context.next_branch_failed_name();
context.push_mut_ref_fv(branch_failed.clone(), parse_quote!(bool));
let scope = context.save_scope();
let mut choices = self.choices.clone();
let last = choices.pop().unwrap();
let mut branches: Vec<_> = choices.into_iter()
.map(|idx| {
context.restore_scope(scope.clone());
let b = branch_failed.clone();
let success: syn::Stmt = parse_quote!(#b = false;);
continuation.compile_and_wrap(context, self.compiler, idx, success)
})
.collect();
context.restore_scope(scope.clone());
context.pop_mut_ref_fv();
let (success, failure) = continuation.unwrap();
branches.push(context.compile(self.compiler, last, success, failure));
let mut branches_iter = branches.into_iter();
let first = branches_iter.next().unwrap();
let choice = branches_iter
.rev()
.fold(parse_quote!(state), |accu: syn::Expr, branch|
parse_quote!({
if #branch_failed {
let mut state = state.restore_from_failure(#mark.clone());
let state = #branch;
#accu
}
else { state }
}));
parse_quote!({
let #mark = state.mark();
let mut #branch_failed = true;
let state = #first;
#choice
})
}
}