diff --git a/examples/main2.rs b/examples/main2.rs index e513364198a156282aebc871dcdd7bce124c9441..7270d7a6e95c025aa76234d3e04a5291f68eb608 100644 --- a/examples/main2.rs +++ b/examples/main2.rs @@ -94,39 +94,31 @@ fn climb_op(op: &Op) -> (u8, Ass) { } } - fn climb(e: Expr) -> Expr { println!("climb {:?}", &e); match e.clone() { Expr::Num(_) => e, Expr::BinOp(l, op, r) => { let (prec, ass) = climb_op(&op); - - // lookahead - match *r.clone() { + let new_r = *r; + match new_r.clone() { Expr::Num(_) => e, Expr::BinOp(r_l, r_op, r_r) => { let (r_prec, r_ass) = climb_op(&r_op); - println!( - "-- l: {:?}, r: {:?}, r_prec {}, prec {} - ", - r_l, r_r, prec, r_prec - ); if r_prec < prec - + match r_ass { + + match ass { Ass::Left => 1, Ass::Right => 0, } { - // swap - println!("swap"); + // push upwards + println!("push upwards {:?} {:?}", op, r_op); let new_l = Expr::BinOp(Box::new(*l), op, Box::new(*r_l)); - let new_top = Expr::BinOp(Box::new(new_l), r_op, Box::new(*r_r)); - - climb(new_top) + let new_top = Expr::BinOp(Box::new(new_l), r_op, Box::new(climb(*r_r))); + new_top } else { - Expr::BinOp(l, op, Box::new(climb(*r))) + Expr::BinOp(l, op, Box::new(climb(new_r))) } } } @@ -160,12 +152,12 @@ fn climb4() { #[test] fn climb5() { - test_eq("2*3+4+5", 2*3+4+5); + test_eq("2*3+4+5", 2 * 3 + 4 + 5); } #[test] fn climb6() { - test_eq("2*3-4*5-2", 2*3-4*5-2); + test_eq("2*3-4*5-2", 2 * 3 - 4 * 5 - 2); } #[test] @@ -173,74 +165,77 @@ fn climb_err() { test_eq("2 + 2 ^ 5 -3", 2 + 2i32.pow(5 - 3)); } - -fn main() { - println!("{}", 2^5); - let p = parse_expr("3*2+5").unwrap().1; - println!("{:?}", &p); - println!("math {}", math_expr(&p)); - let r = climb(p); - println!("r {:?}", &r); - println!("math r {}", math_expr(&r)); - println!("eval r {} = {} ", math_eval(&r), 3 * 2 + 5); - - println!(); - let p = parse_expr("3+2*5").unwrap().1; +fn climb_test(s: &str, v: i32) { + let p = parse_expr(s).unwrap().1; println!("{:?}", &p); println!("math {}", math_expr(&p)); let r = climb(p); println!("r {:?}", &r); println!("math r {}", math_expr(&r)); - println!("eval r {} = {} ", math_eval(&r), 3 + 2 * 5); - - println!(); - let p = parse_expr("3+2*5+27").unwrap().1; - println!("{:?}", &p); - println!("math {}", math_expr(&p)); - let r = climb(p); - println!("r {:?}", &r); - println!("math r {}", math_expr(&r)); - println!("eval r {} = {} ", math_eval(&r), 3 + 2 * 5 + 27); - - println!(); - let p = parse_expr("2*5+11*27+13").unwrap().1; - println!("{:?}", &p); - println!("math {}", math_expr(&p)); - let r = climb(p); - println!("r {:?}", &r); - println!("math r {}", math_expr(&r)); - println!("eval r {} = {} ", math_eval(&r), 2 * 5 + 11 * 27 + 13); - - println!(); - let p = parse_expr("1-2-3").unwrap().1; - println!("{:?}", &p); - println!("math {}", math_expr(&p)); - let r = climb(p); - println!("r {:?}", &r); - println!("math r {}", math_expr(&r)); - println!("eval r {} = {} ", math_eval(&r), 1 - 2 - 3); - - let i = "1-2-3-4"; - println!("\n{}", i); - let p = parse_expr(i).unwrap().1; - println!("{:?}", &p); - println!("math {}", math_expr(&p)); - println!("eval r {} = {} ", math_eval(&p), 1 - 2 - 3 - 4); - let r = climb(p); - println!("r {:?}", &r); - println!("math r {}", math_expr(&r)); - println!("eval r {} = {} ", math_eval(&r), ((1 - 2) - 3) - 4); - - - let i = "2^5-1"; - println!("\n{}", i); - let p = parse_expr(i).unwrap().1; - println!("{:?}", &p); - println!("math {}", math_expr(&p)); - println!("eval r {} = {} ", math_eval(&p), 1 - 2 - 3 - 4); - let r = climb(p); - println!("r {:?}", &r); - println!("math r {}", math_expr(&r)); - println!("eval r {} = {} ", math_eval(&r), ((1 - 2) - 3) - 4); + println!("eval r {} = {} ", math_eval(&r), v); +} +fn main() { + climb_test("2*5+10+10", 2*5+10+10); + climb_test("2*5+10*11-1", 2*5+10*11-1); + climb_test("2*5+10*11-2+12", 2*5+10*11-1+12); + // println!(); + // let p = parse_expr("3+2*5+27").unwrap().1; + // println!("{:?}", &p); + // println!("math {}", math_expr(&p)); + // let r = climb(p); + // println!("r {:?}", &r); + // println!("math r {}", math_expr(&r)); + // println!("eval r {} = {} ", math_eval(&r), 3 + 2 * 5 + 27); + + // println!(); + // let p = parse_expr("2*5+11*27+13").unwrap().1; + // println!("{:?}", &p); + // println!("math {}", math_expr(&p)); + // let r = climb(p); + // println!("r {:?}", &r); + // println!("math r {}", math_expr(&r)); + // println!("eval r {} = {} ", math_eval(&r), 2 * 5 + 11 * 27 + 13); + + // println!(); + // let p = parse_expr("1-2-3").unwrap().1; + // println!("{:?}", &p); + // println!("math {}", math_expr(&p)); + // let r = climb(p); + // println!("r {:?}", &r); + // println!("math r {}", math_expr(&r)); + // println!("eval r {} = {} ", math_eval(&r), 1 - 2 - 3); + + // let i = "1-2-3-4"; + // println!("\n{}", i); + // let p = parse_expr(i).unwrap().1; + // println!("{:?}", &p); + // println!("math {}", math_expr(&p)); + // println!("eval r {} = {} ", math_eval(&p), 1 - 2 - 3 - 4); + // let r = climb(p); + // println!("r {:?}", &r); + // println!("math r {}", math_expr(&r)); + // println!("eval r {} = {} ", math_eval(&r), ((1 - 2) - 3) - 4); + + // let i = "2*3-4*5-2"; + // println!("\n{}", i); + // let p = parse_expr(i).unwrap().1; + // println!("{:?}", &p); + // println!("math {}", math_expr(&p)); + // println!("eval r {} = {} ", math_eval(&p), 2 * 3 - 4 * 5 - 2); + // let r = climb(p); + // println!("r {:?}", &r); + // println!("math r {}", math_expr(&r)); + // println!("eval r {} = {} ", math_eval(&r), (2 * 3) - (4 * 5) - 2); + + // let i = "2^5-1"; + // println!("\n{}", i); + // let p = parse_expr(i).unwrap().1; + // println!("{:?}", &p); + // println!("math {}", math_expr(&p)); + // println!("eval r {} = {} ", math_eval(&p), 1 - 2 - 3 - 4); + // let r = climb(p); + // println!("r {:?}", &r); + // println!("math r {}", math_expr(&r)); + // println!("eval r {} = {} ", math_eval(&r), ((1 - 2) - 3) - 4); } diff --git a/examples/main3.rs b/examples/main3.rs new file mode 100644 index 0000000000000000000000000000000000000000..7ae13827b0873f6d007ebd88fe9c388cd78fb402 --- /dev/null +++ b/examples/main3.rs @@ -0,0 +1,333 @@ +use nom::{branch, bytes::complete::tag, character::complete::digit1, error, Err}; +use nom_locate::LocatedSpan; + +const INPUT: &str = "-2+3**2*3/5-4"; +//const INPUT: &str = "2+-3"; +//const INPUT: &str = "2+30000000000000000000000"; +//const INPUT: &str = "2"; +//const INPUT: &str = "30000000000000000000000"; +//const INPUT: &str = "3+2a"; + +const UNARYS: [Funcmap; 1] = [Funcmap { + keyword: "-", + prec: 4, + ass: Ass::Right, + func: Function::UnSub, +}]; + +const INFIXS: [Funcmap; 5] = [ + Funcmap { + keyword: "**", + prec: 3, + ass: Ass::Right, + func: Function::Pow, + }, + Funcmap { + keyword: "*", + prec: 2, + ass: Ass::Left, + func: Function::Mult, + }, + Funcmap { + keyword: "/", + prec: 2, + ass: Ass::Left, + func: Function::Div, + }, + Funcmap { + keyword: "+", + prec: 1, + ass: Ass::Left, + func: Function::Add, + }, + Funcmap { + keyword: "-", + prec: 1, + ass: Ass::Left, + func: Function::Sub, + }, +]; + +struct Expr<'a> { + span: Span<'a>, + val: Value<'a>, +} + +enum Value<'a> { + Int(i32), + UnFunc(Function, Box<Expr<'a>>), + Func(Function, Box<Expr<'a>>, Box<Expr<'a>>), +} + +#[derive(Clone, Copy)] +enum Function { + UnSub, + Pow, + Mult, + Div, + Add, + Sub, +} + +struct Funcmap { + keyword: &'static str, + prec: u8, + ass: Ass, + func: Function, +} + +enum Ass { + Left, + Right, +} + +type Span<'a> = LocatedSpan<&'a str>; +type SpanFuncmap<'a> = (Span<'a>, &'a Funcmap); +type IResult<'a, I, O, E = Error<'a>> = Result<(I, O), Err<E>>; + +fn main() { + match parse(Span::new(INPUT)) { + Ok(tree) => { + println!("{:#?}", SimpleExpr::new(&tree)); + } + Err(Error { + val: Some(val), + error, + .. + }) => println!( + "{:#?} at line {}, column {}:\n\t{}", + error.description(), + val.line, + val.get_utf8_column(), + val.fragment, + ), + Err(err) => panic!(err), + } +} + +fn parse<'a>(input: Span) -> Result<Expr, Error> { + match parse_expr(input) { + Ok((Span { fragment: "", .. }, tree)) => Ok(tree), + Ok((input, _)) => Err(Error { + input: input, + val: Some(input), + error: ErrorKind::NotRecognised, + }), + Err(Err::Incomplete(_)) => Err(Error { + input: input, + val: Some(input), + error: ErrorKind::Incomplete, + }), + Err(Err::Error(err)) => Err(err), + Err(Err::Failure(err)) => Err(err), + } +} + +fn parse_expr<'a>(input: Span) -> IResult<Span, Expr> { + branch::alt((parse_infix, parse_expr_nobin))(input) +} + +fn parse_expr_nobin<'a>(input: Span) -> IResult<Span, Expr> { + branch::alt((parse_unary, parse_expr_nobin_noun))(input) +} + +fn parse_expr_nobin_noun<'a>(input: Span) -> IResult<Span, Expr> { + parse_value(input) +} + +fn parse_value(input: Span) -> IResult<Span, Expr> { + // More primitive type categories go here (branch::alt() if > 1): + parse_number(input) +} + +fn parse_number(input: Span) -> IResult<Span, Expr> { + // More number types go here (branch::alt() if > 1): + parse_int(input) +} + +fn parse_int(input: Span) -> IResult<Span, Expr> { + let (input, digits) = digit1(input)?; + let int = match digits.fragment.parse() { + Ok(int) => int, + Err(err) => { + return Err(Err::Failure(Error { + input, + val: Some(digits), + error: ErrorKind::ParseInt(err), + })) + } + }; + Ok(( + input, + Expr { + span: digits, + val: Value::Int(int), + }, + )) +} + +fn parse_unary(input: Span) -> IResult<Span, Expr> { + let (input, (span, func_map)) = tag_unary(input)?; + let (input, right) = parse_expr_nobin(input)?; + Ok(( + input, + Expr { + span, + val: Value::UnFunc(func_map.func, Box::new(right)), + }, + )) +} + +fn parse_infix(input: Span) -> IResult<Span, Expr> { + // Initialize with minimum precedence 1. + parse_infix_first(input, 1) +} +fn parse_infix_first<'a>(input: Span, min_prec: u8) -> IResult<Span, Expr> { + // First, find left hand side expression. Search for everything but BinOps. + let (input, left) = parse_expr_nobin(input)?; + parse_infix_left(input, min_prec, left) +} +fn parse_infix_prec<'a>(input: Span, min_prec: u8) -> IResult<Span, Expr> { + // Almost identical to parse_infix_first(), but we do not accept unary ops. + let (input, left) = parse_expr_nobin_noun(input)?; + parse_infix_left(input, min_prec, left) +} +fn parse_infix_left<'a>( + input_bin: Span<'a>, + min_prec: u8, + left: Expr<'a>, +) -> IResult<'a, Span<'a>, Expr<'a>> { + // See if we can find an infix function. If not, return what we have. + let (input, (span, func_map)) = match tag_infix(input_bin) { + Ok(res) => res, + Err(Err::Error(Error { input, .. })) => return Ok((input, left)), + Err(err) => return Err(err), + }; + + // Does the new infix fulfill our precedence criteria? + if func_map.prec < min_prec { + return Ok((input_bin, left)); + } + + // Parse the right-hand-side. + let new_min_prec = match func_map.ass { + Ass::Left => func_map.prec + 1, + Ass::Right => func_map.prec, + }; + let (input, right) = parse_infix_prec(input, new_min_prec)?; + + // Put together the infix function with arguments. Continue forward. + let expr = Expr { + span, + val: Value::Func(func_map.func, Box::new(left), Box::new(right)), + }; + parse_infix_left(input, min_prec, expr) +} + +fn tag_unary(input: Span) -> IResult<Span, SpanFuncmap> { + tag_func(input, &UNARYS) +} + +fn tag_infix(input: Span) -> IResult<Span, SpanFuncmap> { + tag_func(input, &INFIXS) +} + +fn tag_func<'a>(input: Span<'a>, funcs: &'a [Funcmap]) -> IResult<'a, Span<'a>, SpanFuncmap<'a>> { + for func_map in funcs.iter() { + match tag(func_map.keyword)(input) { + Ok((input, span)) => return Ok((input, (span, &func_map))), + Err(Err::Error(_)) => (), + Err(err) => return Err(err), + } + } + Err(Err::Error(Error { + input, + val: None, + error: ErrorKind::Nom(error::ErrorKind::Tag), + })) +} + +#[derive(Debug)] +enum SimpleExpr<'a> { + Int(&'a i32), + UnSub(Box<SimpleExpr<'a>>), + Pow(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>), + Mult(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>), + Div(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>), + Add(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>), + Sub(Box<SimpleExpr<'a>>, Box<SimpleExpr<'a>>), +} + +impl<'a> SimpleExpr<'a> { + fn new(tree: &'a Expr) -> Self { + match tree { + Expr { + val: Value::Int(int), + .. + } => SimpleExpr::Int(&int), + Expr { + val: Value::UnFunc(Function::UnSub, x), + .. + } => SimpleExpr::UnSub(Box::new(SimpleExpr::new(x))), + Expr { + val: Value::Func(Function::Pow, x, y), + .. + } => SimpleExpr::Pow(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))), + Expr { + val: Value::Func(Function::Mult, x, y), + .. + } => SimpleExpr::Mult(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))), + Expr { + val: Value::Func(Function::Div, x, y), + .. + } => SimpleExpr::Div(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))), + Expr { + val: Value::Func(Function::Add, x, y), + .. + } => SimpleExpr::Add(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))), + Expr { + val: Value::Func(Function::Sub, x, y), + .. + } => SimpleExpr::Sub(Box::new(SimpleExpr::new(x)), Box::new(SimpleExpr::new(y))), + _ => panic!(), + } + } +} + +impl<'a> error::ParseError<Span<'a>> for Error<'a> { + fn from_error_kind(input: Span<'a>, kind: error::ErrorKind) -> Self { + Error { + input, + val: None, + error: ErrorKind::Nom(kind), + } + } + + fn append(_: Span<'a>, _: error::ErrorKind, other: Self) -> Self { + other + } +} + +struct Error<'a> { + input: Span<'a>, + val: Option<Span<'a>>, + error: ErrorKind, +} + +enum ErrorKind { + NotRecognised, + Incomplete, + ParseInt(std::num::ParseIntError), + Nom(error::ErrorKind), +} + +impl ErrorKind { + fn description(&self) -> String { + match self { + ErrorKind::NotRecognised => String::from("Failed to parse input."), + ErrorKind::Incomplete => String::from("There was not enough data."), + ErrorKind::ParseInt(err) => format!("Parse Int Error ({})", &err), + ErrorKind::Nom(err) => String::from(err.description()), + } + } +}