use nom::combinator::opt;
use nom::multi::{many0, many1};
use nom::sequence::{delimited, pair, preceded, tuple};
use nom::IResult;
use serde::{Deserialize, Serialize};
use crate::domain::expression::Expression;
use crate::domain::typing::Type;
use crate::error::ParserError;
use crate::lexer::{Token, TokenStream};
use crate::tokens::id;
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Object {
pub name: String,
#[serde(rename = "type")]
pub type_: Type,
}
impl Object {
pub fn to_pddl(&self) -> String {
format!("{} - {}", self.name, self.type_.to_pddl())
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Problem {
pub name: String,
pub domain: String,
#[serde(default)]
pub objects: Vec<Object>,
#[serde(default)]
pub init: Vec<Expression>,
pub goal: Expression,
}
impl Problem {
pub fn parse(input: TokenStream) -> Result<Self, ParserError> {
let (output, problem) = delimited(
Token::OpenParen,
preceded(Token::Define, Problem::parse_problem),
Token::CloseParen,
)(input)?;
if !output.is_empty() {
return Err(ParserError::ExpectedEndOfInput);
}
Ok(problem)
}
fn parse_problem(input: TokenStream) -> IResult<TokenStream, Problem, ParserError> {
let (output, (name, domain, objects, init, goal)) = tuple((
Problem::parse_name,
Problem::parse_domain,
Problem::parse_objects,
Problem::parse_init,
Problem::parse_goal,
))(input)?;
Ok((
output,
Problem {
name,
domain,
objects,
init,
goal,
},
))
}
fn parse_name(input: TokenStream) -> IResult<TokenStream, String, ParserError> {
let (output, name) = delimited(Token::OpenParen, preceded(Token::Problem, id), Token::CloseParen)(input)?;
Ok((output, name))
}
fn parse_domain(input: TokenStream) -> IResult<TokenStream, String, ParserError> {
let (output, domain) =
delimited(Token::OpenParen, preceded(Token::ProblemDomain, id), Token::CloseParen)(input)?;
Ok((output, domain))
}
fn parse_objects(input: TokenStream) -> IResult<TokenStream, Vec<Object>, ParserError> {
let (output, objects) = delimited(
Token::OpenParen,
preceded(
Token::Objects,
many0(pair(many1(id), opt(preceded(Token::Dash, Type::parse_type)))),
),
Token::CloseParen,
)(input)?;
let objects = objects
.into_iter()
.flat_map(move |(names, type_)| {
names
.into_iter()
.map(|name| Object {
name,
type_: type_.clone().unwrap_or_default(),
})
.collect::<Vec<_>>()
})
.collect();
Ok((output, objects))
}
fn parse_init(input: TokenStream) -> IResult<TokenStream, Vec<Expression>, ParserError> {
log::debug!("BEGIN > parse_init {:?}", input.span());
let (output, init) = delimited(
Token::OpenParen,
preceded(Token::Init, many0(Expression::parse_expression)),
Token::CloseParen,
)(input)?;
log::debug!("END < parse_init {:?}", output.span());
Ok((output, init))
}
fn parse_goal(input: TokenStream) -> IResult<TokenStream, Expression, ParserError> {
let (output, goal) = delimited(
Token::OpenParen,
preceded(Token::Goal, Expression::parse_expression),
Token::CloseParen,
)(input)?;
Ok((output, goal))
}
pub fn to_pddl(&self) -> String {
let mut pddl = String::new();
pddl.push_str(&format!("(define (problem {})\n", self.name));
pddl.push_str(&format!("(:domain {})\n", self.domain));
pddl.push_str(&format!(
"(:objects\n{}\n)\n",
self.objects.iter().map(Object::to_pddl).collect::<Vec<_>>().join("\n")
));
pddl.push_str(&format!(
"(:init\n{}\n)\n",
self.init.iter().map(Expression::to_pddl).collect::<Vec<_>>().join("\n")
));
pddl.push_str(&format!("(:goal\n{}\n)\n", &self.goal.to_pddl()));
pddl.push(')');
pddl
}
}