view src/old_manual_parsers.rs @ 5:b02268b0d4b1 draft

Generalize two-hand expression parsing, and add parser for powers
author Lewin Bormann <lbo@spheniscida.de>
date Wed, 23 Nov 2016 21:13:05 +0100
parents
children ad77c2ad4853
line wrap: on
line source

fn expr<'a>(st: State<'a>) -> ParseResult {
    if st.len() == 0 {
        err("Empty", st)
    } else {
        // Test if addition or subtraction
        let mut paren_lvl = 0;
        let mut ix = 0;
        let mut op_pos: i32 = -1;

        for c in st.iter() {
            if c == '(' {
                paren_lvl += 1;
            } else if c == ')' {
                paren_lvl -= 1;
            } else if paren_lvl == 0 && (c == '+' || 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 st.at(op_pos as usize) == '-' {
                            ParseResult::Ok(Ast::Subtraction(Box::new(a1), Box::new(a2)))
                        } else {
                            ParseResult::Ok(Ast::Addition(Box::new(a1), Box::new(a2)))
                        }
                    }
                    _ => panic!("Expected OK results"),
                }
            } else if !left.ok() {
                err("Left part of expr is bad", st)
            } else {
                err("Right or both parts of expr is|are bad", st)
            }
        } else {
            term(st)
        }
    }
}

fn term<'a>(st: State<'a>) -> ParseResult {
    if st.len() == 0 {
        err("Empty", st)
    } else {
        // 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 && (c == '*' || 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 st.at(op_pos as usize) == '*' {
                            ParseResult::Ok(Ast::Multiplication(Box::new(a1), Box::new(a2)))
                        } else {
                            ParseResult::Ok(Ast::Division(Box::new(a1), Box::new(a2)))
                        }
                    }
                    _ => 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 {
            sym(st)
        }
    }
}
fn sym<'a>(st: State<'a>) -> ParseResult {
    if st.len() == 0 {
        err("Empty", st)
    } else if st.at(0) == '-' {
        match num(st.restrict(1, st.len())) {
            ParseResult::Ok(Ast::Num(n)) => ParseResult::Ok(Ast::Num(-n)),
            x => x,
        }
    } else {
        num(st)
    }
}

fn num<'a>(st: State<'a>) -> ParseResult {
    if st.len() == 0 {
        err("Empty", st)
    } else if st.iter().all(|c| c >= '0' && c <= '9') {
        let s = String::from_iter(st.iter());
        match i64::from_str(&s) {
            Ok(n) => ParseResult::Ok(Ast::Num(n)),
            Err(e) => err(&format!("int parse err: {}", e), st),
        }
    } else {
        err("Not a number", st)
    }
}