fix quadratic parsing of expression

main
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 super::{IResult, Span};
use nom::{ use nom::{
branch::alt, branch::alt,
combinator::map, combinator::{map, opt},
multi::separated_list0, multi::separated_list0,
sequence::{delimited, preceded, separated_pair, tuple}, 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 /// bit and, or, xor e.g. a ^ b & c
/// TODO: make precedence rules for bit ops /// TODO: make precedence rules for bit ops
fn bitop(input: TokenSpan) -> IResult<TokenSpan, Expression> { fn bitop(input: TokenSpan) -> IResult<TokenSpan, Expression> {
alt(( // special care is given to avoid parsing `unary` twice, as that would
map(tuple((unary, bitop_kind, bitop)), |(a, kind, b)| { // make this parser quadratic
Expression::BinOp(Box::new(BinOp { a, b, kind })) map(
}), tuple((unary, opt(tuple((bitop_kind, bitop))))),
unary, |(a, rest)| {
))(input) if let Some((kind, b)) = rest {
Expression::BinOp(Box::new(BinOp { a, b, kind }))
} else {
a
}
},
)(input)
} }
pub fn call_item(input: TokenSpan) -> IResult<TokenSpan, Call> { pub fn call_item(input: TokenSpan) -> IResult<TokenSpan, Call> {
@ -140,6 +146,10 @@ mod test {
fn test_atoms() { fn test_atoms() {
fullexpr(TokenSpan::new(&tok("a"))).unwrap(); fullexpr(TokenSpan::new(&tok("a"))).unwrap();
fullexpr(TokenSpan::new(&tok("(a)"))).unwrap(); fullexpr(TokenSpan::new(&tok("(a)"))).unwrap();
fullexpr(TokenSpan::new(&tok(
"(((((((((((((((((((a)))))))))))))))))))",
)))
.unwrap();
} }
#[test] #[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(); 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] #[test]