use crate::lexer::{lex, Tok};
use crate::types::*;
const SUPPORTED: &[&str] = &[
":STRIPS",
":NEGATION",
":EQUALITY",
":TYPING",
":CONDITIONAL-EFFECTS",
":NEGATIVE-PRECONDITIONS",
":DISJUNCTIVE-PRECONDITIONS",
":EXISTENTIAL-PRECONDITIONS",
":UNIVERSAL-PRECONDITIONS",
":QUANTIFIED-PRECONDITIONS",
":ADL",
":FLUENTS",
":NUMERIC-FLUENTS",
":ACTION-COSTS",
":PREFERENCES",
":CONSTRAINTS",
":GOAL-UTILITIES",
":DURATIVE-ACTIONS",
":DURATION-INEQUALITIES",
":TIMED-INITIAL-LITERALS",
":TIME",
];
const MAX_NEST_DEPTH: usize = 150;
struct P {
t: Vec<Tok>,
lines: Vec<u32>,
i: usize,
depth: usize,
}
impl P {
fn new(t: Vec<Tok>, lines: Vec<u32>) -> Self {
P {
t,
lines,
i: 0,
depth: 0,
}
}
fn push_depth(&mut self) -> Result<(), String> {
self.depth += 1;
if self.depth > MAX_NEST_DEPTH {
self.depth -= 1;
Err(format!(
"formula/expression nested deeper than {MAX_NEST_DEPTH}"
))
} else {
Ok(())
}
}
fn pop_depth(&mut self) {
self.depth -= 1;
}
fn line(&self) -> u32 {
self.lines
.get(self.i)
.or_else(|| self.lines.last())
.copied()
.unwrap_or(1)
}
fn peek(&self) -> Option<&Tok> {
self.t.get(self.i)
}
fn peek_at(&self, ahead: usize) -> Option<&Tok> {
self.t.get(self.i + ahead)
}
fn next(&mut self) -> Result<Tok, String> {
let t = self
.t
.get(self.i)
.cloned()
.ok_or_else(|| "unexpected end of input".to_string())?;
self.i += 1;
Ok(t)
}
fn expect_lparen(&mut self) -> Result<(), String> {
match self.next()? {
Tok::LParen => Ok(()),
other => Err(format!("expected '(', found {:?}", other)),
}
}
fn expect_rparen(&mut self) -> Result<(), String> {
match self.next()? {
Tok::RParen => Ok(()),
other => Err(format!("expected ')', found {:?}", other)),
}
}
fn at_rparen(&self) -> bool {
matches!(self.peek(), Some(Tok::RParen))
}
fn num(&mut self) -> Result<f64, String> {
match self.next()? {
Tok::Num(n) => Ok(n),
other => Err(format!("expected number, found {:?}", other)),
}
}
fn name(&mut self) -> Result<String, String> {
match self.next()? {
Tok::Name(s) => Ok(s),
other => Err(format!("expected name, found {:?}", other)),
}
}
fn expect_kw(&mut self, kw: &str) -> Result<(), String> {
let n = self.name()?;
if n == kw {
Ok(())
} else {
Err(format!("expected `{}`, found `{}`", kw, n))
}
}
fn skip_balanced(&mut self) -> Result<(), String> {
let mut depth = 1;
while depth > 0 {
match self.next()? {
Tok::LParen => depth += 1,
Tok::RParen => depth -= 1,
_ => {}
}
}
Ok(())
}
}
fn parse_typed_list(p: &mut P) -> Result<Vec<(String, String)>, String> {
let mut out = Vec::new();
let mut pending: Vec<String> = Vec::new();
while !p.at_rparen() {
match p.peek().cloned() {
Some(Tok::Dash) => {
p.next()?; let ty = match p.next()? {
Tok::Name(s) => s,
Tok::LParen => {
let _either = p.name()?; let first = p.name()?;
while !p.at_rparen() {
p.next()?;
}
p.expect_rparen()?;
first
}
other => return Err(format!("expected type, found {:?}", other)),
};
for nm in pending.drain(..) {
out.push((nm, ty.clone()));
}
}
Some(Tok::Name(s)) => {
p.next()?;
pending.push(s);
}
Some(Tok::Var(s)) => {
p.next()?;
pending.push(s);
}
other => return Err(format!("unexpected token in typed list: {:?}", other)),
}
}
for nm in pending.drain(..) {
out.push((nm, "OBJECT".to_string()));
}
Ok(out)
}
fn term_of(t: Tok) -> Result<Term, String> {
match t {
Tok::Var(s) => Ok(Term::Var(s)),
Tok::Name(s) => Ok(Term::Const(s)),
other => Err(format!("expected term, found {:?}", other)),
}
}
fn parse_expr(p: &mut P) -> Result<Expr, String> {
p.push_depth()?;
let r = parse_expr_inner(p);
p.pop_depth();
r
}
fn parse_expr_inner(p: &mut P) -> Result<Expr, String> {
match p.next()? {
Tok::Num(n) => Ok(Expr::Num(n)),
Tok::LParen => {
match p.peek().cloned() {
Some(Tok::Op(op)) => {
p.next()?;
if op == "+" || op == "*" {
let mut acc = parse_expr(p)?;
while !p.at_rparen() {
let b = parse_expr(p)?;
acc = if op == "+" {
Expr::Add(Box::new(acc), Box::new(b))
} else {
Expr::Mul(Box::new(acc), Box::new(b))
};
}
p.expect_rparen()?;
Ok(acc)
} else if op == "/" {
let a = parse_expr(p)?;
let b = parse_expr(p)?;
p.expect_rparen()?;
Ok(Expr::Div(Box::new(a), Box::new(b)))
} else {
Err(format!("unexpected operator `{}` in expression", op))
}
}
Some(Tok::Dash) => {
p.next()?;
let a = parse_expr(p)?;
if p.at_rparen() {
p.expect_rparen()?;
Ok(Expr::Neg(Box::new(a)))
} else {
let b = parse_expr(p)?;
p.expect_rparen()?;
Ok(Expr::Sub(Box::new(a), Box::new(b)))
}
}
Some(Tok::Name(_)) => {
let head = p.name()?;
let mut args = Vec::new();
while !p.at_rparen() {
args.push(term_of(p.next()?)?);
}
p.expect_rparen()?;
Ok(Expr::Fluent(head, args))
}
other => Err(format!("unexpected token in expression: {:?}", other)),
}
}
other => Err(format!("expected expression, found {:?}", other)),
}
}
fn comp_of(op: &str) -> Option<CompOp> {
match op {
"<" => Some(CompOp::Lt),
"<=" => Some(CompOp::Le),
"=" => Some(CompOp::Eq),
">=" => Some(CompOp::Ge),
">" => Some(CompOp::Gt),
_ => None,
}
}
fn parse_formula(p: &mut P) -> Result<Formula, String> {
p.push_depth()?;
let r = parse_formula_inner(p);
p.pop_depth();
r
}
fn parse_formula_inner(p: &mut P) -> Result<Formula, String> {
p.expect_lparen()?;
match p.peek().cloned() {
Some(Tok::Op(op)) => {
p.next()?;
if op == "=" && matches!(p.peek(), Some(Tok::Var(_)) | Some(Tok::Name(_))) {
let a = term_of(p.next()?)?;
let b = term_of(p.next()?)?;
p.expect_rparen()?;
return Ok(Formula::Eq(a, b));
}
let c =
comp_of(&op).ok_or_else(|| format!("unexpected operator `{}` in formula", op))?;
let a = parse_expr(p)?;
let b = parse_expr(p)?;
p.expect_rparen()?;
Ok(Formula::Comp(c, a, b))
}
Some(Tok::Name(head)) => {
p.next()?;
match head.as_str() {
"AND" => {
let mut v = Vec::new();
while !p.at_rparen() {
v.push(parse_formula(p)?);
}
p.expect_rparen()?;
Ok(Formula::And(v))
}
"OR" => {
let mut v = Vec::new();
while !p.at_rparen() {
v.push(parse_formula(p)?);
}
p.expect_rparen()?;
Ok(Formula::Or(v))
}
"NOT" => {
let f = parse_formula(p)?;
p.expect_rparen()?;
Ok(Formula::Not(Box::new(f)))
}
"IMPLY" => {
let a = parse_formula(p)?;
let b = parse_formula(p)?;
p.expect_rparen()?;
Ok(Formula::Or(vec![Formula::Not(Box::new(a)), b]))
}
"FORALL" | "EXISTS" => {
p.expect_lparen()?;
let vars = parse_typed_list(p)?;
p.expect_rparen()?;
let inner = parse_formula(p)?;
p.expect_rparen()?;
if head == "FORALL" {
Ok(Formula::Forall(vars, Box::new(inner)))
} else {
Ok(Formula::Exists(vars, Box::new(inner)))
}
}
"PREFERENCE" => {
let name = if matches!(p.peek(), Some(Tok::Name(_))) {
Some(p.name()?)
} else {
None
};
let f = parse_formula(p)?;
p.expect_rparen()?;
Ok(Formula::Pref(name, Box::new(f)))
}
_ => {
let mut args = Vec::new();
while !p.at_rparen() {
args.push(term_of(p.next()?)?);
}
p.expect_rparen()?;
Ok(Formula::Atom(head, args))
}
}
}
Some(Tok::RParen) => {
p.expect_rparen()?;
Ok(Formula::True)
}
other => Err(format!("unexpected token in formula: {:?}", other)),
}
}
fn parse_effect(p: &mut P) -> Result<Effect, String> {
p.push_depth()?;
let r = parse_effect_inner(p);
p.pop_depth();
r
}
fn parse_effect_inner(p: &mut P) -> Result<Effect, String> {
p.expect_lparen()?;
match p.peek().cloned() {
Some(Tok::Name(head)) => {
p.next()?;
match head.as_str() {
"AND" => {
let mut v = Vec::new();
while !p.at_rparen() {
v.push(parse_effect(p)?);
}
p.expect_rparen()?;
Ok(Effect::And(v))
}
"NOT" => {
p.expect_lparen()?;
let pred = p.name()?;
let mut args = Vec::new();
while !p.at_rparen() {
args.push(term_of(p.next()?)?);
}
p.expect_rparen()?; p.expect_rparen()?; Ok(Effect::Del(pred, args))
}
"INCREASE" | "DECREASE" | "ASSIGN" | "SCALE-UP" | "SCALE-DOWN" => {
let op = match head.as_str() {
"INCREASE" => AssignOp::Increase,
"DECREASE" => AssignOp::Decrease,
"ASSIGN" => AssignOp::Assign,
"SCALE-UP" => AssignOp::ScaleUp,
_ => AssignOp::ScaleDown,
};
p.expect_lparen()?;
let fname = p.name()?;
let mut fargs = Vec::new();
while !p.at_rparen() {
fargs.push(term_of(p.next()?)?);
}
p.expect_rparen()?;
let val = parse_expr(p)?;
p.expect_rparen()?;
Ok(Effect::Num(op, fname, fargs, val))
}
"WHEN" => {
let cond = parse_formula(p)?;
let eff = parse_effect(p)?;
p.expect_rparen()?;
Ok(Effect::When(cond, Box::new(eff)))
}
"FORALL" => {
p.expect_lparen()?;
let vars = parse_typed_list(p)?;
p.expect_rparen()?;
let eff = parse_effect(p)?;
p.expect_rparen()?;
Ok(Effect::Forall(vars, Box::new(eff)))
}
_ => {
let mut args = Vec::new();
while !p.at_rparen() {
args.push(term_of(p.next()?)?);
}
p.expect_rparen()?;
Ok(Effect::Add(head, args))
}
}
}
other => Err(format!("unexpected token in effect: {:?}", other)),
}
}
fn parse_predicates(p: &mut P) -> Result<Vec<(String, Vec<String>)>, String> {
let mut out = Vec::new();
while !p.at_rparen() {
p.expect_lparen()?;
let name = p.name()?;
let params = parse_typed_list(p)?;
p.expect_rparen()?;
out.push((name, params.into_iter().map(|(_, t)| t).collect()));
}
p.expect_rparen()?;
Ok(out)
}
fn parse_functions(p: &mut P) -> Result<Vec<(String, Vec<String>)>, String> {
let mut out = Vec::new();
while !p.at_rparen() {
p.expect_lparen()?;
let name = p.name()?;
let params = parse_typed_list(p)?;
p.expect_rparen()?;
out.push((name, params.into_iter().map(|(_, t)| t).collect()));
if matches!(p.peek(), Some(Tok::Dash)) {
p.next()?; let _ = p.name()?; }
}
p.expect_rparen()?;
Ok(out)
}
fn parse_action(p: &mut P) -> Result<Action, String> {
let name = p.name()?;
let mut params = Vec::new();
let mut precond = Formula::True;
let mut effect = Effect::And(vec![]);
while !p.at_rparen() {
let kw = p.name()?;
match kw.as_str() {
":PARAMETERS" => {
p.expect_lparen()?;
params = parse_typed_list(p)?;
p.expect_rparen()?;
}
":PRECONDITION" => {
precond = parse_formula(p)?;
}
":EFFECT" => {
effect = parse_effect(p)?;
}
other => return Err(format!("unknown action keyword `{}`", other)),
}
}
p.expect_rparen()?;
Ok(Action {
name,
params,
precond,
effect,
monitored: false,
})
}
fn parse_durative_action(p: &mut P) -> Result<DurativeAction, String> {
let name = p.name()?;
let mut params = Vec::new();
let mut duration = Duration::fixed(Expr::Num(0.0));
let mut conditions = Vec::new();
let mut effects = Vec::new();
while !p.at_rparen() {
let kw = p.name()?;
match kw.as_str() {
":PARAMETERS" => {
p.expect_lparen()?;
params = parse_typed_list(p)?;
p.expect_rparen()?;
}
":DURATION" => duration = parse_duration(p)?,
":CONDITION" => conditions = parse_timed_conditions(p)?,
":EFFECT" => effects = parse_timed_effects(p)?,
other => return Err(format!("unknown durative-action keyword `{}`", other)),
}
}
p.expect_rparen()?;
Ok(DurativeAction {
name,
params,
duration,
conditions,
effects,
})
}
fn parse_duration(p: &mut P) -> Result<Duration, String> {
p.expect_lparen()?;
if matches!(p.peek(), Some(Tok::Name(n)) if n.eq_ignore_ascii_case("and")) {
p.next()?; let mut min = None;
let mut max = None;
while !p.at_rparen() {
let (lo, hi) = parse_duration_atom(p)?;
min = min.or(lo);
max = max.or(hi);
}
p.expect_rparen()?;
return Ok(Duration { min, max });
}
let (lo, hi) = parse_duration_inner(p)?;
p.expect_rparen()?;
Ok(Duration { min: lo, max: hi })
}
fn parse_duration_atom(p: &mut P) -> Result<(Option<Expr>, Option<Expr>), String> {
p.expect_lparen()?;
let r = parse_duration_inner(p)?;
p.expect_rparen()?;
Ok(r)
}
fn parse_duration_inner(p: &mut P) -> Result<(Option<Expr>, Option<Expr>), String> {
let op = match p.next()? {
Tok::Op(s) => s,
other => {
return Err(format!(
"expected =, >=, or <= in :duration, found {:?}",
other
))
}
};
match p.next()? {
Tok::Var(_) => {}
other => {
return Err(format!(
"expected ?duration in :duration, found {:?}",
other
))
}
}
let e = parse_expr(p)?;
match op.as_str() {
"=" => Ok((Some(e.clone()), Some(e))),
">=" => Ok((Some(e), None)),
"<=" => Ok((None, Some(e))),
other => Err(format!(
"unsupported :duration operator `{}` (expected =, >=, or <=)",
other
)),
}
}
fn timespec_from(p: &mut P, h: &str) -> Result<TimeSpec, String> {
match h {
"AT" => match p.name()?.as_str() {
"START" => Ok(TimeSpec::Start),
"END" => Ok(TimeSpec::End),
x => Err(format!("expected start/end after 'at', found `{}`", x)),
},
"OVER" => match p.name()?.as_str() {
"ALL" => Ok(TimeSpec::All),
x => Err(format!("expected 'all' after 'over', found `{}`", x)),
},
x => Err(format!(
"expected at/over in durative condition, found `{}`",
x
)),
}
}
fn parse_timed_conditions(p: &mut P) -> Result<Vec<(TimeSpec, Formula)>, String> {
p.expect_lparen()?;
if p.at_rparen() {
p.next()?; return Ok(Vec::new());
}
let h = p.name()?;
if h == "AND" {
let mut v = Vec::new();
while !p.at_rparen() {
p.expect_lparen()?;
let hh = p.name()?;
let ts = timespec_from(p, &hh)?;
let f = parse_formula(p)?;
p.expect_rparen()?;
v.push((ts, f));
}
p.expect_rparen()?;
Ok(v)
} else {
let ts = timespec_from(p, &h)?;
let f = parse_formula(p)?;
p.expect_rparen()?;
Ok(vec![(ts, f)])
}
}
fn parse_timed_effects(p: &mut P) -> Result<Vec<(TimeSpec, Effect)>, String> {
p.expect_lparen()?;
if p.at_rparen() {
p.next()?; return Ok(Vec::new());
}
let h = p.name()?;
if h == "AND" {
let mut v = Vec::new();
while !p.at_rparen() {
p.expect_lparen()?;
let hh = p.name()?;
let ts = timespec_from(p, &hh)?;
let e = parse_effect(p)?;
p.expect_rparen()?;
v.push((ts, e));
}
p.expect_rparen()?;
Ok(v)
} else {
let ts = timespec_from(p, &h)?;
let e = parse_effect(p)?;
p.expect_rparen()?;
Ok(vec![(ts, e)])
}
}
fn parse_constraint(p: &mut P) -> Result<Constraint, String> {
p.expect_lparen()?;
let head = p.name()?;
let c = match head.as_str() {
"AND" => {
let mut v = Vec::new();
while !p.at_rparen() {
v.push(parse_constraint(p)?);
}
Constraint::And(v)
}
"FORALL" => {
p.expect_lparen()?;
let vars = parse_typed_list(p)?;
p.expect_rparen()?;
Constraint::Forall(vars, Box::new(parse_constraint(p)?))
}
"PREFERENCE" => {
let name = if matches!(p.peek(), Some(Tok::Name(_))) {
Some(p.name()?)
} else {
None
};
Constraint::Pref(name, Box::new(parse_constraint(p)?))
}
"ALWAYS" => Constraint::Always(parse_formula(p)?),
"SOMETIME" => Constraint::Sometime(parse_formula(p)?),
"AT-MOST-ONCE" => Constraint::AtMostOnce(parse_formula(p)?),
"SOMETIME-AFTER" => {
let a = parse_formula(p)?;
Constraint::SometimeAfter(a, parse_formula(p)?)
}
"SOMETIME-BEFORE" => {
let a = parse_formula(p)?;
Constraint::SometimeBefore(a, parse_formula(p)?)
}
"WITHIN" => {
let n = p.num()?;
Constraint::Within(n, parse_formula(p)?)
}
"ALWAYS-WITHIN" => {
let n = p.num()?;
let a = parse_formula(p)?;
Constraint::AlwaysWithin(n, a, parse_formula(p)?)
}
"HOLD-DURING" => {
let n1 = p.num()?;
let n2 = p.num()?;
Constraint::HoldDuring(n1, n2, parse_formula(p)?)
}
"HOLD-AFTER" => {
let n = p.num()?;
Constraint::HoldAfter(n, parse_formula(p)?)
}
"AT" => {
let kw = p.name()?;
if kw != "END" {
return Err(format!("expected 'end' in (at end ...), found `{}`", kw));
}
Constraint::AtEnd(parse_formula(p)?)
}
other => return Err(format!("unsupported constraint operator `{}`", other)),
};
p.expect_rparen()?;
Ok(c)
}
pub fn parse_domain(src: &str) -> Result<Domain, ParseError> {
let (toks, lines) = lex(src)?;
let mut p = P::new(toks, lines);
domain_inner(&mut p).map_err(|m| ParseError::new(p.line(), m))
}
fn domain_inner(p: &mut P) -> Result<Domain, String> {
p.expect_lparen()?;
p.expect_kw("DEFINE")?;
p.expect_lparen()?;
p.expect_kw("DOMAIN")?;
let name = p.name()?;
p.expect_rparen()?;
let mut d = Domain {
name,
requirements: Vec::new(),
types: Vec::new(),
type_parent: Vec::new(),
constants: Vec::new(),
predicates: Vec::new(),
functions: Vec::new(),
actions: Vec::new(),
durative_actions: Vec::new(),
constraints: Vec::new(),
derived: Vec::new(),
monitors: Vec::new(),
};
while !p.at_rparen() {
p.expect_lparen()?;
let section = p.name()?;
match section.as_str() {
":REQUIREMENTS" => {
while !p.at_rparen() {
let r = p.name()?;
if !SUPPORTED.contains(&r.as_str()) {
return Err(format!(
"requirement {} not supported by this FF version",
r
));
}
d.requirements.push(r);
}
p.expect_rparen()?;
}
":TYPES" => {
let tl = parse_typed_list(p)?;
for (name, parent) in tl {
d.types.push(name.clone());
if name != parent {
d.type_parent.push((name, parent));
}
}
let tp: std::collections::HashMap<&str, &str> = d
.type_parent
.iter()
.map(|(a, b)| (a.as_str(), b.as_str()))
.collect();
for start in tp.keys() {
let (mut cur, mut hops) = (*start, 0usize);
while let Some(next) = tp.get(cur) {
cur = next;
hops += 1;
if hops > tp.len() {
return Err(format!(
"cyclic (:types ...) hierarchy involving `{start}`"
));
}
}
}
p.expect_rparen()?;
}
":CONSTANTS" => {
d.constants = parse_typed_list(p)?;
p.expect_rparen()?;
}
":PREDICATES" => {
d.predicates = parse_predicates(p)?;
}
":FUNCTIONS" => {
d.functions = parse_functions(p)?;
}
":ACTION" => {
d.actions.push(parse_action(p)?);
}
":DURATIVE-ACTION" => {
d.durative_actions.push(parse_durative_action(p)?);
}
":CONSTRAINTS" => {
if !p.at_rparen() {
d.constraints.push(parse_constraint(p)?);
}
p.expect_rparen()?;
}
":DERIVED" => {
p.expect_lparen()?;
let head = p.name()?;
let params = parse_typed_list(p)?;
p.expect_rparen()?; let body = parse_formula(p)?;
p.expect_rparen()?; d.derived.push(DerivedRule { head, params, body });
}
_ => {
p.skip_balanced()?;
}
}
}
p.expect_rparen()?;
Ok(d)
}
fn parse_init_elt(
p: &mut P,
atoms: &mut Vec<(String, Vec<String>)>,
fluents: &mut Vec<((String, Vec<String>), f64)>,
til: &mut Vec<TimedLiteral>,
) -> Result<(), String> {
p.expect_lparen()?;
if matches!(p.peek(), Some(Tok::Name(n)) if n.eq_ignore_ascii_case("at"))
&& matches!(p.peek_at(1), Some(Tok::Num(_)))
{
p.next()?; let time = match p.next()? {
Tok::Num(n) => n,
other => {
return Err(format!(
"expected a time in a timed initial literal, found {:?}",
other
))
}
};
p.expect_lparen()?;
let add = if matches!(p.peek(), Some(Tok::Name(n)) if n.eq_ignore_ascii_case("not")) {
p.next()?; p.expect_lparen()?;
false
} else {
true
};
let pred = p.name()?;
let mut args = Vec::new();
while !p.at_rparen() {
args.push(name_or_const(p.next()?)?);
}
p.expect_rparen()?; if !add {
p.expect_rparen()?; }
p.expect_rparen()?; til.push(TimedLiteral {
time,
add,
pred,
args,
});
return Ok(());
}
match p.peek().cloned() {
Some(Tok::Op(op)) if op == "=" => {
p.next()?;
p.expect_lparen()?;
let fname = p.name()?;
let mut fargs = Vec::new();
while !p.at_rparen() {
fargs.push(name_or_const(p.next()?)?);
}
p.expect_rparen()?;
let v = match p.next()? {
Tok::Num(n) => n,
other => return Err(format!("expected number in init `=`, found {:?}", other)),
};
p.expect_rparen()?;
fluents.push(((fname, fargs), v));
Ok(())
}
Some(Tok::Name(_)) => {
let pred = p.name()?;
let mut args = Vec::new();
while !p.at_rparen() {
args.push(name_or_const(p.next()?)?);
}
p.expect_rparen()?;
atoms.push((pred, args));
Ok(())
}
other => Err(format!("unexpected token in :init: {:?}", other)),
}
}
fn name_or_const(t: Tok) -> Result<String, String> {
match t {
Tok::Name(s) => Ok(s),
other => Err(format!("expected object name, found {:?}", other)),
}
}
pub fn parse_problem(src: &str) -> Result<Problem, ParseError> {
let (toks, lines) = lex(src)?;
let mut p = P::new(toks, lines);
problem_inner(&mut p).map_err(|m| ParseError::new(p.line(), m))
}
fn problem_inner(p: &mut P) -> Result<Problem, String> {
p.expect_lparen()?;
p.expect_kw("DEFINE")?;
p.expect_lparen()?;
p.expect_kw("PROBLEM")?;
let name = p.name()?;
p.expect_rparen()?;
let mut prob = Problem {
name,
domain_name: String::new(),
objects: Vec::new(),
init_atoms: Vec::new(),
init_fluents: Vec::new(),
til: Vec::new(),
goal: Formula::True,
constraints: Vec::new(),
metric: None,
};
while !p.at_rparen() {
p.expect_lparen()?;
let section = p.name()?;
match section.as_str() {
":DOMAIN" => {
prob.domain_name = p.name()?;
p.expect_rparen()?;
}
":REQUIREMENTS" => {
p.skip_balanced()?;
}
":OBJECTS" => {
prob.objects = parse_typed_list(p)?;
p.expect_rparen()?;
}
":INIT" => {
while !p.at_rparen() {
parse_init_elt(
p,
&mut prob.init_atoms,
&mut prob.init_fluents,
&mut prob.til,
)?;
}
p.expect_rparen()?;
}
":GOAL" => {
prob.goal = parse_formula(p)?;
p.expect_rparen()?;
}
":CONSTRAINTS" => {
if !p.at_rparen() {
prob.constraints.push(parse_constraint(p)?);
}
p.expect_rparen()?;
}
":METRIC" => {
let dir = match p.name()?.as_str() {
"MINIMIZE" => MetricDir::Minimize,
"MAXIMIZE" => MetricDir::Maximize,
other => return Err(format!("unknown metric direction `{}`", other)),
};
let e = parse_expr(p)?;
prob.metric = Some((dir, e));
p.expect_rparen()?;
}
_ => {
p.skip_balanced()?;
}
}
}
p.expect_rparen()?;
Ok(prob)
}