pddl_parser/
problem.rs

1use nom::combinator::opt;
2use nom::multi::{many0, many1};
3use nom::sequence::{delimited, pair, preceded, tuple};
4use nom::IResult;
5use serde::{Deserialize, Serialize};
6
7use crate::domain::expression::Expression;
8use crate::domain::typing::Type;
9use crate::error::ParserError;
10use crate::lexer::{Token, TokenStream};
11use crate::tokens::id;
12
13/// A PDDL object
14#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct Object {
16    /// The name of the object
17    pub name: String,
18    /// The type of the object
19    #[serde(rename = "type")]
20    pub type_: Type,
21}
22
23impl Object {
24    /// Convert a typed object to a PDDL format. That is `name - type`.
25    pub fn to_pddl(&self) -> String {
26        format!("{} - {}", self.name, self.type_.to_pddl())
27    }
28}
29
30/// A PDDL problem
31///
32/// A problem is a description of a particular planning problem. It consists of a domain, a set of objects, an initial state, and a goal state.
33#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
34pub struct Problem {
35    /// The name of the problem
36    pub name: String,
37    /// The name of the domain of the problem
38    pub domain: String,
39    /// The objects of the problem
40    #[serde(default)]
41    pub objects: Vec<Object>,
42    /// The initial state of the problem
43    #[serde(default)]
44    pub init: Vec<Expression>,
45    /// The goal of the problem
46    pub goal: Expression,
47}
48
49impl Problem {
50    /// Parse a PDDL problem
51    pub fn parse(input: TokenStream) -> Result<Self, ParserError> {
52        let (output, problem) = delimited(
53            Token::OpenParen,
54            preceded(Token::Define, Problem::parse_problem),
55            Token::CloseParen,
56        )(input)?;
57        if !output.is_empty() {
58            return Err(ParserError::ExpectedEndOfInput);
59        }
60        Ok(problem)
61    }
62
63    fn parse_problem(input: TokenStream) -> IResult<TokenStream, Problem, ParserError> {
64        let (output, (name, domain, objects, init, goal)) = tuple((
65            Problem::parse_name,
66            Problem::parse_domain,
67            Problem::parse_objects,
68            Problem::parse_init,
69            Problem::parse_goal,
70        ))(input)?;
71        Ok((
72            output,
73            Problem {
74                name,
75                domain,
76                objects,
77                init,
78                goal,
79            },
80        ))
81    }
82
83    fn parse_name(input: TokenStream) -> IResult<TokenStream, String, ParserError> {
84        let (output, name) = delimited(Token::OpenParen, preceded(Token::Problem, id), Token::CloseParen)(input)?;
85        Ok((output, name))
86    }
87
88    fn parse_domain(input: TokenStream) -> IResult<TokenStream, String, ParserError> {
89        let (output, domain) =
90            delimited(Token::OpenParen, preceded(Token::ProblemDomain, id), Token::CloseParen)(input)?;
91        Ok((output, domain))
92    }
93
94    fn parse_objects(input: TokenStream) -> IResult<TokenStream, Vec<Object>, ParserError> {
95        let (output, objects) = delimited(
96            Token::OpenParen,
97            preceded(
98                Token::Objects,
99                many0(pair(many1(id), opt(preceded(Token::Dash, Type::parse_type)))),
100            ),
101            Token::CloseParen,
102        )(input)?;
103        let objects = objects
104            .into_iter()
105            .flat_map(move |(names, type_)| {
106                names
107                    .into_iter()
108                    .map(|name| Object {
109                        name,
110                        type_: type_.clone().unwrap_or_default(),
111                    })
112                    .collect::<Vec<_>>()
113            })
114            .collect();
115        Ok((output, objects))
116    }
117
118    fn parse_init(input: TokenStream) -> IResult<TokenStream, Vec<Expression>, ParserError> {
119        log::debug!("BEGIN > parse_init {:?}", input.span());
120        let (output, init) = delimited(
121            Token::OpenParen,
122            preceded(Token::Init, many0(Expression::parse_expression)),
123            Token::CloseParen,
124        )(input)?;
125        log::debug!("END < parse_init {:?}", output.span());
126        Ok((output, init))
127    }
128
129    fn parse_goal(input: TokenStream) -> IResult<TokenStream, Expression, ParserError> {
130        let (output, goal) = delimited(
131            Token::OpenParen,
132            preceded(Token::Goal, Expression::parse_expression),
133            Token::CloseParen,
134        )(input)?;
135        Ok((output, goal))
136    }
137
138    /// Convert the problem to PDDL format (as a string) for writing to a file
139    pub fn to_pddl(&self) -> String {
140        let mut pddl = String::new();
141
142        // Name and domain
143        pddl.push_str(&format!("(define (problem {})\n", self.name));
144        pddl.push_str(&format!("(:domain {})\n", self.domain));
145
146        // Objects
147        pddl.push_str(&format!(
148            "(:objects\n{}\n)\n",
149            self.objects.iter().map(Object::to_pddl).collect::<Vec<_>>().join("\n")
150        ));
151
152        // Init
153        pddl.push_str(&format!(
154            "(:init\n{}\n)\n",
155            self.init.iter().map(Expression::to_pddl).collect::<Vec<_>>().join("\n")
156        ));
157
158        // Goal
159        pddl.push_str(&format!("(:goal\n{}\n)\n", &self.goal.to_pddl()));
160
161        // End
162        pddl.push(')');
163
164        pddl
165    }
166}