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)