Mercurial > lbo > hg > arithmetal
view src/generic_term_parser_experiment.rs @ 4:000d0a69ed00 draft
Implement prototype for generic two-side operator parser
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Wed, 23 Nov 2016 20:53:58 +0100 |
parents | |
children |
line wrap: on
line source
type TwoHandBuilder = fn(Box<Ast>, Box<Ast>) -> Ast; type OperatorMap = HashMap<char, TwoHandBuilder>; fn term_op_map() -> OperatorMap { let mut map: OperatorMap = HashMap::new(); map.insert('*', Ast::Multiplication); map.insert('/', Ast::Division); map } fn expr_op_map() -> OperatorMap { let mut map: OperatorMap = HashMap::new(); map.insert('+', Ast::Addition); map.insert('-', Ast::Subtraction); map } fn parse_twohand_expr<'a>(opmap: OperatorMap, st: State<'a>) -> ParseResult { if st.len() == 0 { err("Empty", st) } else { let ops: Vec<char> = opmap.keys().map(|c| *c).collect(); // Predicate: Is this an operator we're looking for let _wanted_operator = |c: char| ops.iter().find(|d| c == **d).is_some(); // Test if addition or subtraction let mut paren_lvl = 0; let mut ix = 0; let mut op_pos: i32 = -1; // Look for operator at top level for c in st.iter() { if c == '(' { paren_lvl += 1; } else if c == ')' { paren_lvl -= 1; } else if paren_lvl == 0 && (_wanted_operator(c)) { // yep! op_pos = ix; break; } ix += 1; } if op_pos > -1 { let left = pexpr(st.restrict(0, op_pos as usize)); let right = pexpr(st.restrict(op_pos as usize + 1, st.len())); if left.ok() && right.ok() { match (left, right) { (ParseResult::Ok(a1), ParseResult::Ok(a2)) => { if let Some(builder) = opmap.get(&st.at(op_pos as usize)) { ParseResult::Ok(builder(Box::new(a1), Box::new(a2))) } else { err("No matching Ast builder found", st) } } _ => panic!("Expected OK results"), } } else if !left.ok() { err("Left part of term is bad", st) } else { err("Right or both parts of term is|are bad", st) } } else { // XXX This needs to be generic, too sym(st) } } }