Mercurial > lbo > hg > arithmetal
changeset 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 | 1d5a1a347148 |
children | b02268b0d4b1 |
files | src/generic_term_parser_experiment.rs src/lib.rs |
diffstat | 2 files changed, 73 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/generic_term_parser_experiment.rs Wed Nov 23 20:53:58 2016 +0100 @@ -0,0 +1,72 @@ + +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) + } + } +} +
--- a/src/lib.rs Wed Nov 23 20:34:31 2016 +0100 +++ b/src/lib.rs Wed Nov 23 20:53:58 2016 +0100 @@ -11,6 +11,7 @@ use std::iter::FromIterator; use std::str::FromStr; +use std::collections::HashMap; /// Expression tree #[derive(Debug, PartialEq)] @@ -276,7 +277,6 @@ } } } - fn sym<'a>(st: State<'a>) -> ParseResult { if st.len() == 0 { err("Empty", st)