fix quadratic parsing of expression

This commit is contained in:
NotAFile 2022-02-06 18:39:07 +01:00
parent a69c6ab0b3
commit dfc74b4b24
1 changed files with 18 additions and 8 deletions

View File

@ -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<TokenSpan, BinOpKind> {
/// bit and, or, xor e.g. a ^ b & c
/// TODO: make precedence rules for bit ops
fn bitop(input: TokenSpan) -> IResult<TokenSpan, Expression> {
alt((
map(tuple((unary, bitop_kind, bitop)), |(a, kind, b)| {
// 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 }))
}),
unary,
))(input)
} else {
a
}
},
)(input)
}
pub fn call_item(input: TokenSpan) -> IResult<TokenSpan, Call> {
@ -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]