use crate::parsers::{
parens, parse_gd, parse_number, parse_variable, prefix_expr, space_separated_list0, typed_list,
ParseResult, Span,
};
use crate::types::{Con2GD, ConGD};
use nom::branch::alt;
use nom::character::complete::multispace1;
use nom::combinator::map;
use nom::sequence::{preceded, tuple};
pub fn parse_con_gd<'a, T: Into<Span<'a>>>(input: T) -> ParseResult<'a, ConGD> {
let and = map(
prefix_expr("and", space_separated_list0(parse_con_gd)),
ConGD::new_and,
);
let forall = map(
prefix_expr(
"forall",
tuple((
parens(typed_list(parse_variable)),
preceded(multispace1, parse_con_gd),
)),
),
|(vars, gd)| ConGD::new_forall(vars, gd),
);
let at_end = map(prefix_expr("at end", parse_gd), ConGD::new_at_end);
let always = map(prefix_expr("always", parse_con2_gd), ConGD::new_always);
let sometime = map(prefix_expr("sometime", parse_con2_gd), ConGD::new_sometime);
let within = map(
prefix_expr(
"within",
tuple((parse_number, preceded(multispace1, parse_con2_gd))),
),
|(num, gd)| ConGD::new_within(num, gd),
);
let at_most_once = map(
prefix_expr("at-most-once", parse_con2_gd),
ConGD::new_at_most_once,
);
let sometime_after = map(
prefix_expr(
"sometime-after",
tuple((parse_con2_gd, preceded(multispace1, parse_con2_gd))),
),
|(a, b)| ConGD::new_sometime_after(a, b),
);
let sometime_before = map(
prefix_expr(
"sometime-before",
tuple((parse_con2_gd, preceded(multispace1, parse_con2_gd))),
),
|(a, b)| ConGD::new_sometime_before(a, b),
);
let always_within = map(
prefix_expr(
"always-within",
tuple((
parse_number,
preceded(multispace1, parse_con2_gd),
preceded(multispace1, parse_con2_gd),
)),
),
|(num, a, b)| ConGD::new_always_within(num, a, b),
);
let hold_during = map(
prefix_expr(
"hold-during",
tuple((
parse_number,
preceded(multispace1, parse_number),
preceded(multispace1, parse_con2_gd),
)),
),
|(t0, t1, gd)| ConGD::new_hold_during(t0, t1, gd),
);
let hold_after = map(
prefix_expr(
"hold-after",
tuple((parse_number, preceded(multispace1, parse_con2_gd))),
),
|(time, gd)| ConGD::new_hold_after(time, gd),
);
alt((
and,
forall,
at_end,
always,
sometime,
within,
at_most_once,
sometime_after,
sometime_before,
always_within,
hold_during,
hold_after,
))(input.into())
}
fn parse_con2_gd<'a, T: Into<Span<'a>>>(input: T) -> ParseResult<'a, Con2GD> {
let gd = map(parse_gd, Con2GD::new_goal);
let con_gd = map(parse_con_gd, Con2GD::new_nested);
alt((gd, con_gd))(input.into())
}
impl crate::parsers::Parser for ConGD {
type Item = ConGD;
fn parse<'a, S: Into<Span<'a>>>(input: S) -> ParseResult<'a, Self::Item> {
parse_con_gd(input)
}
}
impl crate::parsers::Parser for Con2GD {
type Item = Con2GD;
fn parse<'a, S: Into<Span<'a>>>(input: S) -> ParseResult<'a, Self::Item> {
parse_con2_gd(input)
}
}
#[cfg(test)]
mod tests {
use crate::parsers::preamble::*;
use crate::{AtomicFormula, Con2GD, ConGD, GoalDefinition, Number, Term};
#[test]
fn test_parse() {
let gd = GoalDefinition::new_atomic_formula(AtomicFormula::new_equality(
Term::Name("x".into()),
Term::Name("y".into()),
));
let input = "(within 10 (at-most-once (= x y)))";
assert!(ConGD::parse(input).is_value(ConGD::new_within(
Number::from(10),
Con2GD::new_nested(ConGD::new_at_most_once(Con2GD::new_goal(gd.clone())))
)));
let input = "(within 10 (at-most-once (= x y)))";
assert!(
Con2GD::parse(input).is_value(Con2GD::Nested(Box::new(ConGD::new_within(
Number::from(10),
Con2GD::new_nested(ConGD::new_at_most_once(Con2GD::new_goal(gd)))
))))
);
}
}