use crate::item::Node;
use crate::parser::combinators::alt::{alt2, alt4};
use crate::parser::combinators::many::many0;
use crate::parser::combinators::map::map;
use crate::parser::combinators::opt::opt;
use crate::parser::combinators::pair::pair;
use crate::parser::combinators::tag::tag;
use crate::parser::combinators::tuple::{tuple2, tuple3};
use crate::parser::combinators::whitespace::xpwhitespace;
use crate::parser::xpath::nodes::{path_expr, union_expr};
use crate::parser::{ParseError, ParseInput, StaticState};
use crate::transform::{ArithmeticOperand, ArithmeticOperator, Transform};
use qualname::{NamespacePrefix, NamespaceUri};
pub(crate) fn range_expr<'a, N: Node + 'a, L>() -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
+ 'a,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(map(
pair(
additive_expr::<N, L>(),
opt(tuple2(
tuple3(xpwhitespace(), tag("to"), xpwhitespace()),
additive_expr::<N, L>(),
)),
),
|(v, o)| match o {
None => v,
Some((_, u)) => Transform::Range(Box::new(v), Box::new(u)),
},
))
}
fn additive_expr<'a, N: Node + 'a, L>() -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
+ 'a,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(map(
pair(
multiplicative_expr::<N, L>(),
many0(tuple2(
alt2(
map(
tuple3(
xpwhitespace(),
map(tag("+"), |_| ArithmeticOperator::Add),
xpwhitespace(),
),
|(_, x, _)| x,
),
map(
tuple3(
xpwhitespace(),
map(tag("-"), |_| ArithmeticOperator::Subtract),
xpwhitespace(),
),
|(_, x, _)| x,
),
),
multiplicative_expr::<N, L>(),
)),
),
|(mut a, b)| {
if b.is_empty() {
if a.len() == 1 {
let c: ArithmeticOperand<N> = a.pop().unwrap();
c.operand
} else {
Transform::Arithmetic(a)
}
} else {
let mut e: Vec<ArithmeticOperand<N>> = b
.iter()
.map(|(c, d)| ArithmeticOperand::new(*c, Transform::Arithmetic(d.clone())))
.collect();
a.append(&mut e);
Transform::Arithmetic(a)
}
},
))
}
fn multiplicative_expr<'a, N: Node + 'a, L>() -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Vec<ArithmeticOperand<N>>), ParseError>
+ 'a,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(map(
pair(
union_expr::<N, L>(),
many0(tuple2(
alt4(
tuple3(xpwhitespace(), map(tag("*"), |_| "*"), xpwhitespace()),
tuple3(xpwhitespace(), map(tag("div"), |_| "div"), xpwhitespace()),
tuple3(xpwhitespace(), map(tag("idiv"), |_| "idiv"), xpwhitespace()),
tuple3(xpwhitespace(), map(tag("mod"), |_| "mod"), xpwhitespace()),
),
union_expr::<N, L>(),
)),
),
|(a, b)| {
if b.is_empty() {
vec![ArithmeticOperand::new(ArithmeticOperator::Noop, a)]
} else {
let mut r: Vec<ArithmeticOperand<N>> = Vec::new();
r.push(ArithmeticOperand::new(ArithmeticOperator::Noop, a));
for ((_, c, _), d) in b {
r.push(ArithmeticOperand::new(ArithmeticOperator::from(c), d))
}
r
}
},
))
}
pub(crate) fn unary_expr<'a, N: Node + 'a, L>() -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
+ 'a,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(map(
pair(many0(alt2(tag("-"), tag("+"))), value_expr::<N, L>()),
|(u, v)| {
if u.is_empty() {
v
} else {
Transform::NotImplemented("unary_expr".to_string())
}
},
))
}
fn value_expr<'a, N: Node + 'a, L>() -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
+ 'a,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(map(
pair(
path_expr::<N, L>(),
many0(tuple2(tag("!"), path_expr::<N, L>())),
),
|(u, v)| {
if v.is_empty() {
u
} else {
Transform::NotImplemented("value_expr".to_string())
}
},
))
}