Skip to content

Commit

Permalink
cleanup and major bump as parser finished, now evaluator
Browse files Browse the repository at this point in the history
  • Loading branch information
dzhibas committed Feb 11, 2024
1 parent bcf4560 commit 12e9926
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 105 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[package]
name = "bool_expr_parser_nom"
version = "0.1.11"
version = "0.2.1"
edition = "2021"
authors = ["Nikolajus Krauklis <[email protected]>"]

[lints.rust]
unsafe_code = "forbid"
Expand Down
1 change: 0 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@
- [+] Scopes and negated scopes. ex.: a=b and !(c=d or g=z)
- [+] either lower() or upper() function calls or case insensitive string comparison operators
- [+] support for single quote strings
- [ ] not quoted strings as values treated as variables now, needs a fix
- [ ] evaluation with provided context
89 changes: 1 addition & 88 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,96 +15,9 @@ mod ast;
mod eval;
mod parse;

use ast::{ComparisonOp, LogicOp};
use std::{collections::HashMap, error::Error};

type Pair = HashMap<String, String>;
type AppError = Box<dyn Error>;

#[derive(Debug)]
pub enum AstNode<'a> {
Comparison {
op: ComparisonOp,
var: &'a str,
val: &'a str,
},
BoolExpression {
op: LogicOp,
lhs: Box<AstNode<'a>>,
rhs: Box<AstNode<'a>>,
},
}

fn parse_variable(i: &str) -> IResult<&str, &str> {
recognize(pair(
alt((alpha1, tag("_"))),
many0_count(alt((alphanumeric1, tag("_")))),
))(i)
}

fn parse_variable_clean_spaces(i: &str) -> IResult<&str, &str> {
preceded(multispace0, parse_variable)(i)
}

fn parse_comparison_op_old(i: &str) -> IResult<&str, ComparisonOp> {
let (i, t) = alt((
tag("="),
tag(">"),
tag("<"),
tag("=="),
tag(">="),
tag("<="),
tag("!="),
))(i)?;

Ok((i, ComparisonOp::from_str(t)))
}

fn parse_logic_op(i: &str) -> IResult<&str, LogicOp> {
let (i, t) = alt((tag_no_case("and"), tag("&&"), tag_no_case("or"), tag("||")))(i)?;
Ok((i, LogicOp::from_str(t)))
}

fn parse_equal(i: &str) -> IResult<&str, ComparisonOp> {
let (i, (_, op, _)) = tuple((space0, parse_comparison_op_old, space0))(i)?;
return Ok((i, op));
}

fn parse_string_value(i: &str) -> IResult<&str, &str> {
let (tail, (_, str, _)) = tuple((char('"'), take_until("\""), char('"')))(i)?;
Ok((tail, str))
}

fn parse_comparison(i: &str) -> IResult<&str, AstNode> {
map(
tuple((parse_variable_clean_spaces, parse_equal, parse_string_value)),
|(var, op, val)| AstNode::Comparison { op, var, val },
)(i)
}

// fn parse_bool_expr_and(i: &str) -> IResult<&str, LogicExpr> {
// let and = delimited(multispace0, tag_no_case("and"), multispace0);
// map(
// separated_pair(parse_assignment, and, parse_assignment),
// |(p1, p2)| LogicExpr::And(p1, p2),
// )(i)
// }
//
// fn parse_bool_expr_or(i: &str) -> IResult<&str, LogicExpr> {
// let or = delimited(multispace0, tag_no_case("or"), multispace0);
// map(
// separated_pair(parse_assignment, or, parse_assignment),
// |(p1, p2)| LogicExpr::Or(p1, p2),
// )(i)
// }

fn parse_main(i: &str) -> IResult<&str, AstNode> {
alt((parse_comparison,))(i)
}

#[wasm_bindgen]
pub fn parse_wasm(i: &str) -> String {
let Ok((i, tree)) = parse_main(i) else {
let Ok((i, tree)) = parse::parse(i) else {
todo!()
};
let b = format!("{:?}", tree);
Expand Down
36 changes: 22 additions & 14 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,18 @@ fn parse_parenthesized_expr(i: &str) -> IResult<&str, AstNode> {
}

fn parse_expr(input: &str) -> IResult<&str, AstNode> {
let (i, mut head) =
alt((parse_logic_expr, parse_compare_or_array_expr))(input).expect("parse failed");
let (i, mut head) = alt((
parse_parenthesized_expr,
parse_logic_expr,
parse_compare_or_array_expr,
))(input)
.expect("parse failed");

let (i, tail) =
many0(pair(ws(parse_logic_op), parse_compare_or_array_expr))(i).expect("Parse failed");
let (i, tail) = many0(pair(
ws(parse_logic_op),
alt((parse_compare_or_array_expr, parse_parenthesized_expr)),
))(i)
.expect("Parse failed");

for (op, expr) in tail {
head = AstNode::Logic(Box::new(head.clone()), op.clone(), Box::new(expr.clone()));
Expand Down Expand Up @@ -364,14 +371,15 @@ mod tests {
assert_eq!(res.is_ok(), true);
}

// #[test]
// fn test_extreme_test() {
// let expression = r###"a = b and c=d and something not in (1,2,3) or lower(z) == "demo car" or
// z == "demo car" or
// g in (4,5,6) and z == "demo car" or
// model in (ms,mx,m3,my) and created >= 2024-01-01
// and demo == false"###;
// let (i, v) = parse(expression).unwrap();
// assert_eq!(i, "");
// }
#[test]
fn test_extreme_logic_test() {
let expression = r###"a = b and c=d and something not in (1,2,3) or lower(z) == "demo car" or
z == "demo car" or
g in (4,5,6) and z == "demo car" or
model in (ms,mx,m3,my) and !(created >= 2024-01-01
and demo == false) and ((a=2) and not (c=3))"###;
let (i, v) = parse(expression).unwrap();
assert_eq!(i, "");
dbg!(v);
}
}

0 comments on commit 12e9926

Please sign in to comment.