1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
//! # A PDDL 3.1 parser, strongly typed
//!
//! This crates provides a PDDL 3.1 parser implementation based on [nom](https://crates.io/crates/nom).
//!
//! ## Default crate features
//!
//! * `parser` - Enables parsing of PDDL types through the [`Parser`] trait.
//! * `interning` - Enables string interning for [`Name`] types to reduce memory footprint.
//! * `pretty` - Enables pretty-printing of PDDL types via the
//! `Pretty` extension trait. The feature provides round-trip-safe
//! rendering: `parse → pretty() → parse` preserves AST equality.
//!
//! ## Example
//!
//! The two core types of a PDDL are [`Domain`] and [`Problem`]. This example shows how to
//! parse them:
//!
//! ```
//! # #[cfg(feature = "parser")]
//! # fn main() {
//! use pddl::{Parser, Domain, Problem};
//!
//! const BRIEFCASE_WORLD: &'static str = r#"
//! (define (domain briefcase-world)
//! (:requirements :strips :equality :typing :conditional-effects)
//! (:types location physob)
//! (:constants B P D - physob)
//! (:predicates (at ?x - physob ?y - location)
//! (in ?x ?y - physob))
//!
//! (:action mov-B
//! :parameters (?m ?l - location)
//! :precondition (and (at B ?m) (not (= ?m ?l)))
//! :effect (and (at B ?l) (not (at B ?m))
//! (forall (?z)
//! (when (and (in ?z) (not (= ?z B)))
//! (and (at ?z ?l) (not (at ?z ?m)))))) )
//!
//! (:action put-in
//! :parameters (?x - physob ?l - location)
//! :precondition (not (= ?x B))
//! :effect (when (and (at ?x ?l) (at B ?l))
//! (in ?x)) )
//!
//! (:action take-out
//! :parameters (?x - physob)
//! :precondition (not (= ?x B))
//! :effect (not (in ?x)) )
//! )
//! "#;
//!
//! const BRIEFCASE_WORLD_PROBLEM: &'static str = r#"
//! (define (problem get-paid)
//! (:domain briefcase-world)
//! (:init (place home) (place office)
//! (object p) (object d) (object b)
//! (at B home) (at P home) (at D home) (in P))
//! (:goal (and (at B office) (at D office) (at P home)))
//! )
//! "#;
//!
//! let domain = Domain::from_str(BRIEFCASE_WORLD).unwrap();
//! let problem = Problem::from_str(BRIEFCASE_WORLD_PROBLEM).unwrap();
//!
//! // All elements were parsed.
//! assert_eq!(domain.name(), "briefcase-world");
//! assert_eq!(domain.requirements().len(), 4);
//! assert_eq!(domain.types().len(), 2);
//! assert_eq!(domain.constants().len(), 3);
//! assert_eq!(domain.predicates().len(), 2);
//! assert_eq!(domain.structure().len(), 3);
//!
//! // All elements were parsed.
//! assert_eq!(problem.name(), "get-paid");
//! assert_eq!(problem.domain(), "briefcase-world");
//! assert!(problem.requirements().is_empty());
//! assert_eq!(problem.init().len(), 9);
//! assert_eq!(problem.goals().len(), 3);
//! # }
//! # #[cfg(not(feature = "parser"))]
//! # fn main() {}
//! ```
//!
//! ## Multi-Definition Files
//!
//! Some PDDL files contain multiple domain and problem definitions. Use [`PddlFile`] to parse them:
//!
//! ```
//! # #[cfg(feature = "parser")]
//! # fn main() {
//! use pddl::{Parser, PddlFile};
//!
//! const MULTI_DEF: &'static str = r#"
//! (define (domain my-domain)
//! (:requirements :strips)
//! (:predicates (p))
//! )
//! (define (problem my-problem)
//! (:domain my-domain)
//! (:init (p))
//! (:goal (p))
//! )
//! "#;
//!
//! let file = PddlFile::from_str(MULTI_DEF).unwrap();
//! assert_eq!(file.domain_count(), 1);
//! assert_eq!(file.problem_count(), 1);
//! # }
//! # #[cfg(not(feature = "parser"))]
//! # fn main() {}
//! ```
//!
//! ## PDDL Type System Guide
//!
//! This crate provides a comprehensive type system that models the PDDL 3.1 specification.
//! The type names may look unwieldy at first glance, but they follow a deliberate design principle:
//!
//! **Every type name maps directly to a BNF non-terminal from the PDDL 3.1 spec.**
//!
//! For example, the BNF rule `<c-effect>` becomes [`ConditionalEffect`], `<da-gd>` becomes
//! [`DurativeActionGoalDefinition`], and `<con-GD>` becomes [`ConstraintGoalDefinition`]. This 1:1 mapping
//! makes it trivial to cross-reference the spec while reading or writing code.
//!
//! ### BNF Naming Convention
//!
//! The PDDL 3.1 specification defines its grammar using BNF (Backus-Naur Form). Each
//! non-terminal in the BNF is written as `<something>`. This crate uses those names
//! directly, with minor transformations:
//!
//! | BNF Non-Terminal | Rust Type | Notes |
//! |------------------|-----------|-------|
//! | `<gd>` | [`GoalDefinition`] | Goal definition (the core logical formula type) |
//! | `<pre-GD>` | [`PreconditionGoalDefinition`] | Precondition-specific wrapper |
//! | `<precondition>` | [`PreconditionGoalDefinitions`] | Collection of preconditions |
//! | `<da-gd>` | [`DurativeActionGoalDefinition`] | Durative action goals (timed) |
//! | `<con-GD>` | [`ConstraintGoalDefinition`] | Constraint goals (temporal constraints) |
//! | `<con2-GD>` | [`ConstraintGoalDefinitionInner`] | Inner constraint goal (goal or nested con-GD) |
//! | `<pref-con-GD>` | [`PreferenceConstraintGoalDefinition`] | Preference constraint goals |
//! | `<pref-GD>` | [`PreferenceGoalDefinition`] | Preferred goal (goal or named preference) |
//! | `<c-effect>` | [`ConditionalEffect`] | Conditional effect |
//! | `<p-effect>` | [`PrimitiveEffect`] | Primitive effect |
//! | `<effect>` | [`Effects`] | Collection of effects (the `(and ...)` block) |
//! | `<da-effect>` | [`DurativeActionEffect`] | Durative action effect |
//! | `<f-exp>` | [`FluentExpression`] | Fluent/numeric expression |
//! | `<f-comp>` | [`FluentComparison`] | Fluent comparison |
//! | `<f-head>` | [`FunctionHead`] | Fluent head (function reference) |
//! | `<atomic formula (skeleton)>` | [`AtomicFormulaSkeleton`] | Predicate declaration with typed variables |
//!
//! When you see a type with an abbreviated name, look for the corresponding BNF rule
//! in the spec — it will almost certainly match.
//!
//! ### Type Groups
//!
//! #### Atoms & Formulas
//!
//! The building blocks of PDDL logical expressions:
//!
//! - [`AtomicFormula<T>`] — An atomic formula parameterized by its term type `T`.
//! Can be either an equality (`(= x y)`) or a predicate application (`(on a b)`).
//! See [`EqualityAtomicFormula`] and [`PredicateAtomicFormula`].
//! - [`AtomicFormulaSkeleton`] — A predicate declaration with typed variables, used
//! in `(:predicates ...)` blocks. Think of it as a "template" for [`AtomicFormula`].
//! - [`Literal<T>`] — A possibly-negated [`AtomicFormula<T>`]. Represents `(not (on a b))`.
//! - [`Predicate`] — A named predicate (wraps a [`Name`]).
//!
//! **Generic parameter `T`**: [`AtomicFormula<T>`] and [`Literal<T>`] are generic.
//! - `AtomicFormula<Name>` — Used in problem initial states (concrete objects only).
//! - `AtomicFormula<Term>` — Used in action goals/preconditions (may contain [`Variable`]s).
//!
//! #### Goals & Preconditions
//!
//! This is where the naming proliferation is most apparent. Each variant serves a
//! distinct purpose in the PDDL spec:
//!
//! - [`GoalDefinition`] (`<gd>`) — The core logical formula type. Supports `and`, `or`,
//! `not`, `imply`, `exists`, `forall`, atomic formulas, literals, and fluent comparisons.
//! Used in action preconditions, goal definitions, and effect conditions.
//!
//! - [`PreconditionGoalDefinition`] (`<pre-GD>`) — A simplified variant used specifically
//! for action preconditions. Contains either a [`PreferenceGoalDefinition`] or a `forall` quantifier.
//! Multiple are collected in [`PreconditionGoalDefinitions`].
//!
//! - [`ProblemGoalDefinition`] (`<goal>` in problem context) — A thin wrapper around [`PreconditionGoalDefinitions`] used by
//! [`Problem`] for the `(:goal ...)` section.
//!
//! - [`DurativeActionGoalDefinition`] (`<da-gd>`) — Goals for durative actions. Uses
//! [`TimedGoalDefinition`] (time-qualified goals like `(at start (on a b))`) instead of plain
//! [`GoalDefinition`].
//!
//! - [`ConstraintGoalDefinition`] (`<con-GD>`) — Temporal constraint goals for problem-level constraints.
//! Supports `always`, `sometime`, `within`, `at-most-once`, `sometime-after`,
//! `sometime-before`, `always-within`, `hold-during`, `hold-after`. Used by
//! [`ProblemConstraintsDef`].
//!
//! - [`ConstraintGoalDefinitionInner`] (`<con2-GD>`) — An inner component of [`ConstraintGoalDefinition`], representing either
//! a plain [`GoalDefinition`] or a nested [`ConstraintGoalDefinition`].
//!
//! - [`PreferenceConstraintGoalDefinition`] (`<pref-con-GD>`) — Constraint goals with optional preference names.
//! Used in [`ProblemConstraintsDef`].
//!
//! - [`PreferenceGoalDefinition`] — Either a plain [`GoalDefinition`] or a named [`Preference`].
//! Used in [`PreconditionGoalDefinition`].
//!
//! #### Effects
//!
//! The effects hierarchy mirrors the BNF structure:
//!
//! ```text
//! Effects (Vec<ConditionalEffect>) ← the (and ...) block
//! └── ConditionalEffect ← one effect element
//! ├── PrimitiveEffect ← primitive effect
//! ├── Forall(ForallConditionalEffect) ← universal quantification over effects
//! └── When(WhenConditionalEffect) ← conditional effect (when <cond> <effect>)
//! └── EffectCondition
//! ├── PrimitiveEffect ← primitive effect (same as above)
//! ├── Forall...
//! └── When...
//! ```
//!
//! - [`PrimitiveEffect`] (`<p-effect>`) — A primitive effect: setting/negating an atomic formula,
//! or assigning a numeric/object fluent.
//! - [`ConditionalEffect`] (`<c-effect>`) — A potentially conditional effect. Wraps [`PrimitiveEffect`],
//! [`ForallConditionalEffect`], or [`WhenConditionalEffect`].
//! - [`Effects`] (`<effect>`) — A collection of [`ConditionalEffect`] values, representing the
//! `(and ...)` block in PDDL.
//! - [`DurativeActionEffect`] (`<da-effect>`) — Effects for durative actions, using
//! [`TimedEffect`] (time-qualified effects like `(at end (on a b))`).
//!
//! #### Numeric & Fluents
//!
//! Types for numeric reasoning in PDDL:
//!
//! - [`FluentExpression`] (`<f-exp>`) — A fluent expression: a number, function call, negation,
//! binary operation (`+`, `-`, `*`, `/`), or multi-operand operation.
//! - [`FunctionHead`] (`<f-head>`) — A function head: either a bare function symbol or a
//! [`FunctionTerm`] (function applied to arguments).
//! - [`FluentComparison`] (`<f-comp>`) — A fluent comparison: `<`, `<=`, `>`, `>=`, `=` applied
//! to two [`FluentExpression`] values.
//! - [`TimedFluentExpression`] (`<f-exp-t>`) — Time-qualified fluent expression (for durative actions).
//! - [`DurativeActionFluentExpression`] (`<f-exp-da>`) — Durative-action-specific fluent expression.
//! - [`FunctionHead`] variants: [`BasicFunctionTerm`], [`FunctionTerm`].
//! - [`AssignOp`] / [`TimedAssignOperator`] — Assignment operators (`assign`, `scale-up`, etc.).
//!
//! #### Terms
//!
//! The fundamental building blocks that appear in formulas:
//!
//! - [`Term`] — A term: either a [`Name`] (concrete object), [`Variable`], or
//! [`FunctionTerm`] (fluent application).
//! - [`Name`] — A named constant/object.
//! - [`Variable`] — A logical variable (e.g., `?x`).
//! - [`TypedList<T>`] — A list of items with shared type annotations, e.g.,
//! `(?x ?y - robot obj1 obj2 - package)`.
//!
//! ### Common Confusion Points
//!
//! | Confused Pair | Difference |
//! |---------------|------------|
//! | [`AtomicFormulaSkeleton`] vs [`AtomicFormula`] | Skeleton declares a predicate's signature (used in `:predicates`); Formula applies it to concrete terms (used in goals/init). |
//! | [`PrimitiveEffect`] vs [`ConditionalEffect`] vs [`Effects`] | `PrimitiveEffect` is a single primitive effect; `ConditionalEffect` may add conditions/quantifiers; `Effects` is the `(and ...)` collection. |
//! | [`GoalDefinition`] vs [`PreconditionGoalDefinition`] | `GoalDefinition` is the full logical formula; `PreconditionGoalDefinition` is a simplified wrapper used only in action preconditions. |
//! | [`GoalDefinition`] vs [`DurativeActionGoalDefinition`] | `GoalDefinition` is timeless; `DurativeActionGoalDefinition` uses [`TimedGoalDefinition`] for time-qualified goals `(at start ...)`. |
//! | [`ConstraintGoalDefinition`] vs [`GoalDefinition`] | `ConstraintGoalDefinition` is for problem-level temporal constraints (`always`, `sometime`); `GoalDefinition` is the standard logical formula. |
//! | [`ProblemGoalDefinition`] vs [`GoalDefinition`] | `ProblemGoalDefinition` wraps [`PreconditionGoalDefinitions`] for the problem's `(:goal ...)`; `GoalDefinition` is the individual formula. |
//! | [`PreferenceGoalDefinition`] vs [`PreferenceConstraintGoalDefinition`] | `PreferenceGoalDefinition` is for action-level preferences; `PreferenceConstraintGoalDefinition` is for problem-level constraint preferences. |
//! | [`Effects`] vs [`ConditionalEffect`] vs [`EffectCondition`] | `Effects` is the top-level `(and ...)` collection of [`ConditionalEffect`]s (action `:effect` body); `ConditionalEffect` is one element that may be primitive, `forall`-quantified, or `when`-conditional; `EffectCondition` is the recursive `ConditionalEffect` tree nested inside `when` clauses. |
//! | [`FluentExpression`] vs [`FunctionHead`] | `FluentExpression` is any numeric expression; `FunctionHead` is specifically a function reference (with or without args). |
//! | [`Literal<T>`] vs [`AtomicFormula<T>`] | `Literal` can be negated; `AtomicFormula` is always positive. |
//!
//! ### PDDL Snippet → Rust Type Mapping
//!
//! ```text
//! ;; PDDL domain definition
//! (define (domain blocksworld)
//! (:predicates (on ?x ?y) ← AtomicFormulaSkeleton
//! (clear ?x)) ← AtomicFormulaSkeleton
//!
//! (:action pick-up
//! :parameters (?x) ← TypedList<Variable>
//! :precondition (and ← PreconditionGoalDefinitions
//! (clear ?x) ← GoalDefinition::AtomicFormula
//! (handempty)) ← GoalDefinition::AtomicFormula
//! :effect (and ← Effects
//! (not (clear ?x)) ← ConditionalEffect::Effect(PrimitiveEffect::NotAtomicFormula)
//! (holding ?x))) ← ConditionalEffect::Effect(PrimitiveEffect::AtomicFormula)
//!
//! (:goal (and ← ProblemGoalDefinition → PreconditionGoalDefinitions
//! (on a b) ← GoalDefinition::AtomicFormula
//! (on b c))) ← GoalDefinition::AtomicFormula
//! )
//!
//! ;; PDDL problem initial state
//! (define (problem bw-1)
//! (:init
//! (on a b) ← InitElement::Literal (Literal<Name>)
//! (clear a) ← InitElement::Literal
//! (= (total-cost) 0)) ← InitElement::IsValue (numeric fluent)
//! )
//! ```
//!
//! ### Navigating Further
//!
//! Each type has its own documentation with detailed examples and PDDL requirement annotations.
//! Use your IDE's "Go to Definition" or hover documentation to explore individual types.
// only enables the `doc_cfg` feature when
// the `docsrs` configuration attribute is defined
// re-export Parser trait.
pub use Parser;
// re-export types
pub use *;
pub use ;