pub mod absolute_time;
pub mod binary_expression;
pub mod error;
pub mod relative_time;
pub mod string;
pub mod utils;
use crate::{
ast::{
AbsolutePath, ErrorToken, Expression, PathElement, UnaryExpression, UnaryOperator, Value,
WildcardPath,
},
parser::{
absolute_time::{date_time, date_value},
binary_expression::binary_expr,
error::{error, expect, Error},
relative_time::relative_time_value,
string::string,
utils::{keyword, IResult, LocatedSpan, State, ToRange},
},
};
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{alpha1, alphanumeric1, char, digit1, multispace0},
combinator::{all_consuming, map, map_res, opt, recognize, value},
multi::{many0, many1},
sequence::{delimited, pair, preceded, tuple},
};
use std::{cell::RefCell, str::FromStr};
pub(crate) fn identifier(i: LocatedSpan) -> IResult<LocatedSpan> {
recognize(pair(
alt((alpha1, tag("_"))),
many0(alt((alphanumeric1, tag("_")))),
))(i)
}
pub(crate) fn expr(i: LocatedSpan) -> IResult<Expression> {
let parse_expr = |i| alt((binary_expr, simple_expr))(i);
let (i, expr) = parse_expr(i)?;
match many1(parse_expr)(i.clone()) {
Err(nom::Err::Error(_)) => Ok((i, expr)),
Err(err) => Err(err),
Ok((i2, mut expressions)) => {
i2.extra.report_error_if_no_overlap(Error(
(i.to_range().start)..(i2.to_range().start),
"expected an operator between expressions".to_string(),
));
expressions.insert(0, expr);
Ok((i2, Expression::Error(ErrorToken::List(expressions))))
}
}
}
pub(crate) fn simple_expr(i: LocatedSpan) -> IResult<Expression> {
delimited(
multispace0,
alt((
unary_expr, path_expr, paren_expr, value_expr, path_start, error,
)),
multispace0,
)(i)
}
fn unary_expr(i: LocatedSpan) -> IResult<Expression> {
map(tuple((keyword("not"), simple_expr)), |(_, expr)| {
Expression::UnaryExpression(Box::new(UnaryExpression {
op: UnaryOperator::Not,
expr,
}))
})(i)
}
fn paren_expr(i: LocatedSpan) -> IResult<Expression> {
let paren = delimited(
multispace0,
delimited(
char('('),
expect(expr, "expected expression after `(`"),
expect(char(')'), "expected `)`"),
),
multispace0,
);
map(paren, |inner| {
inner.unwrap_or(Expression::Error(ErrorToken::Unexpected))
})(i)
}
fn path_expr(i: LocatedSpan) -> IResult<Expression> {
map(wildcard_path, |path| {
let absolute_path = path.0.iter().all(|path_element| match path_element {
PathElement::Field(_) => true,
_ => false,
});
if absolute_path {
Expression::AbsolutePath(
path
.0
.into_iter()
.map(|path_element| match path_element {
PathElement::Field(field) => field,
_ => unreachable!(),
})
.collect(),
)
} else {
Expression::WildcardPath(path)
}
})(i)
}
fn absolute_path(i: LocatedSpan) -> IResult<AbsolutePath> {
many1(path_field_element)(i)
}
fn path_field_element(i: LocatedSpan) -> IResult<String> {
preceded(
tag("."),
alt((
map(identifier, |res: LocatedSpan| String::from(*res)),
string,
)),
)(i)
}
fn wildcard_path(i: LocatedSpan) -> IResult<WildcardPath> {
map(many1(path_element), WildcardPath)(i)
}
fn path_element(i: LocatedSpan) -> IResult<PathElement> {
preceded(
tag("."),
alt((
value(PathElement::RecursiveWildcard, tag("**")),
value(PathElement::Wildcard, tag("*")),
map(identifier, |res: LocatedSpan| {
PathElement::Field(String::from(*res))
}),
map(string, PathElement::Field),
)),
)(i)
}
fn path_start(i: LocatedSpan) -> IResult<Expression> {
value(Expression::Error(ErrorToken::PathStart), tag("."))(i)
}
fn value_expr(i: LocatedSpan) -> IResult<Expression> {
map(
alt((
null,
bool,
float,
string_value,
date_time,
date_value,
relative_time_value,
int,
)),
Expression::Value,
)(i)
}
fn null(i: LocatedSpan) -> IResult<Value> {
value(Value::Null, keyword("null"))(i)
}
fn bool(i: LocatedSpan) -> IResult<Value> {
map(
alt((keyword("true"), keyword("false"))),
|res: LocatedSpan| Value::Bool(*res == "true"),
)(i)
}
fn float(i: LocatedSpan) -> IResult<Value> {
map(float64, Value::Float)(i)
}
fn float64(i: LocatedSpan) -> IResult<f64> {
map_res(
recognize(tuple((
opt(alt((tag("+"), tag("-")))),
digit1,
tag("."),
digit1,
))),
|res: LocatedSpan| f64::from_str(*res),
)(i)
}
fn int(i: LocatedSpan) -> IResult<Value> {
map(int64, Value::Int)(i)
}
fn int64(i: LocatedSpan) -> IResult<i64> {
map_res(
recognize(tuple((opt(alt((tag("+"), tag("-")))), digit1))),
|res: LocatedSpan| i64::from_str_radix(*res, 10),
)(i)
}
fn string_value(i: LocatedSpan) -> IResult<Value> {
map(string, Value::String)(i)
}
pub fn is_valid_identifier(i: &str) -> bool {
let errors = RefCell::new(Vec::new());
let input = LocatedSpan::new_extra(i, State::new(&errors));
let all_parsed = all_consuming(identifier)(input).is_ok();
all_parsed && errors.into_inner().is_empty()
}
pub fn parse_absolute_path<'a>(i: &'a str) -> (AbsolutePath, Vec<Error>) {
let errors = RefCell::new(Vec::new());
let input = LocatedSpan::new_extra(i, State::new(&errors));
let (_, expr) = all_consuming(absolute_path)(input)
.map_err(|err| {
println!("Errors: {:?}", errors);
err
})
.expect("parser cannot fail");
(expr, errors.into_inner())
}
pub fn parse_wildcard_path<'a>(i: &'a str) -> (WildcardPath, Vec<Error>) {
let errors = RefCell::new(Vec::new());
let input = LocatedSpan::new_extra(i, State::new(&errors));
let (_, expr) = all_consuming(wildcard_path)(input)
.map_err(|err| {
println!("Errors: {:?}", errors);
err
})
.expect("parser cannot fail");
(expr, errors.into_inner())
}
pub fn parse_filter<'a>(i: &'a str) -> (Expression, Vec<Error>) {
let errors = RefCell::new(Vec::new());
let input = LocatedSpan::new_extra(i, State::new(&errors));
let (_, expr) = all_consuming(expr)(input)
.map_err(|err| {
println!("Errors: {:?}", errors);
err
})
.expect("parser cannot fail");
(expr, errors.into_inner())
}
#[cfg(test)]
mod tests {
use super::{bool, float, int, null, parse_filter, path_expr, value_expr};
use crate::{
ast::{
BinaryExpression, BinaryOperator, ErrorToken, Expression, PathElement, Value, WildcardPath,
},
parser::{
error::Error,
utils::{span, unwrap_span},
},
};
#[test]
fn test_path_expr() {
assert_eq!(
path_expr(span(".a.b.c")).map(unwrap_span),
Ok((
"",
Expression::AbsolutePath(vec!["a".to_string(), "b".to_string(), "c".to_string(),])
))
);
assert_eq!(
path_expr(span(".a.b.c some other data")).map(unwrap_span),
Ok((
" some other data",
Expression::AbsolutePath(vec!["a".to_string(), "b".to_string(), "c".to_string(),])
))
);
assert_eq!(
path_expr(span(".a.b.\"c some strange property\"")).map(unwrap_span),
Ok((
"",
Expression::AbsolutePath(vec![
"a".to_string(),
"b".to_string(),
"c some strange property".to_string(),
])
))
);
assert_eq!(
path_expr(span(".a.*.c")).map(unwrap_span),
Ok((
"",
Expression::WildcardPath(WildcardPath(vec![
PathElement::Field("a".to_string()),
PathElement::Wildcard,
PathElement::Field("c".to_string()),
]))
))
);
assert_eq!(
path_expr(span(".a.**.c")).map(unwrap_span),
Ok((
"",
Expression::WildcardPath(WildcardPath(vec![
PathElement::Field("a".to_string()),
PathElement::RecursiveWildcard,
PathElement::Field("c".to_string()),
]))
))
);
}
#[test]
fn test_null() {
assert_eq!(null(span("null")).map(unwrap_span), Ok(("", Value::Null)));
}
#[test]
fn test_bool() {
assert_eq!(
bool(span("true")).map(unwrap_span),
Ok(("", Value::Bool(true)))
);
assert_eq!(
bool(span("false")).map(unwrap_span),
Ok(("", Value::Bool(false)))
);
assert_eq!(
bool(span("true)")).map(unwrap_span),
Ok((")", Value::Bool(true)))
);
assert_eq!(
bool(span("false)")).map(unwrap_span),
Ok((")", Value::Bool(false)))
);
assert!(bool(span("truea")).is_err());
assert!(bool(span("falsea")).is_err());
}
#[test]
fn test_float() {
assert_eq!(
float(span("3.14")).map(unwrap_span),
Ok(("", Value::Float(3.14)))
);
assert_eq!(
float(span("-42.0")).map(unwrap_span),
Ok(("", Value::Float(-42.0)))
);
}
#[test]
fn test_int() {
assert_eq!(int(span("3")).map(unwrap_span), Ok(("", Value::Int(3))));
assert_eq!(int(span("-42")).map(unwrap_span), Ok(("", Value::Int(-42))));
}
#[test]
fn test_value_expr() {
assert_eq!(
value_expr(span("3.14")).map(unwrap_span),
Ok(("", Expression::Value(Value::Float(3.14))))
);
assert_eq!(
value_expr(span("-42.0")).map(unwrap_span),
Ok(("", Expression::Value(Value::Float(-42.0))))
);
assert_eq!(
value_expr(span("3")).map(unwrap_span),
Ok(("", Expression::Value(Value::Int(3))))
);
assert_eq!(
value_expr(span("-42")).map(unwrap_span),
Ok(("", Expression::Value(Value::Int(-42))))
);
}
#[test]
fn test_error_reporting() {
assert_eq!(
parse_filter("()"),
(
Expression::Error(ErrorToken::Unexpected),
vec![Error(1..2, "expected expression after `(`".to_string())]
)
);
assert_eq!(
parse_filter("(true"),
(
Expression::Value(Value::Bool(true)),
vec![Error(5..5, "expected `)`".to_string())]
)
);
assert_eq!(
parse_filter(".time .level > 20"),
(
Expression::Error(ErrorToken::List(vec![
Expression::AbsolutePath(vec!["time".to_string()]),
Expression::BinaryExpression(Box::new(BinaryExpression {
lhs: Expression::AbsolutePath(vec!["level".to_string()]),
op: BinaryOperator::Gt,
rhs: Expression::Value(Value::Int(20))
}))
])),
vec![Error(
6..17,
"expected an operator between expressions".to_string()
)]
)
);
assert_eq!(
parse_filter(". .level > 20"),
(
Expression::Error(ErrorToken::List(vec![
Expression::Error(ErrorToken::PathStart),
Expression::BinaryExpression(Box::new(BinaryExpression {
lhs: Expression::AbsolutePath(vec!["level".to_string()]),
op: BinaryOperator::Gt,
rhs: Expression::Value(Value::Int(20))
}))
])),
vec![Error(
2..13,
"expected an operator between expressions".to_string()
)]
)
);
assert_eq!(
parse_filter(".time an .level > 20"),
(
Expression::Error(ErrorToken::List(vec![
Expression::AbsolutePath(vec!["time".to_string()]),
Expression::Error(ErrorToken::Identifier("an".to_string())),
Expression::BinaryExpression(Box::new(BinaryExpression {
lhs: Expression::AbsolutePath(vec!["level".to_string()]),
op: BinaryOperator::Gt,
rhs: Expression::Value(Value::Int(20))
}))
])),
vec![Error(6..8, "unexpected `an`".to_string()),]
)
);
assert_eq!(
parse_filter(".time after 10 .level > 20"),
(
Expression::Error(ErrorToken::List(vec![
Expression::BinaryExpression(Box::new(BinaryExpression {
lhs: Expression::AbsolutePath(vec!["time".to_string()]),
op: BinaryOperator::Gte,
rhs: Expression::Value(Value::Int(10))
})),
Expression::BinaryExpression(Box::new(BinaryExpression {
lhs: Expression::AbsolutePath(vec!["level".to_string()]),
op: BinaryOperator::Gt,
rhs: Expression::Value(Value::Int(20))
}))
])),
vec![Error(
15..26,
"expected an operator between expressions".to_string()
)]
)
);
assert_eq!(
parse_filter(".level === 20"),
(
Expression::Error(ErrorToken::List(vec![
Expression::BinaryExpression(Box::new(BinaryExpression {
lhs: Expression::AbsolutePath(vec!["level".to_string()]),
op: BinaryOperator::Eq,
rhs: Expression::Error(ErrorToken::Unexpected)
})),
Expression::Value(Value::Int(20)),
])),
vec![
Error(9..10, "unexpected `=`".to_string()),
Error(
11..13,
"expected an operator between expressions".to_string()
)
]
)
);
assert_eq!(
parse_filter("2023-02-29"),
(
Expression::Error(ErrorToken::List(vec![
Expression::Value(Value::Int(2023)),
Expression::Value(Value::Int(-2)),
Expression::Value(Value::Int(-29)),
])),
vec![Error(0..10, "Invalid date".to_string())]
)
);
}
}