Parenthesis and implicit AND support
This commit is contained in:
parent
83b5431994
commit
9a14114e50
1 changed files with 98 additions and 10 deletions
|
@ -64,12 +64,12 @@ pub enum Expr {
|
|||
}
|
||||
|
||||
pub fn make_parser() -> impl Parser<char, Expr, Error = Simple<char>> {
|
||||
let combined = recursive(|expr| {
|
||||
recursive(|expr| {
|
||||
let quoted_str = just('"')
|
||||
.ignore_then(none_of('"').repeated().collect::<String>())
|
||||
.then_ignore(just('"'));
|
||||
|
||||
let raw_str = filter(|c: &char| !c.is_whitespace() && *c != '"')
|
||||
let raw_str = filter(|c: &char| !c.is_whitespace() && *c != '"' && *c != '(' && *c != ')')
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
.collect::<String>();
|
||||
|
@ -130,7 +130,7 @@ pub fn make_parser() -> impl Parser<char, Expr, Error = Simple<char>> {
|
|||
let fuzzy = literal.map(Expr::Fuzzy);
|
||||
|
||||
let filter = text_cmp.or(number_cmp).or(fuzzy);
|
||||
let atom = filter;
|
||||
let atom = choice((filter, expr.delimited_by(just('('), just(')'))));
|
||||
|
||||
let bool_op = choice((just("&&").to(BoolOp::And), just("||").to(BoolOp::Or))).padded();
|
||||
|
||||
|
@ -139,14 +139,14 @@ pub fn make_parser() -> impl Parser<char, Expr, Error = Simple<char>> {
|
|||
.then(bool_op.then(atom).repeated())
|
||||
.foldl(|a, (b, c)| Expr::Combined(Box::new(a), b, Box::new(c)));
|
||||
|
||||
combined
|
||||
});
|
||||
let implicit_and = combined
|
||||
.clone()
|
||||
.then(whitespace().ignore_then(combined).repeated())
|
||||
.foldl(|a: Expr, b: Expr| Expr::Combined(Box::new(a), BoolOp::And, Box::new(b)));
|
||||
|
||||
combined
|
||||
.clone()
|
||||
.then(whitespace().ignore_then(combined).repeated())
|
||||
.foldl(|a: Expr, b: Expr| Expr::Combined(Box::new(a), BoolOp::And, Box::new(b)))
|
||||
.then_ignore(end())
|
||||
implicit_and
|
||||
})
|
||||
.then_ignore(end())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -162,6 +162,36 @@ fn can_parse_fuzzy_query() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_repeat_fuzzy_queries() {
|
||||
let parser = make_parser();
|
||||
assert_eq!(
|
||||
parser.parse(r#"rhapsody "of victory""#).unwrap(),
|
||||
Expr::Combined(
|
||||
Box::new(Expr::Fuzzy(Literal::Text("rhapsody".to_owned()))),
|
||||
BoolOp::And,
|
||||
Box::new(Expr::Fuzzy(Literal::Text("of victory".to_owned()))),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_mix_fuzzy_and_structured() {
|
||||
let parser = make_parser();
|
||||
assert_eq!(
|
||||
parser.parse(r#"rhapsody album % dragonflame"#).unwrap(),
|
||||
Expr::Combined(
|
||||
Box::new(Expr::Fuzzy(Literal::Text("rhapsody".to_owned()))),
|
||||
BoolOp::And,
|
||||
Box::new(Expr::TextCmp(
|
||||
TextField::Album,
|
||||
TextOp::Like,
|
||||
"dragonflame".to_owned()
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_parse_text_fields() {
|
||||
let parser = make_parser();
|
||||
|
@ -371,3 +401,61 @@ fn boolean_operators_share_precedence() {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_use_parenthesis_for_precedence() {
|
||||
let parser = make_parser();
|
||||
assert_eq!(
|
||||
parser
|
||||
.parse(r#"album % lands || (album % tales && title % sword)"#)
|
||||
.unwrap(),
|
||||
Expr::Combined(
|
||||
Box::new(Expr::TextCmp(
|
||||
TextField::Album,
|
||||
TextOp::Like,
|
||||
"lands".to_owned()
|
||||
)),
|
||||
BoolOp::Or,
|
||||
Box::new(Expr::Combined(
|
||||
Box::new(Expr::TextCmp(
|
||||
TextField::Album,
|
||||
TextOp::Like,
|
||||
"tales".to_owned()
|
||||
)),
|
||||
BoolOp::And,
|
||||
Box::new(Expr::TextCmp(
|
||||
TextField::Title,
|
||||
TextOp::Like,
|
||||
"sword".to_owned()
|
||||
)),
|
||||
))
|
||||
),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
parser
|
||||
.parse(r#"(album % lands || album % tales) && title % "sword""#)
|
||||
.unwrap(),
|
||||
Expr::Combined(
|
||||
Box::new(Expr::Combined(
|
||||
Box::new(Expr::TextCmp(
|
||||
TextField::Album,
|
||||
TextOp::Like,
|
||||
"lands".to_owned()
|
||||
)),
|
||||
BoolOp::Or,
|
||||
Box::new(Expr::TextCmp(
|
||||
TextField::Album,
|
||||
TextOp::Like,
|
||||
"tales".to_owned()
|
||||
))
|
||||
)),
|
||||
BoolOp::And,
|
||||
Box::new(Expr::TextCmp(
|
||||
TextField::Title,
|
||||
TextOp::Like,
|
||||
"sword".to_owned()
|
||||
))
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue