Parser and Writer
PDDL.jl supports both parsing and writing of PDDL files and strings. In addition, the parser is designed to be extensible, allowing variants or extensions of PDDL to be easily supported.
General Parsing
The PDDL.Parser
submodule contains all functionality related to parsing PDDL strings and loading of PDDL files. To parse a string in PDDL, use the macro @pddl
or the function parse_pddl
. Both of these return a list of parsed results if multiple strings are provided.
PDDL.Parser.@pddl
— Macro@pddl(strs...)
Parse string(s) to PDDL construct(s).
When parsing PDDL formulae, the variable x
can be interpolated into the string using the syntax \$x
. For example, @pddl("(on \$x \$y)")
will parse to Compound(:on, Term[x, y])
if x
and y
are Term
s.
Julia expressions can be interpolated by surrounding the expression with curly braces, i.e. \${...}
.
PDDL.Parser.parse_pddl
— Functionparse_pddl(str)
Parse to PDDL structure based on initial keyword.
Below we use @pddl
to parse a sequence of predicates, and use parse_pddl
to parse a PDDL axiom (a.k.a. derived predicate):
julia> @pddl("(on a b)", "(on b c)")
2-element Vector{Compound}:
on(a, b)
on(b, c)
julia> parse_pddl("(:derived (handempty) (forall (?x) (not (holding ?x))))")
handempty <<= forall(object(X), not(holding(X)))
In addition, there exists a string macro pddl"..."
, which is useful for parsing single string literals:
julia> pddl"(on a b)"
on(a, b)
PDDL.Parser.@pddl_str
— Macropddl"..."
Parse string "..."
to PDDL construct.
When parsing PDDL formulae, the variable x
can be interpolated into the string using the syntax $x
. For example, pddl"(on $x $y)"
will parse to Compound(:on, Term[x, y])
if x
and y
are Term
s.
Julia expressions can be interpolated by surrounding the expression with curly braces, i.e. ${...}
.
Interpolation
The string macro pddl"...
(as well as the @pddl
macro) supports the interpolation of Julia variables using the $
operator when parsing PDDL formulae. This makes it easier to construct predicates or expressions with a fixed structure but variable contents:
obj = Const(:a)
sym = :b
pddl"(on $obj $sym)"
# Parses to the same value as pddl"(on a b)"
fname = :on
pddl"($fname a b)"
# Also parses to pddl"(on a b)"
var = pddl"(?x)"
type = :block
pddl"(forall ($var - $type) (on-table $var))"
# Parses to pddl"(forall (?x - block) (on-table ?x))"
It is also possible to interpolate entire Julia expressions by surrounding the expression in curly braces (note that the expression itself must not contain any curly braces):
pddl"(= cost ${1 + 2})" # Parses to pddl"(= cost 3)"
pddl"(= cost ${zero(Int)})" # Parses to pddl"(= cost 0)"
Interpolation is not supported when parsing larger PDDL constructs, such as actions, domains, and problems.
Parsing Domains and Problems
To parse domains and problems specified as PDDL strings, use parse_domain
and parse_problem
.
PDDL.Parser.parse_domain
— Functionparse_domain(expr)
Parse PDDL domain description.
PDDL.Parser.parse_problem
— Functionparse_problem(expr)
Parse PDDL problem description.
To load domains or problems from a file, use load_domain
and load_problem
.
PDDL.Parser.load_domain
— Functionload_domain(path::AbstractString)
load_domain(io::IO)
Load PDDL domain from specified path or IO object.
PDDL.Parser.load_problem
— Functionload_problem(path::AbstractString)
load_problem(io::IO)
Load PDDL problem from specified path or IO object.
Extending the Parser
The parser can be extended to handle new PDDL constructs using the following macros:
PDDL.Parser.@add_top_level
— Macro@add_top_level(name, f)
Register f
as a top-level parser for PDDL descriptions (e.g domains, problems).
PDDL.Parser.@add_header_field
— Macro@add_header_field(desc, fieldname, f)
Register f
as a parser for a header field in a PDDL description.
PDDL.Parser.@add_body_field
— Macro@add_body_field(desc, fieldname, f)
Register f
as a parser for a body field in a PDDL description.
General Writing
The PDDL.Writer
submodule contains all functionality related to writing PDDL strings and saving of PDDL files. To write a string in PDDL syntax, use the function write_pddl
.
PDDL.Writer.write_pddl
— Functionwrite_pddl(f)
Write to string in PDDL syntax.
Below we use write_pddl
to write out an Action
from the Blocksworld domain.
julia> write_pddl(PDDL.get_action(domain, :stack)) |> print
(:action stack
:parameters (?x ?y - block)
:precondition (and (holding ?x) (clear ?y) (not (= ?x ?y)))
:effect (and (not (holding ?x)) (not (clear ?y)) (clear ?x) (handempty) (on ?x ?y)))
Writing Domains and Problems
To write domains and problem as PDDL strings, use write_domain
and write_problem
.
PDDL.Writer.write_domain
— Functionwrite_domain(domain)
write_domain(domain, indent)
Write domain in PDDL syntax.
PDDL.Writer.write_problem
— Functionwrite_problem(problem)
write_problem(problem, indent)
Write problem in PDDL syntax.
To save domains or problems as text files to a path, use save_domain
and save_problem
.
PDDL.Writer.save_domain
— Functionsave_domain(path::String, domain::Domain)
Save PDDL domain to specified path.
PDDL.Writer.save_problem
— Functionsave_problem(path::String, problem::Problem)
Save PDDL problem to specified path.