diff --git a/src/parser/expression.rs b/src/parser/expression.rs index f64939a..c7320e1 100644 --- a/src/parser/expression.rs +++ b/src/parser/expression.rs @@ -2,7 +2,7 @@ use super::tokens::{token, Token, TokenKind as tk, TokenSpan}; use super::{IResult, Span}; use nom::{ branch::alt, - combinator::map, + combinator::{map, opt}, multi::separated_list0, sequence::{delimited, preceded, separated_pair, tuple}, }; @@ -88,12 +88,18 @@ fn bitop_kind(input: TokenSpan) -> IResult { /// bit and, or, xor e.g. a ^ b & c /// TODO: make precedence rules for bit ops fn bitop(input: TokenSpan) -> IResult { - alt(( - map(tuple((unary, bitop_kind, bitop)), |(a, kind, b)| { - Expression::BinOp(Box::new(BinOp { a, b, kind })) - }), - unary, - ))(input) + // special care is given to avoid parsing `unary` twice, as that would + // make this parser quadratic + map( + tuple((unary, opt(tuple((bitop_kind, bitop))))), + |(a, rest)| { + if let Some((kind, b)) = rest { + Expression::BinOp(Box::new(BinOp { a, b, kind })) + } else { + a + } + }, + )(input) } pub fn call_item(input: TokenSpan) -> IResult { @@ -140,6 +146,10 @@ mod test { fn test_atoms() { fullexpr(TokenSpan::new(&tok("a"))).unwrap(); fullexpr(TokenSpan::new(&tok("(a)"))).unwrap(); + fullexpr(TokenSpan::new(&tok( + "(((((((((((((((((((a)))))))))))))))))))", + ))) + .unwrap(); } #[test] @@ -147,7 +157,7 @@ mod test { fullexpr(TokenSpan::new(&tok("asdf"))).unwrap(); fullexpr(TokenSpan::new(&tok("~(asdf)"))).unwrap(); fullexpr(TokenSpan::new(&tok("!asdf"))).unwrap(); - // unary(TokenSpan::new(&tok("~!(asdf)"))).unwrap(); + fullexpr(TokenSpan::new(&tok("~!(asdf)"))).unwrap(); } #[test]