use crate::jsonpath::ast::expr::{AndExpr, LogicalExpr, NotExpr, OrExpr, TestExpr, TestExprKind};
use crate::jsonpath::parser::comparison::try_parse as try_comparison;
use crate::jsonpath::parser::function::functions;
use crate::jsonpath::parser::primitives::{match_str, skip_whitespace};
use crate::jsonpath::parser::query::try_filter_query;
use crate::jsonpath::parser::{ParseError, ParseErrorKind, ParseResult};
use hurl_core::reader::Reader;
pub fn logical_or_expr(reader: &mut Reader) -> ParseResult<LogicalExpr> {
let mut operands = vec![];
operands.push(logical_and_expr(reader)?);
loop {
skip_whitespace(reader);
if !match_str("||", reader) {
break;
}
skip_whitespace(reader);
operands.push(logical_or_expr(reader)?);
}
if operands.len() == 1 {
Ok(operands.into_iter().next().unwrap())
} else {
Ok(LogicalExpr::Or(OrExpr::new(operands)))
}
}
fn logical_and_expr(reader: &mut Reader) -> ParseResult<LogicalExpr> {
let mut operands = vec![];
operands.push(basic_expr(reader)?);
loop {
skip_whitespace(reader);
if !match_str("&&", reader) {
break;
}
skip_whitespace(reader);
operands.push(basic_expr(reader)?);
}
if operands.len() == 1 {
Ok(operands.into_iter().next().unwrap())
} else {
Ok(LogicalExpr::And(AndExpr::new(operands)))
}
}
fn basic_expr(reader: &mut Reader) -> ParseResult<LogicalExpr> {
let save = reader.cursor();
if let Some(expr) = try_paren_expr(reader)? {
Ok(expr)
} else if let Some(comparison_expr) = try_comparison(reader)? {
Ok(LogicalExpr::Comparison(comparison_expr))
} else if let Some(test_expr) = try_test_expr(reader)? {
Ok(LogicalExpr::Test(test_expr))
} else {
Err(ParseError::new(
save.pos,
ParseErrorKind::Expecting("basic expression".to_string()),
))
}
}
fn try_paren_expr(reader: &mut Reader) -> ParseResult<Option<LogicalExpr>> {
let save = reader.cursor();
let not = match_str("!", reader);
skip_whitespace(reader);
if match_str("(", reader) {
let expr = logical_or_expr(reader)?;
if match_str(")", reader) {
let logical_expr = if not {
LogicalExpr::Not(NotExpr::new(expr))
} else {
expr
};
Ok(Some(logical_expr))
} else {
Err(ParseError::new(
reader.cursor().pos,
ParseErrorKind::Expecting("')'".to_string()),
))
}
} else {
reader.seek(save);
Ok(None)
}
}
fn try_test_expr(reader: &mut Reader) -> ParseResult<Option<TestExpr>> {
let not = match_str("!", reader);
skip_whitespace(reader);
if let Some(query) = try_filter_query(reader)? {
let kind = TestExprKind::FilterQuery(query);
Ok(Some(TestExpr::new(not, kind)))
} else if let Some(logical_type_function) = functions::try_logical_type_function(reader)? {
let kind = TestExprKind::LogicalTypeFunction(Box::new(logical_type_function));
Ok(Some(TestExpr::new(not, kind)))
} else {
Ok(None)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jsonpath::ast::comparison::{Comparable, ComparisonExpr, ComparisonOp};
use crate::jsonpath::ast::expr::{AndExpr, LogicalExpr, TestExpr, TestExprKind};
use crate::jsonpath::ast::function::argument::{RegexValueTypeArgument, ValueTypeArgument};
use crate::jsonpath::ast::function::functions::LogicalTypeFunction;
use crate::jsonpath::ast::literal::{Literal, Number};
use crate::jsonpath::ast::query::{AbsoluteQuery, Query, RelativeQuery};
use crate::jsonpath::ast::segment::{ChildSegment, Segment};
use crate::jsonpath::ast::selector::{NameSelector, Selector, WildcardSelector};
use crate::jsonpath::ast::singular_query::{
RelativeSingularQuery, SingularQuery, SingularQuerySegment,
};
use hurl_core::reader::Reader;
use regex::Regex;
#[test]
fn test_parse_logical_or_expr() {
let mut reader = Reader::new("@.b");
assert_eq!(
logical_or_expr(&mut reader).unwrap(),
LogicalExpr::Test(TestExpr::new(
false,
TestExprKind::FilterQuery(Query::RelativeQuery(RelativeQuery::new(vec![
Segment::Child(ChildSegment::new(vec![Selector::Name(NameSelector::new(
"b".to_string()
))]))
])))
))
);
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(3));
}
#[test]
fn test_parse_or_expression() {
let mut reader = Reader::new("@<2 || @>4");
assert_eq!(
logical_or_expr(&mut reader).unwrap(),
LogicalExpr::Or(OrExpr::new(vec![
LogicalExpr::Comparison(ComparisonExpr::new(
Comparable::SingularQuery(SingularQuery::Relative(RelativeSingularQuery::new(
vec![]
))),
Comparable::Literal(Literal::Number(Number::Integer(2))),
ComparisonOp::Less
)),
LogicalExpr::Comparison(ComparisonExpr::new(
Comparable::SingularQuery(SingularQuery::Relative(RelativeSingularQuery::new(
vec![]
))),
Comparable::Literal(Literal::Number(Number::Integer(4))),
ComparisonOp::Greater
))
]))
);
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(10));
}
#[test]
fn test_parse_and_expression() {
let mut reader = Reader::new("@>1&&@<4");
assert_eq!(
logical_and_expr(&mut reader).unwrap(),
LogicalExpr::And(AndExpr::new(vec![
LogicalExpr::Comparison(ComparisonExpr::new(
Comparable::SingularQuery(SingularQuery::Relative(RelativeSingularQuery::new(
vec![]
))),
Comparable::Literal(Literal::Number(Number::Integer(1))),
ComparisonOp::Greater
)),
LogicalExpr::Comparison(ComparisonExpr::new(
Comparable::SingularQuery(SingularQuery::Relative(RelativeSingularQuery::new(
vec![]
))),
Comparable::Literal(Literal::Number(Number::Integer(4))),
ComparisonOp::Less
))
]))
);
}
#[test]
fn test_parse_paren_expression() {
let mut reader = Reader::new("!(@.b)");
assert_eq!(
try_paren_expr(&mut reader).unwrap().unwrap(),
LogicalExpr::Not(NotExpr::new(LogicalExpr::Test(TestExpr::new(
false,
TestExprKind::FilterQuery(Query::RelativeQuery(RelativeQuery::new(vec![
Segment::Child(ChildSegment::new(vec![Selector::Name(NameSelector::new(
"b".to_string()
))]))
])))
))))
);
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(6));
}
#[test]
fn test_parse_paren_expression_none() {
let mut reader = Reader::new("!@.b");
assert!(try_paren_expr(&mut reader).unwrap().is_none());
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(0));
}
#[test]
fn test_parse_test_expr() {
let mut reader = Reader::new("@.b");
assert_eq!(
try_test_expr(&mut reader).unwrap().unwrap(),
TestExpr::new(
false,
TestExprKind::FilterQuery(Query::RelativeQuery(RelativeQuery::new(vec![
Segment::Child(ChildSegment::new(vec![Selector::Name(NameSelector::new(
"b".to_string()
))]))
])))
)
);
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(3));
let mut reader = Reader::new("$");
assert_eq!(
try_test_expr(&mut reader).unwrap().unwrap(),
TestExpr::new(
false,
TestExprKind::FilterQuery(Query::AbsoluteQuery(AbsoluteQuery::new(vec![])))
)
);
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(1));
let mut reader = Reader::new("$.*.a]");
assert_eq!(
try_test_expr(&mut reader).unwrap().unwrap(),
TestExpr::new(
false,
TestExprKind::FilterQuery(Query::AbsoluteQuery(AbsoluteQuery::new(vec![
Segment::Child(ChildSegment::new(vec![Selector::Wildcard(
WildcardSelector
)])),
Segment::Child(ChildSegment::new(vec![Selector::Name(NameSelector::new(
"a".to_string()
))]))
])))
)
);
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(5));
let mut reader = Reader::new("!@.a");
assert_eq!(
try_test_expr(&mut reader).unwrap().unwrap(),
TestExpr::new(
true,
TestExprKind::FilterQuery(Query::RelativeQuery(RelativeQuery::new(vec![
Segment::Child(ChildSegment::new(vec![Selector::Name(NameSelector::new(
"a".to_string()
))]))
])))
)
);
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(4));
let mut reader = Reader::new("match(@.a, 'a.*')");
assert_eq!(
try_test_expr(&mut reader).unwrap().unwrap(),
TestExpr::new(
false,
TestExprKind::LogicalTypeFunction(Box::new(LogicalTypeFunction::Match(
ValueTypeArgument::SingularQuery(SingularQuery::Relative(
RelativeSingularQuery::new(vec![SingularQuerySegment::Name(
NameSelector::new("a".to_string())
)])
)),
RegexValueTypeArgument::Literal(Regex::new("a.*").unwrap())
)))
)
);
assert_eq!(reader.cursor().index, hurl_core::reader::CharPos(17));
}
}