use super::{
super::{combinator::*, identifier::*},
aggregate_initializer::*,
operator::*,
primary::*,
};
use crate::ast::*;
fn create_tree(mut head: Expression, tails: Vec<(BinaryOperator, Expression)>) -> Expression {
for (op, expr) in tails {
head = Expression::Binary {
op,
arg1: Box::new(head),
arg2: Box::new(expr),
}
}
head
}
pub fn simple_expression(input: &str) -> ParseResult<Expression> {
tuple((term, many0(tuple((add_like_op, term)))))
.map(|(head, tails)| create_tree(head, tails))
.parse(input)
}
pub fn term(input: &str) -> ParseResult<Expression> {
tuple((factor, many0(tuple((multiplication_like_op, factor)))))
.map(|(head, tails)| create_tree(head, tails))
.parse(input)
}
pub fn factor(input: &str) -> ParseResult<Expression> {
tuple((simple_factor, opt(tuple((power_op, simple_factor)))))
.map(|(arg1, opt)| {
if let Some((op, arg2)) = opt {
Expression::Binary {
op,
arg1: Box::new(arg1),
arg2: Box::new(arg2),
}
} else {
arg1
}
})
.parse(input)
}
pub fn simple_factor(input: &str) -> ParseResult<Expression> {
let paren_expr = tuple((char('('), expression, char(')'))).map(|(_open, e, _close)| e);
let unary = tuple((opt(unary_op), alt((paren_expr, primary)))).map(|(opt, expr)| {
if let Some(op) = opt {
Expression::Unary {
op,
arg: Box::new(expr),
}
} else {
expr
}
});
alt((
unary,
aggregate_initializer,
entity_constructor,
interval,
query_expression,
enumeration_reference, ))
.parse(input)
}
pub fn expression(input: &str) -> ParseResult<Expression> {
tuple((
simple_expression,
opt(tuple((rel_op_extended, simple_expression))),
))
.map(|(lhs, opt)| {
if let Some((op, rhs)) = opt {
Expression::Relation {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
}
} else {
lhs
}
})
.parse(input)
}
pub fn enumeration_reference(input: &str) -> ParseResult<Expression> {
tuple((opt(tuple((type_ref, char('.')))), enumeration_ref))
.map(|(opt, enum_ref)| Expression::EnumerationReference {
ty: opt.map(|(ty, _comma)| ty),
enum_ref,
})
.parse(input)
}
pub fn interval(input: &str) -> ParseResult<Expression> {
tuple((
char('{'),
interval_low,
interval_op,
interval_item,
interval_op,
interval_high,
char('}'),
))
.map(
|(_open, low, op_low, item, op_high, high, _close)| Expression::Interval {
op_low,
op_high,
low: Box::new(low),
item: Box::new(item),
high: Box::new(high),
},
)
.parse(input)
}
pub fn interval_high(input: &str) -> ParseResult<Expression> {
simple_expression(input)
}
pub fn interval_item(input: &str) -> ParseResult<Expression> {
simple_expression(input)
}
pub fn interval_low(input: &str) -> ParseResult<Expression> {
simple_expression(input)
}
pub fn aggregate_source(input: &str) -> ParseResult<Expression> {
simple_expression(input)
}
pub fn logical_expression(input: &str) -> ParseResult<Expression> {
expression(input)
}
pub fn query_expression(input: &str) -> ParseResult<Expression> {
tuple((
tag("QUERY"),
char('('),
variable_id,
tag("<*"),
aggregate_source,
char('|'),
logical_expression,
char(')'),
))
.map(
|(_start, _open, variable, _star, source, _bar, expr, _close)| Expression::Query {
variable,
source: Box::new(source),
expr: Box::new(expr),
},
)
.parse(input)
}
pub fn entity_constructor(input: &str) -> ParseResult<Expression> {
tuple((
entity_ref,
char('('),
opt(comma_separated(expression)),
char(')'),
))
.map(
|(name, _open, values, _close)| Expression::EntityConstructor {
name,
values: values.unwrap_or_default(),
},
)
.parse(input)
}
#[cfg(test)]
mod tests {
use super::*;
use nom::Finish;
#[test]
fn unary() {
let (res, (expr, _remarks)) = super::expression("-1.0").finish().unwrap();
assert_eq!(res, "");
assert_eq!(
expr,
Expression::Unary {
op: UnaryOperator::Minus,
arg: Box::new(Expression::Literal(Literal::Real(1.0))),
}
);
}
#[test]
fn interval() {
let (res, (expr, _remarks)) = super::interval("{1 <= date.day_component <= 31}")
.finish()
.unwrap();
assert_eq!(res, "");
dbg!(expr);
}
#[test]
fn binary() {
let (res, (expr, _remarks)) = super::expression("1.0 + 2.0").finish().unwrap();
assert_eq!(res, "");
assert_eq!(
expr,
Expression::Binary {
op: BinaryOperator::Add,
arg1: Box::new(Expression::Literal(Literal::Real(1.0))),
arg2: Box::new(Expression::Literal(Literal::Real(2.0))),
}
);
}
#[test]
fn binary3() {
let (res, (expr, _remarks)) = super::expression("1.0 + 2.0 - 3.0").finish().unwrap();
assert_eq!(res, "");
assert_eq!(
expr,
Expression::Binary {
op: BinaryOperator::Sub,
arg1: Box::new(Expression::Binary {
op: BinaryOperator::Add,
arg1: Box::new(Expression::Literal(Literal::Real(1.0))),
arg2: Box::new(Expression::Literal(Literal::Real(2.0))),
}),
arg2: Box::new(Expression::Literal(Literal::Real(3.0)))
}
);
}
#[test]
fn relation() {
let (res, (expr, _remarks)) = super::expression("1 <= 2").finish().unwrap();
assert_eq!(res, "");
assert_eq!(expr, Expression::real(1.0).leq(Expression::real(2.0)));
}
#[test]
fn relation_self() {
let (res, (expr, _remarks)) = super::expression("1 <= SELF").finish().unwrap();
assert_eq!(res, "");
assert_eq!(expr, Expression::real(1.0).leq(Expression::self_()));
}
#[test]
fn binary_relation() {
let (res, (expr, _remarks)) = super::expression("(1 <= SELF) AND (SELF <= 12)")
.finish()
.unwrap();
assert_eq!(res, "");
assert_eq!(
expr,
Expression::real(1.0)
.leq(Expression::self_())
.and(Expression::self_().leq(Expression::real(12.0)))
);
}
#[test]
fn literal() {
let (res, (expr, _remarks)) = super::expression("1.0").finish().unwrap();
assert_eq!(res, "");
assert_eq!(expr, Expression::real(1.0));
}
#[test]
fn qualifiable_factor() {
let (res, (expr, _remarks)) = super::expression(r"x\group.attr").finish().unwrap();
assert_eq!(res, "");
assert_eq!(
expr,
Expression::QualifiableFactor {
factor: QualifiableFactor::Reference("x".to_string()),
qualifiers: vec![
Qualifier::Group("group".to_string()),
Qualifier::Attribute("attr".to_string())
]
}
);
}
#[test]
fn entity_constructor() {
let (residual, (ctor, _remarks)) = super::entity_constructor("point(0.0, 0.0, 0.0)")
.finish()
.unwrap();
assert_eq!(residual, "");
if let super::Expression::EntityConstructor { name, values } = ctor {
assert_eq!(name, "point");
assert_eq!(values.len(), 3);
} else {
panic!("Must be entity constructor")
}
}
#[test]
fn call_attr() {
let (residual, (expr, _remarks)) = super::expression("f(a, b).attr").finish().unwrap();
dbg!(expr);
assert_eq!(residual, "");
}
}