use re::instruction::Instr;

/* The state of a program can be unambiguously specified by
 * a current instruction and a current position in the string. */
struct EvalState { pc: usize, cc: usize }

/* An evaluator that maintains a manual, mutable stack for doing
 * regular-expression matching. */
pub fn eval(instrs: &[Instr], input: &[char]) -> bool {
    let mut stack = vec![ EvalState {pc: 0, cc: 0} ];

    /* Every time we find that a possibility is impossible, we
     * remove it from the stack. If we have completed a match,
     * we'll short-circuit out of this loop; otherwise, an empty
     * stack means we have failed every possible branch and can
     * return false. */
    while let Some(st) = stack.pop() {
        match instrs[st.pc] {
            Instr::Char(_) if st.cc >= input.len() =>
                continue,
            Instr::Char(c) if c == input[st.cc] =>
                stack.push(EvalState { pc: st.pc + 1, cc: st.cc + 1 }),
            Instr::Char(_)     =>
                continue,
            Instr::Match       =>
                return true,
            Instr::Jmp(i)      =>
                stack.push(EvalState { pc: i, cc: st.cc }),
            Instr::Split(i, j) => {
                stack.push(EvalState { pc: j, cc: st.cc });
                stack.push(EvalState { pc: i, cc: st.cc });
            },
        }
    }
    return false;
}
