Renamed “pddlparse” library to simply “pddl”.

This commit is contained in:
2017-08-09 17:52:50 +02:00
parent a24ce91acb
commit 9199b68080
120 changed files with 479 additions and 479 deletions

28
lib/pddl/CMakeLists.txt Normal file
View File

@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 2.6)
project(pddl)
option(PDDL_BUILD_TESTS "Build unit tests" OFF)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic -Werror ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "-g ${CMAKE_CXX_FLAGS_DEBUG}")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
if (CMAKE_GENERATOR STREQUAL "Ninja" AND
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)))
# Force colored warnings in Ninja's output, if the compiler has -fdiagnostics-color support.
# Rationale in https://github.com/ninja-build/ninja/issues/814
set(CMAKE_CXX_FLAGS "-fdiagnostics-color=always ${CMAKE_CXX_FLAGS}")
endif()
add_subdirectory(src)
if(PDDL_BUILD_TESTS)
add_subdirectory(tests)
endif(PDDL_BUILD_TESTS)

504
lib/pddl/include/pddl/AST.h Normal file
View File

@@ -0,0 +1,504 @@
#ifndef __PDDL__AST_H
#define __PDDL__AST_H
#include <limits>
#include <experimental/optional>
#include <set>
#include <type_traits>
#include <vector>
#include <pddl/ASTForward.h>
namespace pddl
{
namespace ast
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// AST
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Constant
{
explicit Constant(ConstantDeclaration *declaration)
: declaration{declaration}
{
}
Constant(const Constant &other) = delete;
Constant &operator=(const Constant &&other) = delete;
Constant(Constant &&other) = default;
Constant &operator=(Constant &&other) = default;
ConstantDeclaration *declaration;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct ConstantDeclaration
{
explicit ConstantDeclaration(std::string &&name, std::experimental::optional<Type> &&type = std::experimental::nullopt)
: name{std::move(name)},
type{std::move(type)}
{
}
ConstantDeclaration(const ConstantDeclaration &other) = delete;
ConstantDeclaration &operator=(const ConstantDeclaration &&other) = delete;
ConstantDeclaration(ConstantDeclaration &&other) = delete;
ConstantDeclaration &operator=(ConstantDeclaration &&other) = delete;
std::string name;
// TODO: check whether “either” types should actually be allowed at all
std::experimental::optional<Type> type;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct PrimitiveType
{
explicit PrimitiveType(PrimitiveTypeDeclaration *declaration)
: declaration{declaration}
{
}
PrimitiveType(const PrimitiveType &other) = delete;
PrimitiveType &operator=(const PrimitiveType &&other) = delete;
PrimitiveType(PrimitiveType &&other) = default;
PrimitiveType &operator=(PrimitiveType &&other) = default;
PrimitiveTypeDeclaration *declaration;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct PrimitiveTypeDeclaration
{
explicit PrimitiveTypeDeclaration(std::string &&name)
: name{std::move(name)}
{
}
PrimitiveTypeDeclaration(const PrimitiveTypeDeclaration &other) = delete;
PrimitiveTypeDeclaration &operator=(const PrimitiveTypeDeclaration &&other) = delete;
PrimitiveTypeDeclaration(PrimitiveTypeDeclaration &&other) = delete;
PrimitiveTypeDeclaration &operator=(PrimitiveTypeDeclaration &&other) = delete;
std::string name;
std::vector<PrimitiveTypePointer> parentTypes;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Variable
{
explicit Variable(VariableDeclaration *declaration)
: declaration{declaration}
{
}
Variable(const Variable &other) = delete;
Variable &operator=(const Variable &&other) = delete;
Variable(Variable &&other) = default;
Variable &operator=(Variable &&other) = default;
VariableDeclaration *declaration;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct VariableDeclaration
{
explicit VariableDeclaration(std::string &&name, std::experimental::optional<Type> type = std::experimental::nullopt)
: name{std::move(name)},
type{std::move(type)}
{
}
VariableDeclaration(const VariableDeclaration &other) = delete;
VariableDeclaration &operator=(const VariableDeclaration &&other) = delete;
VariableDeclaration(VariableDeclaration &&other) = delete;
VariableDeclaration &operator=(VariableDeclaration &&other) = delete;
std::string name;
std::experimental::optional<Type> type;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Compounds
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Predicate
{
using Arguments = Terms;
explicit Predicate(Arguments &&arguments, PredicateDeclaration *declaration)
: arguments{std::move(arguments)},
declaration{declaration}
{
}
Predicate(const Predicate &other) = delete;
Predicate &operator=(const Predicate &&other) = delete;
Predicate(Predicate &&other) = default;
Predicate &operator=(Predicate &&other) = default;
Arguments arguments;
PredicateDeclaration *declaration;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct PredicateDeclaration
{
explicit PredicateDeclaration(std::string &&name, VariableDeclarations &&parameters)
: name{std::move(name)},
parameters{std::move(parameters)}
{
}
PredicateDeclaration(const PredicateDeclaration &other) = delete;
PredicateDeclaration &operator=(const PredicateDeclaration &&other) = delete;
PredicateDeclaration(PredicateDeclaration &&other) = default;
PredicateDeclaration &operator=(PredicateDeclaration &&other) = default;
std::string name;
VariableDeclarations parameters;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions: Base Classes
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class ArgumentLeft, class ArgumentRight = ArgumentLeft>
struct Binary
{
explicit Binary(ArgumentLeft &&argumentLeft, ArgumentRight &&argumentRight)
: argumentLeft{std::move(argumentLeft)},
argumentRight{std::move(argumentRight)}
{
}
Binary(const Binary &other) = delete;
Binary &operator=(const Binary &&other) = delete;
Binary(Binary &&other) = default;
Binary &operator=(Binary &&other) = default;
ArgumentLeft argumentLeft;
ArgumentRight argumentRight;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class Argument>
struct NAry
{
using Arguments = std::vector<Argument>;
explicit NAry(Arguments &&arguments) noexcept
: arguments{std::move(arguments)}
{
}
NAry(const NAry &other) = delete;
NAry &operator=(const NAry &&other) = delete;
NAry(NAry &&other) = default;
NAry &operator=(NAry &&other) = default;
Arguments arguments;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class Argument>
struct Quantified
{
using Parameters = VariableDeclarations;
explicit Quantified(Parameters &&parameters, Argument &&argument)
: parameters{std::move(parameters)},
argument{std::move(argument)}
{
}
Quantified(const Quantified &other) = delete;
Quantified &operator=(const Quantified &&other) = delete;
Quantified(Quantified &&other) = default;
Quantified &operator=(Quantified &&other) = default;
Parameters parameters;
Argument argument;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct And: public NAry<And<Argument>, Argument>
{
using typename NAry<And<Argument>, Argument>::Arguments;
static constexpr const auto Identifier = "and";
explicit And(Arguments &&arguments) noexcept
: NAry<And<Argument>, Argument>(std::move(arguments))
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: make binary expression
template<class Argument>
struct At
{
static constexpr const auto TimePointStart = std::numeric_limits<std::size_t>::max();
static constexpr const auto TimePointEnd = std::numeric_limits<std::size_t>::max() - 1;
At(std::size_t timePoint, Argument &&argument)
: timePoint{timePoint},
argument{std::move(argument)}
{
}
At(const At &other) = delete;
At &operator=(const At &&other) = delete;
At(At &&other) = default;
At &operator=(At &&other) = default;
std::size_t timePoint;
Argument argument;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct Either: public NAry<Either<Argument>, Argument>
{
using typename NAry<Either<Argument>, Argument>::Arguments;
static constexpr const auto Identifier = "either";
explicit Either(Arguments &&arguments) noexcept
: NAry<Either<Argument>, Argument>(std::move(arguments))
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct Exists: public Quantified<Exists<Argument>, Argument>
{
static constexpr const auto Identifier = "exists";
explicit Exists(VariableDeclarations &&parameters, Argument &&argument)
: Quantified<Exists<Argument>, Argument>(std::move(parameters), std::move(argument))
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct ForAll: public Quantified<ForAll<Argument>, Argument>
{
static constexpr const auto Identifier = "forall";
explicit ForAll(VariableDeclarations &&parameters, Argument &&argument)
: Quantified<ForAll<Argument>, Argument>(std::move(parameters), std::move(argument))
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct Imply: public Binary<Imply<Argument>, Argument>
{
static constexpr const auto Identifier = "imply";
// TODO: make noexcept consistent
explicit Imply(Argument &&argumentLeft, Argument &&argumentRight)
: Binary<Imply<Argument>, Argument>(std::move(argumentLeft), std::move(argumentRight))
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct Not
{
explicit Not(Argument &&argument)
: argument{std::move(argument)}
{
}
Not(const Not &other) = delete;
Not &operator=(const Not &&other) = delete;
Not(Not &&other) = default;
Not &operator=(Not &&other) = default;
Argument argument;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct Or: public NAry<Or<Argument>, Argument>
{
using typename NAry<Or<Argument>, Argument>::Arguments;
static constexpr const auto Identifier = "or";
explicit Or(Arguments &&arguments) noexcept
: NAry<Or<Argument>, Argument>(std::move(arguments))
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ArgumentLeft, class ArgumentRight>
struct When: public Binary<When<ArgumentLeft, ArgumentRight>, ArgumentLeft, ArgumentRight>
{
static constexpr const auto Identifier = "when";
explicit When(ArgumentLeft &&argumentLeft, ArgumentRight &&argumentRight)
: Binary<When<ArgumentLeft, ArgumentRight>, ArgumentLeft, ArgumentRight>(std::move(argumentLeft), std::move(argumentRight))
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// PDDL Structure
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Action
{
Action() = default;
Action(const Action &other) = delete;
Action &operator=(const Action &&other) = delete;
Action(Action &&other) = default;
Action &operator=(Action &&other) = default;
std::string name;
VariableDeclarations parameters;
std::experimental::optional<Precondition> precondition;
std::experimental::optional<Effect> effect;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Domain
{
Domain() = default;
Domain(const Domain &other) = delete;
Domain &operator=(const Domain &&other) = delete;
Domain(Domain &&other) = delete;
Domain &operator=(Domain &&other) = delete;
std::string name;
Requirements requirements;
PrimitiveTypeDeclarations types;
ConstantDeclarations constants;
PredicateDeclarations predicates;
Actions actions;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct InitialState
{
InitialState() = default;
InitialState(const InitialState &other) = delete;
InitialState &operator=(const InitialState &&other) = delete;
InitialState(InitialState &&other) = default;
InitialState &operator=(InitialState &&other) = default;
Facts facts;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Problem
{
Problem() = default;
Problem(Domain *domain)
: domain{domain}
{
}
Problem(const Problem &other) = delete;
Problem &operator=(const Problem &&other) = delete;
Problem(Problem &&other) = default;
Problem &operator=(Problem &&other) = default;
Domain *domain;
std::string name;
Requirements requirements;
ConstantDeclarations objects;
InitialState initialState;
std::experimental::optional<Goal> goal;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: think about ignoring requirement statements entirely and computing them instead
enum class Requirement
{
STRIPS,
Typing,
NegativePreconditions,
DisjunctivePreconditions,
Equality,
ExistentialPreconditions,
UniversalPreconditions,
QuantifiedPreconditions,
ConditionalEffects,
Fluents,
NumericFluents,
ObjectFluents,
ADL,
DurativeActions,
DurationInequalities,
ContinuousEffects,
DerivedPredicates,
TimedInitialLiterals,
Preferences,
Constraints,
ActionCosts,
GoalUtilities
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Description
{
Description() = default;
Description(const Description &other) = delete;
Description &operator=(const Description &&other) = delete;
Description(Description &&other) = default;
Description &operator=(Description &&other) = default;
DomainPointer domain;
std::experimental::optional<ProblemPointer> problem;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,280 @@
#ifndef __PDDL__AST_FORWARD_H
#define __PDDL__AST_FORWARD_H
#include <iosfwd>
#include <memory>
#include <experimental/optional>
#include <set>
#include <vector>
#include <pddl/Variant.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// AST Forward Declarations
//
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace ast
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Constant;
using ConstantPointer = std::unique_ptr<Constant>;
struct ConstantDeclaration;
using ConstantDeclarationPointer = std::unique_ptr<ConstantDeclaration>;
using ConstantDeclarations = std::vector<ConstantDeclarationPointer>;
struct PrimitiveType;
using PrimitiveTypePointer = std::unique_ptr<PrimitiveType>;
using PrimitiveTypes = std::vector<PrimitiveTypePointer>;
struct PrimitiveTypeDeclaration;
using PrimitiveTypeDeclarationPointer = std::unique_ptr<PrimitiveTypeDeclaration>;
using PrimitiveTypeDeclarations = std::vector<PrimitiveTypeDeclarationPointer>;
struct Variable;
using VariablePointer = std::unique_ptr<Variable>;
using Variables = std::vector<VariablePointer>;
struct VariableDeclaration;
using VariableDeclarationPointer = std::unique_ptr<VariableDeclaration>;
using VariableDeclarations = std::vector<VariableDeclarationPointer>;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Compounds
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Predicate;
using PredicatePointer = std::unique_ptr<Predicate>;
using Predicates = std::vector<PredicatePointer>;
struct PredicateDeclaration;
using PredicateDeclarationPointer = std::unique_ptr<PredicateDeclaration>;
using PredicateDeclarations = std::vector<PredicateDeclarationPointer>;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct And;
template<class Argument>
using AndPointer = std::unique_ptr<And<Argument>>;
template<class Argument>
struct At;
template<class Argument>
using AtPointer = std::unique_ptr<At<Argument>>;
template<class Argument>
struct Either;
template<class Argument>
using EitherPointer = std::unique_ptr<Either<Argument>>;
template<class Argument>
struct Exists;
template<class Argument>
using ExistsPointer = std::unique_ptr<Exists<Argument>>;
template<class Argument>
struct ForAll;
template<class Argument>
using ForAllPointer = std::unique_ptr<ForAll<Argument>>;
template<class Argument>
struct Imply;
template<class Argument>
using ImplyPointer = std::unique_ptr<Imply<Argument>>;
template<class Argument>
struct Not;
template<class Argument>
using NotPointer = std::unique_ptr<Not<Argument>>;
template<class Argument>
struct Or;
template<class Argument>
using OrPointer = std::unique_ptr<Or<Argument>>;
template<class ArgumentLeft, class ArgumentRight>
struct When;
template<class ArgumentLeft, class ArgumentRight>
using WhenPointer = std::unique_ptr<When<ArgumentLeft, ArgumentRight>>;
////////////////////////////////////////////////////////////////////////////////////////////////////
// PDDL Structure
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Action;
using ActionPointer = std::unique_ptr<Action>;
using Actions = std::vector<ActionPointer>;
struct Description;
using DescriptionPointer = std::unique_ptr<Description>;
struct Domain;
using DomainPointer = std::unique_ptr<Domain>;
struct InitialState;
struct Problem;
using ProblemPointer = std::unique_ptr<Problem>;
enum class Requirement;
using Requirements = std::vector<Requirement>;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Variants
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace detail
{
using TermT = Variant<
ConstantPointer,
VariablePointer>;
}
class Term : public detail::TermT
{
Term() = delete;
using detail::TermT::TermT;
};
using Terms = std::vector<Term>;
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace detail
{
// TODO: add missing types
using AtomicFormulaT = Variant<
PredicatePointer>;
}
class AtomicFormula : public detail::AtomicFormulaT
{
AtomicFormula() = delete;
using detail::AtomicFormulaT::AtomicFormulaT;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace detail
{
using LiteralT = Variant<
AtomicFormula,
NotPointer<AtomicFormula>>;
}
class Literal : public detail::LiteralT
{
Literal() = delete;
using detail::LiteralT::LiteralT;
};
using Literals = std::vector<Literal>;
////////////////////////////////////////////////////////////////////////////////////////////////////
class Precondition;
namespace detail
{
// TODO: add missing types
using PreconditionT = Variant<
AtomicFormula,
AndPointer<Precondition>,
ExistsPointer<Precondition>,
ForAllPointer<Precondition>,
ImplyPointer<Precondition>,
NotPointer<Precondition>,
OrPointer<Precondition>>;
}
class Precondition : public detail::PreconditionT
{
Precondition() = delete;
using detail::PreconditionT::PreconditionT;
};
using Preconditions = std::vector<Precondition>;
////////////////////////////////////////////////////////////////////////////////////////////////////
class ConditionalEffect;
namespace detail
{
// TODO: add missing types
using ConditionalEffectT = Variant<
Literal,
AndPointer<Literal>>;
}
class ConditionalEffect : public detail::ConditionalEffectT
{
ConditionalEffect() = delete;
using detail::ConditionalEffectT::ConditionalEffectT;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
class Effect;
namespace detail
{
// TODO: add missing types
using EffectT = Variant<
Literal,
AndPointer<Effect>,
ForAllPointer<Effect>,
WhenPointer<Precondition, ConditionalEffect>>;
}
class Effect : public detail::EffectT
{
Effect() = delete;
using detail::EffectT::EffectT;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace detail
{
using TypeT = Variant<
EitherPointer<PrimitiveTypePointer>,
PrimitiveTypePointer>;
}
class Type : public detail::TypeT
{
Type() = delete;
using detail::TypeT::TypeT;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
class Fact;
namespace detail
{
using FactT = Variant<
AtPointer<Literal>,
Literal>;
}
class Fact : public detail::FactT
{
Fact() = delete;
using detail::FactT::FactT;
};
using Facts = std::vector<Fact>;
////////////////////////////////////////////////////////////////////////////////////////////////////
using Goal = Precondition;
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,608 @@
#ifndef __PDDL__AST_OUTPUT_H
#define __PDDL__AST_OUTPUT_H
#include <colorlog/ColorStream.h>
#include <colorlog/Formatting.h>
#include <pddl/AST.h>
#include <pddl/detail/OutputUtils.h>
#include <pddl/detail/parsing/Requirement.h>
namespace pddl
{
namespace ast
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Output
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Constant &constant, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const ConstantDeclaration &constantDeclaration, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const PrimitiveType &primitiveType, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const PrimitiveTypeDeclaration &primitiveTypeDeclaration, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Variable &variable, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const VariableDeclaration &variableDeclaration, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Predicate &predicate, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const PredicateDeclaration &predicateDeclaration, pddl::detail::PrintContext &printContext);
template<class Derived, class ArgumentLeft, class ArgumentRight = ArgumentLeft>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Binary<Derived, ArgumentLeft, ArgumentRight> &binary, pddl::detail::PrintContext &printContext);
template<class Derived, class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const NAry<Derived, Argument> &nAry, pddl::detail::PrintContext &printContext);
template<class Derived, class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Quantified<Derived, Argument> &quantified, pddl::detail::PrintContext &printContext);
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const At<Argument> &at, pddl::detail::PrintContext &printContext);
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Not<Argument> &not_, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Action &action, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Domain &domain, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const InitialState &initialState, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Problem &problem, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Requirement &requirement, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Description &description, pddl::detail::PrintContext &printContext);
template<class ValueType>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const std::unique_ptr<ValueType> &variant, pddl::detail::PrintContext &printContext);
template<class ValueType>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const std::vector<ValueType> &variant, pddl::detail::PrintContext &printContext);
template<class Variant>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Variant &variant, pddl::detail::PrintContext &printContext);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Constant &constant, pddl::detail::PrintContext &)
{
return stream << pddl::detail::Constant(constant.declaration->name);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const ConstantDeclaration &constantDeclaration, pddl::detail::PrintContext &printContext)
{
stream << pddl::detail::Constant(constantDeclaration.name);
if (constantDeclaration.type)
{
stream << " - ";
print(stream, constantDeclaration.type.value(), printContext);
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const PrimitiveType &primitiveType, pddl::detail::PrintContext &)
{
return stream << pddl::detail::Type(primitiveType.declaration->name);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const PrimitiveTypeDeclaration &primitiveTypeDeclaration, pddl::detail::PrintContext &printContext)
{
if (primitiveTypeDeclaration.parentTypes.empty())
return (stream << pddl::detail::Type(primitiveTypeDeclaration.name));
if (!primitiveTypeDeclaration.parentTypes.empty())
for (const auto &parentType : primitiveTypeDeclaration.parentTypes)
{
if (&parentType != &primitiveTypeDeclaration.parentTypes.front())
pddl::detail::printIndentedNewline(stream, printContext);
stream << pddl::detail::Type(primitiveTypeDeclaration.name) << " - " << pddl::detail::Type(parentType->declaration->name);
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Variable &variable, pddl::detail::PrintContext &)
{
const auto variableName = "?" + variable.declaration->name;
return (stream << colorlog::Variable(variableName.c_str()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const VariableDeclaration &variableDeclaration, pddl::detail::PrintContext &printContext)
{
const auto variableName = "?" + variableDeclaration.name;
stream << colorlog::Variable(variableName.c_str());
if (variableDeclaration.type)
{
stream << " - ";
print(stream, *variableDeclaration.type, printContext);
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Compounds
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Predicate &predicate, pddl::detail::PrintContext &printContext)
{
stream << "(" << pddl::detail::Identifier(predicate.declaration->name);
for (const auto &argument : predicate.arguments)
{
stream << " ";
print(stream, argument, printContext);
}
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const PredicateDeclaration &predicateDeclaration, pddl::detail::PrintContext &printContext)
{
stream << "(" << pddl::detail::Identifier(predicateDeclaration.name);
for (const auto &parameter : predicateDeclaration.parameters)
{
stream << " ";
print(stream, *parameter, printContext);
}
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions: Base Classes
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class ArgumentLeft, class ArgumentRight>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Binary<Derived, ArgumentLeft, ArgumentRight> &binary, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword(Derived::Identifier);
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, binary.argumentLeft, printContext);
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, binary.argumentRight, printContext);
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const NAry<Derived, Argument> &nAry, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword(Derived::Identifier);
printContext.indentationLevel++;
for (const auto &argument : nAry.arguments)
{
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, argument, printContext);
}
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Quantified<Derived, Argument> &quantified, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword(Derived::Identifier);
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(";
print(stream, quantified.parameters, printContext);
stream << ")";
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, quantified.argument, printContext);
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const And<Argument> &and_, pddl::detail::PrintContext &printContext)
{
return print(stream, static_cast<const NAry<And<Argument>, Argument> &>(and_), printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const At<Argument> &at, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword("at");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
stream << colorlog::Number<decltype(at.timePoint)>(at.timePoint);
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, at.argument, printContext);
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Either<Argument> &either, pddl::detail::PrintContext &printContext)
{
return print(stream, static_cast<const NAry<Either<Argument>, Argument> &>(either), printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Exists<Argument> &exists, pddl::detail::PrintContext &printContext)
{
return print(stream, static_cast<const Quantified<Exists<Argument>, Argument> &>(exists), printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const ForAll<Argument> &forAll, pddl::detail::PrintContext &printContext)
{
return print(stream, static_cast<const Quantified<ForAll<Argument>, Argument> &>(forAll), printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Imply<Argument> &imply, pddl::detail::PrintContext &printContext)
{
return print(stream, static_cast<const Binary<Imply<Argument>, Argument> &>(imply), printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Not<Argument> &not_, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword("not") << " ";
print(stream, not_.argument, printContext);
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Or<Argument> &or_, pddl::detail::PrintContext &printContext)
{
return print(stream, static_cast<const NAry<Or<Argument>, Argument> &>(or_), printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ArgumentLeft, class ArgumentRight>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const When<ArgumentLeft, ArgumentRight> &when, pddl::detail::PrintContext &printContext)
{
return print(stream, static_cast<const Binary<When<ArgumentLeft, ArgumentRight>, ArgumentLeft, ArgumentRight> &>(when), printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// PDDL Structure
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Action &action, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword(":action") << " " << pddl::detail::Identifier(action.name);
printContext.indentationLevel++;
if (!action.parameters.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":parameters");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(";
print(stream, action.parameters, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (action.precondition)
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":precondition");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, action.precondition.value(), printContext);
printContext.indentationLevel--;
}
if (action.effect)
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":effect");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, action.effect.value(), printContext);
printContext.indentationLevel--;
}
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Domain &domain, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword("define") << " (" << colorlog::Keyword("domain") << " " << pddl::detail::Identifier(domain.name) << ")";
printContext.indentationLevel++;
if (!domain.requirements.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":requirements");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, domain.requirements, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!domain.types.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":types");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, domain.types, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!domain.constants.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":constants");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, domain.constants, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!domain.predicates.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":predicates");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, domain.predicates, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!domain.actions.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, domain.actions, printContext);
}
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const InitialState &initialState, pddl::detail::PrintContext &printContext)
{
assert(!initialState.facts.empty());
stream << "(" << colorlog::Keyword(":init");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, initialState.facts, printContext);
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Problem &problem, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword("define") << " (" << colorlog::Keyword("problem") << " " << pddl::detail::Identifier(problem.name) << ")";
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":domain") << " " << pddl::detail::Identifier(problem.domain->name) << ")";
if (!problem.requirements.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":requirements");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, problem.requirements, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!problem.objects.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":objects");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, problem.objects, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!problem.initialState.facts.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, problem.initialState, printContext);
}
if (problem.goal)
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":goal");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, problem.goal.value(), printContext);
stream << ")";
printContext.indentationLevel--;
}
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Requirement &requirement, pddl::detail::PrintContext &)
{
auto requirementName = std::string(":") + pddl::detail::toString(requirement);
return (stream << pddl::detail::Identifier(requirementName.c_str()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Description &description, pddl::detail::PrintContext &printContext)
{
print(stream, *description.domain, printContext);
stream << std::endl;
if (description.problem)
{
stream << std::endl;
print(stream, *description.problem.value(), printContext);
stream << std::endl;
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &operator<<(colorlog::ColorStream &stream, const Description &description)
{
pddl::detail::PrintContext printContext;
return print(stream, description, printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Variants
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ValueType>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const std::unique_ptr<ValueType> &uniquePointer, pddl::detail::PrintContext &printContext)
{
assert(uniquePointer);
return print(stream, *uniquePointer, printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ValueType>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const std::vector<ValueType> &vector, pddl::detail::PrintContext &printContext)
{
for (const auto &element : vector)
{
if (&element != &vector.front())
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, element, printContext);
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Variant>
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Variant &variant, pddl::detail::PrintContext &printContext)
{
variant.match([&](const auto &x){return print(stream, x, printContext);});
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,53 @@
#ifndef __PDDL__CONTEXT_H
#define __PDDL__CONTEXT_H
#include <functional>
#include <pddl/Mode.h>
#include <pddl/Tokenizer.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Context
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Context
{
constexpr static const char *auxiliaryPrefix()
{
return "__plasp_";
}
// TODO: replace std::string with char *
using WarningCallback = std::function<void (tokenize::Location &&, const std::string &)>;
Context() = default;
~Context() = default;
explicit Context(Tokenizer &&tokenizer, WarningCallback warningCallback, Mode mode = Mode::Strict)
: tokenizer{std::move(tokenizer)},
warningCallback{warningCallback},
mode{mode}
{
}
Context(const Context &other) = delete;
Context &operator=(const Context &other) = delete;
Context(Context &&other) = default;
Context &operator=(Context &&other) = default;
Tokenizer tokenizer;
WarningCallback warningCallback;
Mode mode;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,95 @@
#ifndef __PDDL__EXCEPTION_H
#define __PDDL__EXCEPTION_H
#include <exception>
#include <experimental/optional>
#include <string>
#include <tokenize/Location.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Exception
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class Exception: public std::exception
{
public:
Exception()
: Exception("unspecified parser error")
{
}
Exception(const char *message)
: Exception(static_cast<std::string>(message))
{
}
Exception(const std::string &message)
: m_message{message}
{
}
Exception(tokenize::Location &&location)
: Exception(std::forward<tokenize::Location>(location), "unspecified parser error")
{
}
Exception(tokenize::Location &&location, const char *message)
: Exception(std::forward<tokenize::Location>(location), static_cast<std::string>(message))
{
}
Exception(tokenize::Location &&location, const std::string &message)
: m_location{std::move(location)},
m_message{message}
{
}
~Exception() noexcept = default;
const char *what() const noexcept
{
return m_message.c_str();
}
const std::experimental::optional<tokenize::Location> &location() const
{
return m_location;
}
const std::string &message() const
{
return m_message;
}
private:
std::experimental::optional<tokenize::Location> m_location;
std::string m_message;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
class ParserException : public Exception
{
public:
using Exception::Exception;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
class NormalizationException : public Exception
{
public:
using Exception::Exception;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,27 @@
#ifndef __PDDL__MODE_H
#define __PDDL__MODE_H
#include <functional>
#include <pddl/Tokenizer.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Mode
//
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class Mode
{
Strict,
Compatibility
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,24 @@
#ifndef __PDDL__NORMALIZE_H
#define __PDDL__NORMALIZE_H
#include <pddl/AST.h>
#include <pddl/Context.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/Description.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Normalize
//
////////////////////////////////////////////////////////////////////////////////////////////////////
using detail::normalize;
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,159 @@
#ifndef __PDDL__NORMALIZED_AST_H
#define __PDDL__NORMALIZED_AST_H
#include <limits>
#include <experimental/optional>
#include <set>
#include <type_traits>
#include <vector>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace normalizedAST
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Normalized AST
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// PDDL Structure
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Action
{
Action() = default;
Action(const Action &other) = delete;
Action &operator=(const Action &&other) = delete;
Action(Action &&other) = default;
Action &operator=(Action &&other) = default;
std::string name;
VariableDeclarations parameters;
std::experimental::optional<Precondition> precondition;
std::experimental::optional<Effect> effect;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Domain
{
Domain() = default;
Domain(const Domain &other) = delete;
Domain &operator=(const Domain &&other) = delete;
Domain(Domain &&other) = delete;
Domain &operator=(Domain &&other) = delete;
std::string name;
PrimitiveTypeDeclarations types;
ConstantDeclarations constants;
PredicateDeclarations predicates;
DerivedPredicateDeclarations derivedPredicates;
Actions actions;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct DerivedPredicate
{
using Arguments = Terms;
explicit DerivedPredicate(Arguments &&arguments, DerivedPredicateDeclaration *declaration)
: arguments{std::move(arguments)},
declaration{declaration}
{
}
DerivedPredicate(const DerivedPredicate &other) = delete;
DerivedPredicate &operator=(const DerivedPredicate &&other) = delete;
DerivedPredicate(DerivedPredicate &&other) = default;
DerivedPredicate &operator=(DerivedPredicate &&other) = default;
Arguments arguments;
DerivedPredicateDeclaration *declaration;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct DerivedPredicateDeclaration
{
explicit DerivedPredicateDeclaration() = default;
DerivedPredicateDeclaration(const DerivedPredicateDeclaration &other) = delete;
DerivedPredicateDeclaration &operator=(const DerivedPredicateDeclaration &&other) = delete;
DerivedPredicateDeclaration(DerivedPredicateDeclaration &&other) = default;
DerivedPredicateDeclaration &operator=(DerivedPredicateDeclaration &&other) = default;
std::string name;
std::vector<VariableDeclaration *> parameters;
VariableDeclarations existentialParameters;
std::experimental::optional<DerivedPredicatePrecondition> precondition;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct InitialState
{
InitialState() = default;
InitialState(const InitialState &other) = delete;
InitialState &operator=(const InitialState &&other) = delete;
InitialState(InitialState &&other) = default;
InitialState &operator=(InitialState &&other) = default;
Facts facts;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Problem
{
Problem() = default;
Problem(Domain *domain)
: domain{domain}
{
}
Problem(const Problem &other) = delete;
Problem &operator=(const Problem &&other) = delete;
Problem(Problem &&other) = default;
Problem &operator=(Problem &&other) = default;
Domain *domain;
std::string name;
DerivedPredicateDeclarations derivedPredicates;
ConstantDeclarations objects;
InitialState initialState;
std::experimental::optional<Goal> goal;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Description
{
Description() = default;
Description(const Description &other) = delete;
Description &operator=(const Description &&other) = delete;
Description(Description &&other) = default;
Description &operator=(Description &&other) = default;
DomainPointer domain;
std::experimental::optional<ProblemPointer> problem;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,230 @@
#ifndef __PDDL__NORMALIZED_AST_FORWARD_H
#define __PDDL__NORMALIZED_AST_FORWARD_H
#include <pddl/AST.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Normalized AST Forward Declarations
//
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace normalizedAST
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////////////////////////////////////////
using ast::Constant;
using ast::ConstantPointer;
using ast::ConstantDeclaration;
using ast::ConstantDeclarationPointer;
using ast::ConstantDeclarations;
using ast::PrimitiveTypePointer;
using ast::PrimitiveType;
using ast::PrimitiveTypePointer;
using ast::PrimitiveTypes;
using ast::PrimitiveTypeDeclaration;
using ast::PrimitiveTypeDeclarationPointer;
using ast::PrimitiveTypeDeclarations;
using ast::Variable;
using ast::VariablePointer;
using ast::Variables;
using ast::VariableDeclaration;
using ast::VariableDeclarationPointer;
using ast::VariableDeclarations;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Compounds
////////////////////////////////////////////////////////////////////////////////////////////////////
struct DerivedPredicate;
using DerivedPredicatePointer = std::unique_ptr<DerivedPredicate>;
using DerivedPredicates = std::vector<DerivedPredicatePointer>;
struct DerivedPredicateDeclaration;
using DerivedPredicateDeclarationPointer = std::unique_ptr<DerivedPredicateDeclaration>;
using DerivedPredicateDeclarations = std::vector<DerivedPredicateDeclarationPointer>;
using ast::Predicate;
using ast::PredicatePointer;
using ast::Predicates;
using ast::PredicateDeclaration;
using ast::PredicateDeclarationPointer;
using ast::PredicateDeclarations;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
using ast::And;
using ast::AndPointer;
using ast::At;
using ast::AtPointer;
using ast::Either;
using ast::EitherPointer;
using ast::Exists;
using ast::ExistsPointer;
using ast::ForAll;
using ast::ForAllPointer;
using ast::Not;
using ast::NotPointer;
using ast::Or;
using ast::OrPointer;
using ast::When;
using ast::WhenPointer;
////////////////////////////////////////////////////////////////////////////////////////////////////
// PDDL Structure
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Action;
using ActionPointer = std::unique_ptr<Action>;
using Actions = std::vector<ActionPointer>;
struct Description;
using DescriptionPointer = std::unique_ptr<Description>;
struct Domain;
using DomainPointer = std::unique_ptr<Domain>;
struct InitialState;
struct Problem;
using ProblemPointer = std::unique_ptr<Problem>;
enum class Requirement;
using Requirements = std::vector<Requirement>;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Variants
////////////////////////////////////////////////////////////////////////////////////////////////////
using ast::Term;
using ast::Terms;
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace detail
{
using AtomicFormulaT = Variant<
DerivedPredicatePointer,
PredicatePointer>;
}
class AtomicFormula : public detail::AtomicFormulaT
{
AtomicFormula() = delete;
using detail::AtomicFormulaT::AtomicFormulaT;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace detail
{
using LiteralT = Variant<
AtomicFormula,
NotPointer<AtomicFormula>>;
}
class Literal : public detail::LiteralT
{
Literal() = delete;
using detail::LiteralT::LiteralT;
};
using Literals = std::vector<Literal>;
////////////////////////////////////////////////////////////////////////////////////////////////////
class Precondition;
namespace detail
{
using PreconditionT = Variant<
Literal,
AndPointer<Literal>>;
}
class Precondition : public detail::PreconditionT
{
Precondition() = delete;
using detail::PreconditionT::PreconditionT;
};
using Preconditions = std::vector<Precondition>;
////////////////////////////////////////////////////////////////////////////////////////////////////
class DerivedPredicatePrecondition;
namespace detail
{
using DerivedPredicatePreconditionT = Variant<
Literal,
AndPointer<Literal>,
OrPointer<Literal>>;
}
class DerivedPredicatePrecondition : public detail::DerivedPredicatePreconditionT
{
DerivedPredicatePrecondition() = delete;
using detail::DerivedPredicatePreconditionT::DerivedPredicatePreconditionT;
};
using DerivedPredicatePreconditions = std::vector<DerivedPredicatePrecondition>;
////////////////////////////////////////////////////////////////////////////////////////////////////
class ConditionalEffect;
namespace detail
{
using ConditionalEffectT = Variant<
Literal,
AndPointer<Literal>>;
}
class ConditionalEffect : public detail::ConditionalEffectT
{
ConditionalEffect() = delete;
using detail::ConditionalEffectT::ConditionalEffectT;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
class Effect;
namespace detail
{
using EffectT = Variant<
Literal,
AndPointer<Effect>,
ForAllPointer<Effect>,
WhenPointer<Precondition, ConditionalEffect>>;
}
class Effect : public detail::EffectT
{
Effect() = delete;
using detail::EffectT::EffectT;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
using Fact = Literal;
using Facts = std::vector<Fact>;
////////////////////////////////////////////////////////////////////////////////////////////////////
using Goal = Precondition;
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,358 @@
#ifndef __PDDL__NORMALIZED_AST_OUTPUT_H
#define __PDDL__NORMALIZED_AST_OUTPUT_H
#include <colorlog/ColorStream.h>
#include <colorlog/Formatting.h>
#include <pddl/ASTOutput.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/OutputUtils.h>
#include <pddl/detail/parsing/Requirement.h>
namespace pddl
{
namespace normalizedAST
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Output
//
////////////////////////////////////////////////////////////////////////////////////////////////////
using ast::print;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const DerivedPredicate &derivedPredicate, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const DerivedPredicateDeclaration &derivedPredicateDeclaration, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Action &action, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Domain &domain, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const InitialState &initialState, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Problem &problem, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Requirement &requirement, pddl::detail::PrintContext &printContext);
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Description &description, pddl::detail::PrintContext &printContext);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Compounds
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const DerivedPredicate &derivedPredicate, pddl::detail::PrintContext &printContext)
{
// TODO: implement correctly
stream << "(" << pddl::detail::Identifier(derivedPredicate.declaration->name);
for (const auto &argument : derivedPredicate.arguments)
{
stream << " ";
print(stream, argument, printContext);
}
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const DerivedPredicateDeclaration &derivedPredicateDeclaration, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword(":derived-predicate") << " " << pddl::detail::Identifier(derivedPredicateDeclaration.name);
printContext.indentationLevel++;
if (!derivedPredicateDeclaration.parameters.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":parameters");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(";
for (const auto &parameter : derivedPredicateDeclaration.parameters)
{
if (&parameter != &derivedPredicateDeclaration.parameters.front())
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, *parameter, printContext);
}
stream << ")";
printContext.indentationLevel--;
}
if (!derivedPredicateDeclaration.existentialParameters.empty())
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":exists");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
stream << "(";
for (const auto &parameter : derivedPredicateDeclaration.existentialParameters)
{
if (parameter.get() != derivedPredicateDeclaration.existentialParameters.front().get())
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, *parameter, printContext);
}
stream << ")";
printContext.indentationLevel--;
}
if (derivedPredicateDeclaration.precondition)
{
pddl::detail::printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":precondition");
printContext.indentationLevel++;
pddl::detail::printIndentedNewline(stream, printContext);
print(stream, derivedPredicateDeclaration.precondition.value(), printContext);
printContext.indentationLevel--;
}
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// PDDL Structure
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Action &action, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword(":action") << " " << pddl::detail::Identifier(action.name);
printContext.indentationLevel++;
if (!action.parameters.empty())
{
printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":parameters");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
stream << "(";
print(stream, action.parameters, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (action.precondition)
{
printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":precondition");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
print(stream, action.precondition.value(), printContext);
printContext.indentationLevel--;
}
if (action.effect)
{
printIndentedNewline(stream, printContext);
stream << colorlog::Keyword(":effect");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
print(stream, action.effect.value(), printContext);
printContext.indentationLevel--;
}
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Domain &domain, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword("define") << " (" << colorlog::Keyword("domain") << " " << pddl::detail::Identifier(domain.name) << ")";
printContext.indentationLevel++;
if (!domain.types.empty())
{
printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":types");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
print(stream, domain.types, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!domain.constants.empty())
{
printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":constants");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
print(stream, domain.constants, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!domain.predicates.empty())
{
printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":predicates");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
print(stream, domain.predicates, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!domain.derivedPredicates.empty())
{
printIndentedNewline(stream, printContext);
print(stream, domain.derivedPredicates, printContext);
}
if (!domain.actions.empty())
{
printIndentedNewline(stream, printContext);
print(stream, domain.actions, printContext);
}
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const InitialState &initialState, pddl::detail::PrintContext &printContext)
{
assert(!initialState.facts.empty());
stream << "(" << colorlog::Keyword(":init");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
print(stream, initialState.facts, printContext);
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Problem &problem, pddl::detail::PrintContext &printContext)
{
stream << "(" << colorlog::Keyword("define") << " (" << colorlog::Keyword("problem") << " " << pddl::detail::Identifier(problem.name) << ")";
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":domain") << " " << pddl::detail::Identifier(problem.domain->name) << ")";
if (!problem.derivedPredicates.empty())
{
printIndentedNewline(stream, printContext);
print(stream, problem.derivedPredicates, printContext);
}
if (!problem.objects.empty())
{
printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":objects");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
print(stream, problem.objects, printContext);
stream << ")";
printContext.indentationLevel--;
}
if (!problem.initialState.facts.empty())
{
printIndentedNewline(stream, printContext);
print(stream, problem.initialState, printContext);
}
if (problem.goal)
{
printIndentedNewline(stream, printContext);
stream << "(" << colorlog::Keyword(":goal");
printContext.indentationLevel++;
printIndentedNewline(stream, printContext);
print(stream, problem.goal.value(), printContext);
stream << ")";
printContext.indentationLevel--;
}
printContext.indentationLevel--;
return (stream << ")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &print(colorlog::ColorStream &stream, const Description &description, pddl::detail::PrintContext &printContext)
{
print(stream, *description.domain, printContext);
stream << std::endl;
if (description.problem)
{
stream << std::endl;
print(stream, *description.problem.value(), printContext);
stream << std::endl;
}
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &operator<<(colorlog::ColorStream &stream, const Description &description)
{
pddl::detail::PrintContext printContext;
return print(stream, description, printContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,24 @@
#ifndef __PDDL__PARSE_H
#define __PDDL__PARSE_H
#include <experimental/optional>
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Parse
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Description parseDescription(Context &context);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,52 @@
#ifndef __PDDL__TOKENIZER_H
#define __PDDL__TOKENIZER_H
#include <iostream>
#include <tokenize/Tokenizer.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tokenizer
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct PDDLTokenizerPolicy
{
static char transformCharacter(char c) noexcept
{
return std::tolower(c);
}
static bool isWhiteSpaceCharacter(char c)
{
return std::iswspace(c);
}
static bool isBlankCharacter(char c)
{
return std::isblank(c);
}
static bool isIdentifierCharacter(char c)
{
return c != '?'
&& c != '('
&& c != ')'
&& c != ';'
&& std::isgraph(c);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
using Tokenizer = tokenize::Tokenizer<PDDLTokenizerPolicy>;
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -0,0 +1,20 @@
#ifndef __PDDL__VARIANT_H
#define __PDDL__VARIANT_H
#include <mapbox/variant.hpp>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class... Types>
using Variant = mapbox::util::variant<Types...>;
////////////////////////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////////////////////////
#endif

View File

@@ -0,0 +1,48 @@
#ifndef __PDDL__DETAIL__AST_CONTEXT_H
#define __PDDL__DETAIL__AST_CONTEXT_H
#include <pddl/AST.h>
#include <pddl/detail/VariableStack.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ASTContext
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct ASTContext
{
ASTContext(ast::Description &description)
: domain{description.domain.get()},
problem{description.problem.value() ? std::experimental::optional<ast::Problem *>(description.problem.value().get()) : std::experimental::nullopt}
{
}
ASTContext(ast::Domain &domain)
: domain{&domain}
{
}
ASTContext(ast::Problem &problem)
: domain{problem.domain},
problem{&problem}
{
}
ast::Domain *domain;
std::experimental::optional<ast::Problem *> problem;
VariableStack variables;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,165 @@
#ifndef __PDDL__DETAIL__AST_COPY_H
#define __PDDL__DETAIL__AST_COPY_H
#include <pddl/AST.h>
#include <pddl/Variant.h>
namespace pddl
{
namespace ast
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ASTCopy
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////////////////////////////////////////
inline Constant deepCopy(Constant &other);
inline PrimitiveType deepCopy(PrimitiveType &other);
inline Variable deepCopy(Variable &other);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions: Base Classes
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class ArgumentLeft, class ArgumentRight = ArgumentLeft>
inline Derived deepCopy(Binary<Derived, ArgumentLeft, ArgumentRight> &other);
template<class Derived, class Argument>
inline Derived deepCopy(NAry<Derived, Argument> &other);
template<class Derived, class Argument>
inline Derived deepCopy(Quantified<Derived, Argument> &other);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
inline At<Argument> deepCopy(At<Argument> &other);
template<class Argument>
inline Not<Argument> deepCopy(Not<Argument> &other);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Variants
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ast::Type deepCopy(ast::Type &other);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Unique Pointers
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
std::unique_ptr<T> deepCopy(std::unique_ptr<T> &other);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////////////////////////////////////////
Constant deepCopy(Constant &other)
{
return Constant(other.declaration);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
PrimitiveType deepCopy(PrimitiveType &other)
{
return PrimitiveType(other.declaration);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Variable deepCopy(Variable &other)
{
return Variable(other.declaration);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions: Base Classes
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class ArgumentLeft, class ArgumentRight>
Derived deepCopy(Binary<Derived, ArgumentLeft, ArgumentRight> &other)
{
auto argumentLeft{deepCopy(other.argumentLeft)};
auto argumentRight{deepCopy(other.argumentRight)};
return Binary<Derived, ArgumentLeft, ArgumentRight>(std::move(argumentLeft), std::move(argumentRight));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class Argument>
Derived deepCopy(NAry<Derived, Argument> &other)
{
typename Derived::Arguments arguments;
arguments.reserve(other.arguments.size());
for (auto &argument : other.arguments)
arguments.emplace_back(deepCopy(argument));
return Derived(std::move(arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, class Argument>
Derived deepCopy(Quantified<Derived, Argument> &other)
{
auto argument{deepCopy(other.argument)};
return Quantified<Derived, Argument>(std::move(argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
At<Argument> deepCopy(At<Argument> &other)
{
auto argument{deepCopy(other.argument)};
return At<Argument>(other.timePoint, std::move(argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
Not<Argument> deepCopy(Not<Argument> &other)
{
auto argument{deepCopy(other.argument)};
return Not<Argument>(std::move(argument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Variants
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Type deepCopy(ast::Type &other)
{
return other.match([](auto &x) -> ast::Type {return deepCopy(x);});
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Unique Pointers
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
std::unique_ptr<T> deepCopy(std::unique_ptr<T> &other)
{
return std::make_unique<T>(deepCopy(*other));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,117 @@
#ifndef __PDDL__DETAIL__OUTPUT_UTILS_H
#define __PDDL__DETAIL__OUTPUT_UTILS_H
#include <colorlog/Formatting.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// OutputUtils
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct PrintContext
{
size_t indentationLevel{0};
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Identifier
{
Identifier(const char *content)
: content{content}
{
}
Identifier(const std::string &content)
: content{content.c_str()}
{
}
const char *content;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &operator<<(colorlog::ColorStream &stream, const Identifier &identifier)
{
return (stream
<< colorlog::Format({colorlog::Color::Green, colorlog::FontWeight::Normal})
<< identifier.content << colorlog::ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Type
{
Type(const char *name)
: name{name}
{
}
Type(const std::string &name)
: name{name.c_str()}
{
}
const char *name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &operator<<(colorlog::ColorStream &stream, const Type &type)
{
return (stream
<< colorlog::Format({colorlog::Color::Red, colorlog::FontWeight::Normal})
<< type.name << colorlog::ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Constant
{
Constant(const char *name)
: name{name}
{
}
Constant(const std::string &name)
: name{name.c_str()}
{
}
const char *name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &operator<<(colorlog::ColorStream &stream, const Constant &constant)
{
return (stream
<< colorlog::Format({colorlog::Color::Yellow, colorlog::FontWeight::Normal})
<< constant.name << colorlog::ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline colorlog::ColorStream &printIndentedNewline(colorlog::ColorStream &stream, detail::PrintContext &printContext)
{
stream << std::endl;
for (size_t i = 0; i < printContext.indentationLevel; i++)
stream << "\t";
return stream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,31 @@
#ifndef __PDDL__DETAIL__REQUIREMENTS_H
#define __PDDL__DETAIL__REQUIREMENTS_H
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Requirements
//
////////////////////////////////////////////////////////////////////////////////////////////////////
bool hasRequirement(const ast::Domain &domain, ast::Requirement requirement);
bool hasRequirement(const ast::Problem &problem, ast::Requirement requirement);
bool hasRequirement(const ASTContext &astContext, ast::Requirement requirement);
void checkRequirement(ast::Domain &domain, ast::Requirement requirement, Context &context);
void checkRequirement(ast::Problem &problem, ast::Requirement requirement, Context &context);
void checkRequirement(ASTContext &astContext, ast::Requirement requirement, Context &context);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,34 @@
#ifndef __PDDL__DETAIL__SIGNATURE_MATCHING_H
#define __PDDL__DETAIL__SIGNATURE_MATCHING_H
#include <string>
#include <pddl/AST.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SignatureMatching
//
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::PrimitiveTypeDeclaration &lhs, const ast::PrimitiveTypeDeclaration &rhs);
bool matches(const ast::Either<ast::PrimitiveTypePointer> &lhs, const ast::PrimitiveTypeDeclaration &rhs);
bool matches(const ast::PrimitiveTypeDeclaration &lhs, const ast::Either<ast::PrimitiveTypePointer> &rhs);
bool matches(const ast::Either<ast::PrimitiveTypePointer> &lhs, const ast::Either<ast::PrimitiveTypePointer> &rhs);
bool matches(const ast::VariableDeclaration &lhs, const std::experimental::optional<ast::Type> &rhs);
bool matches(const ast::ConstantDeclaration &lhs, const std::experimental::optional<ast::Type> &rhs);
bool matches(const ast::Term &lhs, const std::experimental::optional<ast::Type> &rhs);
bool matches(const std::string &predicateName, const ast::Predicate::Arguments &predicateArguments, const ast::PredicateDeclaration &predicateDeclaration);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,38 @@
#ifndef __PDDL__DETAIL__VARIABLE_STACK_H
#define __PDDL__DETAIL__VARIABLE_STACK_H
#include <pddl/ASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// VariableStack
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class VariableStack
{
public:
using Layer = ast::VariableDeclarations *;
public:
void push(Layer layer);
void pop();
std::experimental::optional<ast::VariableDeclaration *> findVariableDeclaration(const std::string &variableName) const;
bool contains(const ast::VariableDeclaration &variableDeclaration) const;
private:
std::vector<Layer> m_layers;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__ACTION_H
#define __PDDL__DETAIL__NORMALIZATION__ACTION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Action
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::ActionPointer normalize(ast::ActionPointer &&domain, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__ATOMIC_FORMULA_H
#define __PDDL__DETAIL__NORMALIZATION__ATOMIC_FORMULA_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// AtomicFormula
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::AtomicFormula normalize(ast::AtomicFormula &&atomicFormula);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,121 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__COLLECT_FREE_VARIABLES_H
#define __PDDL__DETAIL__NORMALIZATION__COLLECT_FREE_VARIABLES_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedASTForward.h>
#include <pddl/detail/VariableStack.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Collect Free Variables
//
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Variant>
void collectFreeVariables(const Variant &variant, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
variant.match([&](const auto &x){collectFreeVariables(x, freeVariables, variableStack);});
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline void collectFreeVariables(const ast::ConstantPointer &, std::vector<normalizedAST::VariableDeclaration *> &, VariableStack &)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline void collectFreeVariables(const ast::VariablePointer &variable, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
if (variableStack.contains(*variable->declaration))
return;
const auto matchingFreeVariable = std::find(freeVariables.cbegin(), freeVariables.cend(), variable->declaration);
if (matchingFreeVariable != freeVariables.cend())
return;
freeVariables.emplace_back(variable->declaration);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
inline void collectFreeVariables(const ast::PredicatePointer &predicate, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
for (const auto &argument : predicate->arguments)
collectFreeVariables(argument, freeVariables, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
void collectFreeVariables(const ast::AndPointer<Argument> &and_, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
for (const auto &argument : and_->arguments)
collectFreeVariables(argument, freeVariables, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
void collectFreeVariables(const ast::ExistsPointer<Argument> &exists, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
variableStack.push(&exists->parameters);
collectFreeVariables(exists->argument, freeVariables, variableStack);
variableStack.pop();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
void collectFreeVariables(const ast::ForAllPointer<Argument> &forAll, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
variableStack.push(&forAll->parameters);
collectFreeVariables(forAll->argument, freeVariables, variableStack);
variableStack.pop();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
void collectFreeVariables(const ast::ImplyPointer<Argument> &imply, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
collectFreeVariables(imply->argumentLeft, freeVariables, variableStack);
collectFreeVariables(imply->argumentRight, freeVariables, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
void collectFreeVariables(const ast::NotPointer<Argument> &not_, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
collectFreeVariables(not_->argument, freeVariables, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
void collectFreeVariables(const ast::OrPointer<Argument> &or_, std::vector<normalizedAST::VariableDeclaration *> &freeVariables, VariableStack &variableStack)
{
for (const auto &argument : or_->arguments)
collectFreeVariables(argument, freeVariables, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__CONDITIONAL_EFFECT_H
#define __PDDL__DETAIL__NORMALIZATION__CONDITIONAL_EFFECT_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ConditionalEffect
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::ConditionalEffect normalize(ast::ConditionalEffect &&conditionalEffect);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__DESCRIPTION_H
#define __PDDL__DETAIL__NORMALIZATION__DESCRIPTION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Description
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Description normalize(ast::Description &&description);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__DOMAIN_H
#define __PDDL__DETAIL__NORMALIZATION__DOMAIN_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Domain
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::DomainPointer normalize(ast::DomainPointer &&domain);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__EFFECT_H
#define __PDDL__DETAIL__NORMALIZATION__EFFECT_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Effect normalize(ast::Effect &&effect, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__FACT_H
#define __PDDL__DETAIL__NORMALIZATION__FACT_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Fact
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Fact normalize(ast::Fact &&fact);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__INITIAL_STATE_H
#define __PDDL__DETAIL__NORMALIZATION__INITIAL_STATE_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// InitialState
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::InitialState normalize(ast::InitialState &&initialState);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__LITERAL_H
#define __PDDL__DETAIL__NORMALIZATION__LITERAL_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Literal
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalize(ast::Literal &&literal);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__PRECONDITION_H
#define __PDDL__DETAIL__NORMALIZATION__PRECONDITION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Precondition
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Precondition normalize(ast::Precondition &&precondition, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__PROBLEM_H
#define __PDDL__DETAIL__NORMALIZATION__PROBLEM_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Problem
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::ProblemPointer normalize(ast::ProblemPointer &&problem, normalizedAST::Domain *domain);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__NORMALIZATION__REDUCTION_H
#define __PDDL__DETAIL__NORMALIZATION__REDUCTION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/NormalizedASTForward.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Reduction
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void reduce(ast::Precondition &precondition);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,50 @@
#ifndef __PDDL__DETAIL__PARSING__ACTION_H
#define __PDDL__DETAIL__PARSING__ACTION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Action
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class ActionParser
{
public:
ActionParser(Context &context, ast::Domain &domain);
ast::ActionPointer parse();
private:
void findSections(ast::Action &action);
void parseParameterSection(ast::Action &action);
void parsePreconditionSection(ast::Action &action);
void parseEffectSection(ast::Action &action);
// For compatibility with old PDDL versions
void parseVarsSection(ast::Action &action);
Context &m_context;
ast::Domain &m_domain;
tokenize::StreamPosition m_parametersPosition;
tokenize::StreamPosition m_preconditionPosition;
tokenize::StreamPosition m_effectPosition;
// For compatibility with old PDDL versions
tokenize::StreamPosition m_varsPosition;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,27 @@
#ifndef __PDDL__DETAIL__PARSING__ATOMIC_FORMULA_H
#define __PDDL__DETAIL__PARSING__ATOMIC_FORMULA_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
#include <pddl/detail/VariableStack.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// AtomicFormula
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::AtomicFormula> parseAtomicFormula(Context &context, ASTContext &astContext, VariableStack &variableStack);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,27 @@
#ifndef __PDDL__DETAIL__PARSING__CONSTANT_H
#define __PDDL__DETAIL__PARSING__CONSTANT_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Constant
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::ConstantPointer> testParsingConstant(Context &context, ASTContext &astContext);
ast::ConstantPointer parseConstant(Context &context, ASTContext &astContext);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__PARSING__CONSTANT_DECLARATION_H
#define __PDDL__DETAIL__PARSING__CONSTANT_DECLARATION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ConstantDeclaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddConstantDeclarations(Context &context, ast::Domain &domain);
void parseAndAddConstantDeclarations(Context &context, ast::Problem &problem);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,37 @@
#ifndef __PDDL__DETAIL__PARSING__DESCRIPTION_H
#define __PDDL__DETAIL__PARSING__DESCRIPTION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Description
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class DescriptionParser
{
public:
DescriptionParser(Context &context);
ast::Description parse();
private:
void findSections();
Context &m_context;
tokenize::StreamPosition m_domainPosition;
tokenize::StreamPosition m_problemPosition;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,48 @@
#ifndef __PDDL__DETAIL__PARSING__DOMAIN_H
#define __PDDL__DETAIL__PARSING__DOMAIN_H
#include <pddl/AST.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Domain
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class DomainParser
{
public:
DomainParser(Context &context);
ast::DomainPointer parse();
private:
void findSections(ast::Domain &domain);
void parseRequirementSection(ast::Domain &domain);
void computeDerivedRequirements(ast::Domain &domain);
void parseTypeSection(ast::Domain &domain);
void parseConstantSection(ast::Domain &domain);
void parsePredicateSection(ast::Domain &domain);
void parseActionSection(ast::Domain &domain);
Context &m_context;
tokenize::StreamPosition m_requirementsPosition;
tokenize::StreamPosition m_typesPosition;
tokenize::StreamPosition m_constantsPosition;
tokenize::StreamPosition m_predicatesPosition;
std::vector<tokenize::StreamPosition> m_actionPositions;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,27 @@
#ifndef __PDDL__DETAIL__PARSING__EFFECT_H
#define __PDDL__DETAIL__PARSING__EFFECT_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
#include <pddl/detail/VariableStack.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Effect> parseEffect(Context &context, ASTContext &astContext, VariableStack &variableStack);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,252 @@
#ifndef __PDDL__DETAIL__PARSING__EXPRESSIONS_H
#define __PDDL__DETAIL__PARSING__EXPRESSIONS_H
#include <pddl/AST.h>
#include <pddl/Context.h>
#include <pddl/Exception.h>
#include <pddl/detail/ASTContext.h>
#include <pddl/detail/VariableStack.h>
#include <pddl/detail/parsing/VariableDeclaration.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Expressions
//
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::AndPointer<Argument>> parseAnd(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument);
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::AtPointer<Argument>> parseAt(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument);
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::EitherPointer<Argument>> parseEither(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument);
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::ExistsPointer<Argument>> parseExists(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument);
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::ForAllPointer<Argument>> parseForAll(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument);
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::ImplyPointer<Argument>> parseImply(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument);
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::NotPointer<Argument>> parseNot(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument);
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::OrPointer<Argument>> parseOr(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument);
template<typename ArgumentLeft, typename ArgumentRight, typename ArgumentLeftParser, typename ArgumentRightParser>
std::experimental::optional<ast::WhenPointer<ArgumentLeft, ArgumentRight>> parseWhen(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentLeftParser parseArgumentLeft, ArgumentRightParser parseArgumentRight);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions: Base Classes
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, typename ArgumentLeftParser, typename ArgumentRightParser>
std::experimental::optional<std::unique_ptr<Derived>> parseBinary(Context &context,
ASTContext &astContext, VariableStack &variableStack, ArgumentLeftParser parseArgumentLeft,
ArgumentRightParser parseArgumentRight)
{
auto &tokenizer = context.tokenizer;
const auto position = tokenizer.position();
if (!tokenizer.testAndSkip<std::string>("(")
|| !tokenizer.testIdentifierAndSkip(Derived::Identifier))
{
tokenizer.seek(position);
return std::experimental::nullopt;
}
tokenizer.skipWhiteSpace();
// Parse arguments of the expression
auto argumentLeft = parseArgumentLeft(context, astContext, variableStack);
if (!argumentLeft)
throw ParserException(tokenizer.location(), "could not parse argument of “" + std::string(Derived::Identifier) + "” expression");
auto argumentRight = parseArgumentRight(context, astContext, variableStack);
if (!argumentRight)
throw ParserException(tokenizer.location(), "could not parse argument of “" + std::string(Derived::Identifier) + "” expression");
tokenizer.expect<std::string>(")");
return std::make_unique<Derived>(std::move(argumentLeft.value()), std::move(argumentRight.value()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, typename ArgumentParser>
std::experimental::optional<std::unique_ptr<Derived>> parseNAry(Context &context,
ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
auto &tokenizer = context.tokenizer;
const auto position = tokenizer.position();
if (!tokenizer.testAndSkip<std::string>("(")
|| !tokenizer.testIdentifierAndSkip(Derived::Identifier))
{
tokenizer.seek(position);
return std::experimental::nullopt;
}
typename Derived::Arguments arguments;
tokenizer.skipWhiteSpace();
// Parse arguments of the expression
while (tokenizer.currentCharacter() != ')')
{
auto argument = parseArgument(context, astContext, variableStack);
if (!argument)
throw ParserException(tokenizer.location(), "could not parse argument of “" + std::string(Derived::Identifier) + "” expression");
arguments.emplace_back(std::move(argument.value()));
tokenizer.skipWhiteSpace();
}
if (arguments.empty())
context.warningCallback(tokenizer.location(), "" + std::string(Derived::Identifier) + "” expressions should not be empty");
tokenizer.expect<std::string>(")");
return std::make_unique<Derived>(std::move(arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Derived, typename ArgumentParser>
std::experimental::optional<std::unique_ptr<Derived>> parseQuantified(Context &context,
ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
auto &tokenizer = context.tokenizer;
const auto position = tokenizer.position();
if (!tokenizer.testAndSkip<std::string>("(")
|| !tokenizer.testIdentifierAndSkip(Derived::Identifier))
{
tokenizer.seek(position);
return std::experimental::nullopt;
}
// Parse variable list
tokenizer.expect<std::string>("(");
auto parameters = parseVariableDeclarations(context, *astContext.domain);
tokenizer.expect<std::string>(")");
// Push newly parsed variables to the stack
variableStack.push(&parameters);
// Parse argument of the expression
auto argument = parseArgument(context, astContext, variableStack);
if (!argument)
throw ParserException(tokenizer.location(), "could not parse argument of “" + std::string(Derived::Identifier) + "” expression");
// Clean up variable stack
variableStack.pop();
tokenizer.expect<std::string>(")");
return std::make_unique<Derived>(std::move(parameters), std::move(argument.value()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::AndPointer<Argument>> parseAnd(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
return parseNAry<ast::And<Argument>, ArgumentParser>(context, astContext, variableStack, parseArgument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::EitherPointer<Argument>> parseEither(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
return parseNAry<ast::Either<Argument>, ArgumentParser>(context, astContext, variableStack, parseArgument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::ExistsPointer<Argument>> parseExists(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
return parseQuantified<ast::Exists<Argument>, ArgumentParser>(context, astContext, variableStack, parseArgument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::ForAllPointer<Argument>> parseForAll(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
return parseQuantified<ast::ForAll<Argument>, ArgumentParser>(context, astContext, variableStack, parseArgument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::ImplyPointer<Argument>> parseImply(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
return parseBinary<ast::Imply<Argument>, ArgumentParser, ArgumentParser>(context, astContext, variableStack, parseArgument, parseArgument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::NotPointer<Argument>> parseNot(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
auto &tokenizer = context.tokenizer;
const auto position = tokenizer.position();
if (!tokenizer.testAndSkip<std::string>("(")
|| !tokenizer.testIdentifierAndSkip("not"))
{
tokenizer.seek(position);
return std::experimental::nullopt;
}
tokenizer.skipWhiteSpace();
// Parse argument
auto argument = parseArgument(context, astContext, variableStack);
if (!argument)
throw ParserException(tokenizer.location(), "could not parse argument of “not” expression");
tokenizer.expect<std::string>(")");
return std::make_unique<ast::Not<Argument>>(std::move(argument.value()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename Argument, typename ArgumentParser>
std::experimental::optional<ast::OrPointer<Argument>> parseOr(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument)
{
return parseNAry<ast::Or<Argument>, ArgumentParser>(context, astContext, variableStack, parseArgument);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename ArgumentLeft, typename ArgumentRight, typename ArgumentLeftParser, typename ArgumentRightParser>
std::experimental::optional<ast::WhenPointer<ArgumentLeft, ArgumentRight>> parseWhen(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentLeftParser parseArgumentLeft, ArgumentRightParser parseArgumentRight)
{
return parseBinary<ast::When<ArgumentLeft, ArgumentRight>, ArgumentLeftParser, ArgumentRightParser>(context, astContext, variableStack, parseArgumentLeft, parseArgumentRight);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,27 @@
#ifndef __PDDL__DETAIL__PARSING__FACT_H
#define __PDDL__DETAIL__PARSING__FACT_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
#include <pddl/detail/VariableStack.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Fact
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Fact> parseFact(Context &context, ASTContext &astContext, VariableStack &variableStack);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __PDDL__DETAIL__PARSING__INITIAL_STATE_H
#define __PDDL__DETAIL__PARSING__INITIAL_STATE_H
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// InitialState
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::InitialState parseInitialState(Context &context, ASTContext &astContext, VariableStack &variableStack);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,41 @@
#ifndef __PDDL__DETAIL__PARSER_H
#define __PDDL__DETAIL__PARSER_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Parser
//
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
struct Parser
{
};
template<class T, typename... ArgumentParser>
std::experimental::optional<T> parse(Context &context, ASTContext &astContext, ArgumentParser... argumentParsers)
{
return detail::Parser<T>().parse(context, astContext, argumentParsers...);
}
template<class T>
std::experimental::optional<T> parse(Context &context, ASTContext &astContext)
{
return detail::Parser<T>().parse(context, astContext);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,28 @@
#ifndef __PDDL__DETAIL__PARSING__PRECONDITION_H
#define __PDDL__DETAIL__PARSING__PRECONDITION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
#include <pddl/detail/VariableStack.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Precondition
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Precondition> parsePrecondition(Context &context, ASTContext &astContext, VariableStack &variableStack);
std::experimental::optional<ast::Precondition> parsePreconditionBody(Context &context, ASTContext &astContext, VariableStack &variableStack);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,28 @@
#ifndef __PDDL__DETAIL__PARSING__PREDICATE_H
#define __PDDL__DETAIL__PARSING__PREDICATE_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/detail/ASTContext.h>
#include <pddl/detail/VariableStack.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Predicate
//
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: rename consistently
std::experimental::optional<ast::PredicatePointer> parsePredicate(Context &context, ASTContext &astContext, VariableStack &variableStack);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __PDDL__DETAIL__PARSING__PREDICATE_DECLARATION_H
#define __PDDL__DETAIL__PARSING__PREDICATE_DECLARATION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PredicateDeclaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddPredicateDeclarations(Context &context, ast::Domain &domain);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __PDDL__DETAIL__PARSING__PRIMITIVE_TYPE_H
#define __PDDL__DETAIL__PARSING__PRIMITIVE_TYPE_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PrimitiveType
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::PrimitiveTypePointer parsePrimitiveType(Context &context, ast::Domain &domain);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __PDDL__DETAIL__PARSING__PRIMITIVE_TYPE_DECLARATION_H
#define __PDDL__DETAIL__PARSING__PRIMITIVE_TYPE_DECLARATION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PrimitiveTypeDeclaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddPrimitiveTypeDeclarations(Context &context, ast::Domain &domain);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,49 @@
#ifndef __PDDL__DETAIL__PARSING__PROBLEM_H
#define __PDDL__DETAIL__PARSING__PROBLEM_H
#include <pddl/AST.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Problem
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class ProblemParser
{
public:
ProblemParser(Context &context, ast::Domain &domain);
ast::ProblemPointer parse();
private:
void findSections(ast::Problem &problem);
void parseDomainSection(ast::Problem &problem);
void parseRequirementSection(ast::Problem &problem);
void computeDerivedRequirements(ast::Problem &problem);
void parseObjectSection(ast::Problem &problem);
void parseInitialStateSection(ast::Problem &problem);
void parseGoalSection(ast::Problem &problem);
Context &m_context;
ast::Domain &m_domain;
tokenize::StreamPosition m_domainPosition;
tokenize::StreamPosition m_requirementsPosition;
tokenize::StreamPosition m_objectsPosition;
tokenize::StreamPosition m_initialStatePosition;
tokenize::StreamPosition m_goalPosition;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__PARSING__REQUIREMENT_H
#define __PDDL__DETAIL__PARSING__REQUIREMENT_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Requirement
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Requirement> parseRequirement(Context &context);
const char *toString(const ast::Requirement &requirement);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __PDDL__DETAIL__PARSING__TYPE_H
#define __PDDL__DETAIL__PARSING__TYPE_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Type
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Type parseType(Context &context, ast::Domain &domain);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__PARSING__UNSUPPORTED_H
#define __PDDL__DETAIL__PARSING__UNSUPPORTED_H
#include <pddl/Context.h>
#include <pddl/Exception.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Unsupported
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ParserException exceptUnsupportedExpression(tokenize::StreamPosition position, Context &context);
ParserException exceptUnsupportedSection(tokenize::StreamPosition position, Context &context);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,44 @@
#ifndef __PDDL__DETAIL__PARSE_UTILS_H
#define __PDDL__DETAIL__PARSE_UTILS_H
#include <pddl/Tokenizer.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ParseUtils
//
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: refactor
inline void skipSection(Tokenizer &tokenizer)
{
size_t openParentheses = 1;
while (true)
{
const auto character = tokenizer.currentCharacter();
tokenizer.advance();
if (character == '(')
openParentheses++;
else if (character == ')')
{
openParentheses--;
if (openParentheses == 0)
return;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,28 @@
#ifndef __PDDL__DETAIL__PARSING__VARIABLE_H
#define __PDDL__DETAIL__PARSING__VARIABLE_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
#include <pddl/detail/VariableStack.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Variable
//
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: find consistent naming scheme
std::experimental::optional<ast::VariablePointer> testParsingVariable(Context &context, VariableStack &variableStack);
ast::VariablePointer parseVariable(Context &context, VariableStack &variableStack);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef __PDDL__DETAIL__PARSING__VARIABLE_DECLARATION_H
#define __PDDL__DETAIL__PARSING__VARIABLE_DECLARATION_H
#include <pddl/ASTForward.h>
#include <pddl/Context.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// VariableDeclaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddVariableDeclarations(Context &context, ast::Domain &domain, ast::VariableDeclarations &variableDeclarations);
ast::VariableDeclarations parseVariableDeclarations(Context &context, ast::Domain &domain);
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@@ -0,0 +1,41 @@
set(target pddl)
file(GLOB core_sources "pddl/*.cpp")
file(GLOB core_headers "../include/pddl/*.h")
file(GLOB detail_sources "pddl/detail/*.cpp")
file(GLOB detail_headers "../include/pddl/detail/*.h")
file(GLOB detail_parsing_sources "pddl/detail/parsing/*.cpp")
file(GLOB detail_parsing_headers "../include/pddl/detail/parsing/*.h")
file(GLOB detail_normalization_sources "pddl/detail/normalization/*.cpp")
file(GLOB detail_normalization_headers "../include/pddl/detail/normalization/*.h")
set(includes
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/../../lib/colorlog/include
${PROJECT_SOURCE_DIR}/../../lib/tokenize/include
${PROJECT_SOURCE_DIR}/../../lib/variant/include
)
set(sources
${core_sources}
${core_headers}
${detail_sources}
${detail_headers}
${detail_parsing_sources}
${detail_parsing_headers}
${detail_normalization_sources}
${detail_normalization_headers}
)
set(libraries
)
add_library(${target} ${sources})
target_include_directories(${target} PRIVATE ${includes})
target_link_libraries(${target} ${libraries})

View File

@@ -0,0 +1,22 @@
#include <pddl/Parse.h>
#include <pddl/AST.h>
#include <pddl/detail/parsing/Description.h>
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Parse
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Description parseDescription(Context &context)
{
return detail::DescriptionParser(context).parse();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}

View File

@@ -0,0 +1,99 @@
#include <pddl/detail/Requirements.h>
#include <algorithm>
#include <pddl/Exception.h>
#include <pddl/detail/parsing/Requirement.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Requirements
//
////////////////////////////////////////////////////////////////////////////////////////////////////
bool hasRequirement(const ast::Domain &domain, ast::Requirement requirement)
{
const auto match = std::find_if(domain.requirements.cbegin(), domain.requirements.cend(),
[&](const auto &declaredRequirement)
{
return declaredRequirement == requirement;
});
return match != domain.requirements.cend();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool hasRequirement(const ast::Problem &problem, ast::Requirement requirement)
{
const auto match = std::find_if(problem.requirements.cbegin(), problem.requirements.cend(),
[&](const auto &declaredRequirement)
{
return declaredRequirement == requirement;
});
if (match != problem.requirements.cend())
return true;
return hasRequirement(problem.domain, requirement);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool hasRequirement(const ASTContext &astContext, ast::Requirement requirement)
{
if (astContext.problem)
return hasRequirement(*astContext.problem.value(), requirement);
return hasRequirement(*astContext.domain, requirement);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void checkRequirement(ast::Domain &domain, ast::Requirement requirement, Context &context)
{
if (hasRequirement(domain, requirement))
return;
if (context.mode == Mode::Compatibility)
context.warningCallback(context.tokenizer.location(), "requirement “" + std::string(toString(requirement)) + "” used but never declared, silently adding requirement");
else
throw ParserException(context.tokenizer.location(), "requirement “" + std::string(toString(requirement)) + "” used but never declared");
domain.requirements.push_back(requirement);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void checkRequirement(ast::Problem &problem, ast::Requirement requirement, Context &context)
{
if (hasRequirement(problem, requirement))
return;
if (context.mode == Mode::Compatibility)
context.warningCallback(context.tokenizer.location(), "requirement “" + std::string(toString(requirement)) + "” used but never declared, silently adding requirement");
else
throw ParserException(context.tokenizer.location(), "requirement “" + std::string(toString(requirement)) + "” used but never declared");
problem.requirements.push_back(requirement);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void checkRequirement(ASTContext &astContext, ast::Requirement requirement, Context &context)
{
if (astContext.problem)
checkRequirement(*astContext.problem.value(), requirement, context);
else
checkRequirement(*astContext.domain, requirement, context);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,140 @@
#include <pddl/detail/SignatureMatching.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SignatureMatching
//
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::PrimitiveTypeDeclaration &lhs, const ast::PrimitiveTypeDeclaration &rhs)
{
// TODO: check if this assumption is correct
// With typing enabled, all objects inherit from “object”
if (rhs.name == "object")
return true;
// Two types match if rhs is lhs or one of its ancestors
if (&lhs == &rhs)
return true;
for (const auto &lhsParentType : lhs.parentTypes)
if (matches(*lhsParentType->declaration, rhs))
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::PrimitiveTypeDeclaration &lhs, const ast::Either<ast::PrimitiveTypePointer> &rhs)
{
for (const auto &rhsType : rhs.arguments)
if (matches(lhs, *rhsType->declaration))
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::Either<ast::PrimitiveTypePointer> &lhs, const ast::PrimitiveTypeDeclaration &rhs)
{
if (lhs.arguments.size() != 1)
return false;
// Strictly speaking, a 1-ary either is identical to its argument
return matches(*lhs.arguments[0]->declaration, rhs);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::Either<ast::PrimitiveTypePointer> &lhs, const ast::Either<ast::PrimitiveTypePointer> &rhs)
{
// All of the types in lhs must have a match in rhs
for (const auto &lhsType : lhs.arguments)
if (!matches(*lhsType->declaration, rhs))
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T>
bool matches(const T &lhs, const ast::Type &rhs)
{
return rhs.match(
[&](const ast::PrimitiveTypePointer &x){return matches(lhs, *x->declaration);},
[&](const ast::EitherPointer<ast::PrimitiveTypePointer> &x){return matches(lhs, *x);});
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::Type &lhs, const ast::Type &rhs)
{
return lhs.match(
[&](const ast::PrimitiveTypePointer &x){return matches(*x->declaration, rhs);},
[&](const ast::EitherPointer<ast::PrimitiveTypePointer> &x){return matches(*x, rhs);});
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::VariableDeclaration &lhs, const std::experimental::optional<ast::Type> &rhs)
{
if (!lhs.type && !rhs)
return true;
// If typing is enabled, all objects have to be typed
assert(lhs.type);
assert(rhs);
return matches(lhs.type.value(), rhs.value());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::ConstantDeclaration &lhs, const std::experimental::optional<ast::Type> &rhs)
{
if (!lhs.type && !rhs)
return true;
// If typing is enabled, all objects have to be typed
assert(lhs.type);
assert(rhs);
return matches(lhs.type.value(), rhs.value());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const ast::Term &lhs, const std::experimental::optional<ast::Type> &rhs)
{
return lhs.match([&](const auto &x){return matches(*x->declaration, rhs);});
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool matches(const std::string &predicateName, const ast::Predicate::Arguments &predicateArguments, const ast::PredicateDeclaration &predicateDeclaration)
{
if (predicateName != predicateDeclaration.name)
return false;
if (predicateArguments.size() != predicateDeclaration.parameters.size())
return false;
for (size_t i = 0; i < predicateArguments.size(); i++)
if (!matches(predicateArguments[i], predicateDeclaration.parameters[i]->type))
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,77 @@
#include <pddl/detail/VariableStack.h>
#include <algorithm>
#include <pddl/AST.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// VariableStack
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void VariableStack::push(ast::VariableDeclarations *layer)
{
m_layers.push_back(layer);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void VariableStack::pop()
{
m_layers.pop_back();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::VariableDeclaration *> VariableStack::findVariableDeclaration(const std::string &variableName) const
{
const auto variableDeclarationMatches =
[&variableName](const auto &variableDeclaration)
{
return variableDeclaration->name == variableName;
};
for (auto i = m_layers.rbegin(); i != m_layers.rend(); i++)
{
auto &layer = **i;
const auto matchingVariableDeclaration = std::find_if(layer.begin(), layer.end(), variableDeclarationMatches);
if (matchingVariableDeclaration != layer.end())
return matchingVariableDeclaration->get();
}
return std::experimental::nullopt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool VariableStack::contains(const ast::VariableDeclaration &variableDeclaration) const
{
const auto variableDeclarationMatches =
[&](const auto &other)
{
return &variableDeclaration == other.get();
};
for (auto i = m_layers.rbegin(); i != m_layers.rend(); i++)
{
auto &layer = **i;
const auto matchingVariableDeclaration = std::find_if(layer.begin(), layer.end(), variableDeclarationMatches);
if (matchingVariableDeclaration != layer.end())
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,38 @@
#include <pddl/detail/normalization/Action.h>
#include <pddl/AST.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/Effect.h>
#include <pddl/detail/normalization/Precondition.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Action
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::ActionPointer normalize(ast::ActionPointer &&action, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
auto normalizedAction = std::make_unique<normalizedAST::Action>();
normalizedAction->name = std::move(action->name);
normalizedAction->parameters = std::move(action->parameters);
if (action->precondition)
normalizedAction->precondition = normalize(std::move(action->precondition.value()), derivedPredicates);
if (action->effect)
normalizedAction->effect = normalize(std::move(action->effect.value()), derivedPredicates);
return normalizedAction;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,32 @@
#include <pddl/detail/normalization/AtomicFormula.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedAST.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// AtomicFormula
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::AtomicFormula normalize(ast::AtomicFormula &&atomicFormula)
{
const auto handlePredicate =
[&](ast::PredicatePointer &predicate) -> normalizedAST::AtomicFormula
{
return std::move(predicate);
};
return atomicFormula.match(handlePredicate);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,45 @@
#include <pddl/detail/normalization/Effect.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/Literal.h>
#include <pddl/detail/normalization/Precondition.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::ConditionalEffect normalize(ast::ConditionalEffect &&conditionalEffect)
{
const auto handleLiteral =
[](ast::Literal &literal) -> normalizedAST::ConditionalEffect
{
return normalize(std::move(literal));
};
const auto handleAnd =
[&](ast::AndPointer<ast::Literal> &and_) -> normalizedAST::ConditionalEffect
{
normalizedAST::And<normalizedAST::Literal>::Arguments arguments;
for (auto &argument : and_->arguments)
arguments.emplace_back(normalize(std::move(argument)));
return std::make_unique<normalizedAST::And<normalizedAST::Literal>>(std::move(arguments));
};
return conditionalEffect.match(handleLiteral, handleAnd);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,34 @@
#include <pddl/detail/normalization/Description.h>
#include <pddl/AST.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/Domain.h>
#include <pddl/detail/normalization/Problem.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Description
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Description normalize(ast::Description &&description)
{
normalizedAST::Description normalizedDescription;
normalizedDescription.domain = normalize(std::move(description.domain));
if (description.problem)
normalizedDescription.problem = normalize(std::move(description.problem.value()), normalizedDescription.domain.get());
return normalizedDescription;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,38 @@
#include <pddl/detail/normalization/Domain.h>
#include <pddl/AST.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/Action.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Description
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::DomainPointer normalize(ast::DomainPointer &&domain)
{
auto normalizedDomain = std::make_unique<normalizedAST::Domain>();
normalizedDomain->types = std::move(domain->types);
normalizedDomain->name = std::move(domain->name);
normalizedDomain->constants = std::move(domain->constants);
normalizedDomain->predicates = std::move(domain->predicates);
normalizedDomain->actions.reserve(domain->actions.size());
for (auto &&action : domain->actions)
normalizedDomain->actions.emplace_back(normalize(std::move(action), normalizedDomain->derivedPredicates));
return normalizedDomain;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,62 @@
#include <pddl/detail/normalization/Effect.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/ConditionalEffect.h>
#include <pddl/detail/normalization/Literal.h>
#include <pddl/detail/normalization/Precondition.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Effect normalize(ast::Effect &&effect, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
const auto handleLiteral =
[](ast::Literal &literal) -> normalizedAST::Effect
{
return normalize(std::move(literal));
};
const auto handleAnd =
[&](ast::AndPointer<ast::Effect> &and_) -> normalizedAST::Effect
{
normalizedAST::And<normalizedAST::Effect>::Arguments arguments;
for (auto &argument : and_->arguments)
arguments.emplace_back(normalize(std::move(argument), derivedPredicates));
return std::make_unique<normalizedAST::And<normalizedAST::Effect>>(std::move(arguments));
};
const auto handleForAll =
[&](ast::ForAllPointer<ast::Effect> &forAll) -> normalizedAST::Effect
{
auto normalizedArgument = normalize(std::move(forAll->argument), derivedPredicates);
return std::make_unique<normalizedAST::ForAll<normalizedAST::Effect>>(std::move(forAll->parameters), std::move(normalizedArgument));
};
const auto handleWhen =
[&](ast::WhenPointer<ast::Precondition, ast::ConditionalEffect> &when) -> normalizedAST::Effect
{
auto normalizedCondition = normalize(std::move(when->argumentLeft), derivedPredicates);
auto normalizedConditionalEffect = normalize(std::move(when->argumentRight));
return std::make_unique<normalizedAST::When<normalizedAST::Precondition, normalizedAST::ConditionalEffect>>(std::move(normalizedCondition), std::move(normalizedConditionalEffect));
};
return effect.match(handleLiteral, handleAnd, handleForAll, handleWhen);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,39 @@
#include <pddl/detail/normalization/Fact.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/Literal.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Fact
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Fact normalize(ast::Fact &&fact)
{
const auto handleLiteral =
[&](ast::Literal &literal) -> normalizedAST::Literal
{
return normalize(std::move(literal));
};
const auto handleAt =
[&](ast::AtPointer<ast::Literal> &) -> normalizedAST::Literal
{
throw NormalizationException("“at” expressions in preconditions cant be normalized currently");
};
return fact.match(handleLiteral, handleAt);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,33 @@
#include <pddl/detail/normalization/InitialState.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/Fact.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// InitialState
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::InitialState normalize(ast::InitialState &&initialState)
{
normalizedAST::InitialState normalizedInitialState;
normalizedInitialState.facts.reserve(initialState.facts.size());
for (auto &fact : initialState.facts)
normalizedInitialState.facts.emplace_back(normalize(std::move(fact)));
return normalizedInitialState;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,39 @@
#include <pddl/detail/normalization/Literal.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/AtomicFormula.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Literal
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalize(ast::Literal &&literal)
{
const auto handleAtomicFormula =
[&](ast::AtomicFormula &atomicFormula) -> normalizedAST::Literal
{
return normalize(std::move(atomicFormula));
};
const auto handleNot =
[&](ast::NotPointer<ast::AtomicFormula> &not_) -> normalizedAST::Literal
{
return std::make_unique<normalizedAST::Not<normalizedAST::AtomicFormula>>(normalize(std::move(not_->argument)));
};
return literal.match(handleAtomicFormula, handleNot);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,360 @@
#include <pddl/detail/normalization/Precondition.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/AtomicFormula.h>
#include <pddl/detail/normalization/CollectFreeVariables.h>
#include <pddl/detail/normalization/Reduction.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Precondition
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Forward Declarations
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeNested(ast::AndPointer<ast::Precondition> &and_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
normalizedAST::Literal normalizeNested(ast::AtomicFormula &, normalizedAST::DerivedPredicateDeclarations &);
normalizedAST::Literal normalizeNested(ast::ExistsPointer<ast::Precondition> &exists, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
normalizedAST::Literal normalizeNested(ast::ForAllPointer<ast::Precondition> &forAll, normalizedAST::DerivedPredicateDeclarations &);
normalizedAST::Literal normalizeNested(ast::ImplyPointer<ast::Precondition> &, normalizedAST::DerivedPredicateDeclarations &);
normalizedAST::Literal normalizeNested(ast::NotPointer<ast::Precondition> &not_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
normalizedAST::Literal normalizeNested(ast::OrPointer<ast::Precondition> &or_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
normalizedAST::AndPointer<normalizedAST::Literal> normalizeTopLevel(ast::AndPointer<ast::Precondition> &and_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
normalizedAST::AtomicFormula normalizeTopLevel(ast::AtomicFormula &, normalizedAST::DerivedPredicateDeclarations &);
normalizedAST::Literal normalizeTopLevel(ast::ExistsPointer<ast::Precondition> &exists, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
normalizedAST::Literal normalizeTopLevel(ast::ForAllPointer<ast::Precondition> &forAll, normalizedAST::DerivedPredicateDeclarations &);
normalizedAST::Literal normalizeTopLevel(ast::ImplyPointer<ast::Precondition> &, normalizedAST::DerivedPredicateDeclarations &);
normalizedAST::NotPointer<normalizedAST::AtomicFormula> normalizeTopLevel(ast::NotPointer<ast::Precondition> &not_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
normalizedAST::OrPointer<normalizedAST::Literal> normalizeTopLevel(ast::OrPointer<ast::Precondition> &or_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates);
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::DerivedPredicatePointer addDerivedPredicate(const std::vector<normalizedAST::VariableDeclaration *> &parameters, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
auto name = "derived-predicate-" + std::to_string(derivedPredicates.size() + 1);
normalizedAST::DerivedPredicate::Arguments arguments;
arguments.reserve(parameters.size());
for (const auto &parameter : parameters)
arguments.emplace_back(std::make_unique<normalizedAST::Variable>(parameter));
derivedPredicates.emplace_back(std::make_unique<normalizedAST::DerivedPredicateDeclaration>());
auto *derivedPredicate = derivedPredicates.back().get();
derivedPredicate->name = std::move(name);
derivedPredicate->parameters = std::move(parameters);
return std::make_unique<normalizedAST::DerivedPredicate>(std::move(arguments), derivedPredicate);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeNested(ast::AndPointer<ast::Precondition> &and_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
std::vector<normalizedAST::VariableDeclaration *> parameters;
VariableStack variableStack;
collectFreeVariables(and_, parameters, variableStack);
auto derivedPredicate = addDerivedPredicate(parameters, derivedPredicates);
normalizedAST::And<normalizedAST::Literal>::Arguments normalizedArguments;
normalizedArguments.reserve(and_->arguments.size());
for (auto &argument : and_->arguments)
normalizedArguments.emplace_back(argument.match(
[&](auto &x) -> normalizedAST::Literal
{
return normalizeNested(x, derivedPredicates);
}));
derivedPredicate->declaration->precondition = std::make_unique<normalizedAST::And<normalizedAST::Literal>>(std::move(normalizedArguments));
// TODO: investigate, could be a compiler bug
return std::move(derivedPredicate);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeNested(ast::AtomicFormula &atomicFormula, normalizedAST::DerivedPredicateDeclarations &)
{
return normalize(std::move(atomicFormula));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeNested(ast::ExistsPointer<ast::Precondition> &exists, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
std::vector<normalizedAST::VariableDeclaration *> parameters;
VariableStack variableStack;
collectFreeVariables(exists, parameters, variableStack);
auto derivedPredicate = addDerivedPredicate(parameters, derivedPredicates);
derivedPredicate->declaration->existentialParameters = std::move(exists->parameters);
derivedPredicate->declaration->precondition = exists->argument.match(
[&](auto &x) -> normalizedAST::DerivedPredicatePrecondition
{
return normalizeTopLevel(x, derivedPredicates);
});
// TODO: investigate, could be a compiler bug
return std::move(derivedPredicate);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeNested(ast::ForAllPointer<ast::Precondition> &, normalizedAST::DerivedPredicateDeclarations &)
{
// “forall” expressions should be reduced to negated “exists” statements at this point
throw std::logic_error("precondition not in normal form (forall), please report to the bug tracker");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeNested(ast::ImplyPointer<ast::Precondition> &, normalizedAST::DerivedPredicateDeclarations &)
{
// “imply” expressions should be reduced to disjunctions at this point
throw std::logic_error("precondition not in normal form (imply), please report to the bug tracker");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeNested(ast::NotPointer<ast::Precondition> &not_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
auto normalizedArgumentLiteral = not_->argument.match(
[&](auto &x) -> normalizedAST::Literal
{
return normalizeNested(x, derivedPredicates);
});
// Multiple negations should be eliminated at this point
if (normalizedArgumentLiteral.is<normalizedAST::NotPointer<normalizedAST::AtomicFormula>>())
throw std::logic_error("precondition not in normal form (multiple negation), please report to the bug tracker");
auto &normalizedArgument = normalizedArgumentLiteral.get<normalizedAST::AtomicFormula>();
return std::make_unique<normalizedAST::Not<normalizedAST::AtomicFormula>>(std::move(normalizedArgument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeNested(ast::OrPointer<ast::Precondition> &or_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
std::vector<normalizedAST::VariableDeclaration *> parameters;
VariableStack variableStack;
collectFreeVariables(or_, parameters, variableStack);
auto derivedPredicate = addDerivedPredicate(parameters, derivedPredicates);
normalizedAST::Or<normalizedAST::Literal>::Arguments normalizedArguments;
normalizedArguments.reserve(or_->arguments.size());
for (auto &argument : or_->arguments)
normalizedArguments.emplace_back(argument.match(
[&](auto &x) -> normalizedAST::Literal
{
return normalizeNested(x, derivedPredicates);
}));
derivedPredicate->declaration->precondition = std::make_unique<normalizedAST::Or<normalizedAST::Literal>>(std::move(normalizedArguments));
// TODO: investigate, could be a compiler bug
return std::move(derivedPredicate);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::AtomicFormula normalizeTopLevel(ast::AtomicFormula &atomicFormula, normalizedAST::DerivedPredicateDeclarations &)
{
return normalize(std::move(atomicFormula));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Normalize top-level conjunctions
normalizedAST::AndPointer<normalizedAST::Literal> normalizeTopLevel(ast::AndPointer<ast::Precondition> &and_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
normalizedAST::And<normalizedAST::Literal>::Arguments arguments;
arguments.reserve(and_->arguments.size());
const auto handleAtomicFormula =
[&](ast::AtomicFormula &atomicFormula) -> normalizedAST::Literal
{
return normalize(std::move(atomicFormula));
};
const auto handleNot =
[&](ast::NotPointer<ast::Precondition> &not_) -> normalizedAST::Literal
{
return normalizeTopLevel(not_, derivedPredicates);
};
const auto handleNested =
[&](auto &nested) -> normalizedAST::Literal
{
return normalizeNested(nested, derivedPredicates);
};
for (auto &argument : and_->arguments)
{
auto normalizedArgument = argument.match(handleAtomicFormula, handleNot, handleNested);
arguments.emplace_back(std::move(normalizedArgument));
}
return std::make_unique<normalizedAST::And<normalizedAST::Literal>>(std::move(arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeTopLevel(ast::ExistsPointer<ast::Precondition> &exists, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
return normalizeNested(exists, derivedPredicates);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeTopLevel(ast::ForAllPointer<ast::Precondition> &, normalizedAST::DerivedPredicateDeclarations &)
{
throw std::logic_error("precondition not in normal form (forall), please report to the bug tracker");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Literal normalizeTopLevel(ast::ImplyPointer<ast::Precondition> &, normalizedAST::DerivedPredicateDeclarations &)
{
throw std::logic_error("precondition not in normal form (imply), please report to the bug tracker");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Normalize top-level negations
normalizedAST::NotPointer<normalizedAST::AtomicFormula> normalizeTopLevel(ast::NotPointer<ast::Precondition> &not_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
// “not” expressions may be nested one time to form simple literals
if (not_->argument.is<ast::AtomicFormula>())
return std::make_unique<normalizedAST::Not<normalizedAST::AtomicFormula>>(normalize(std::move(not_->argument.get<ast::AtomicFormula>())));
auto normalizedArgument = not_->argument.match(
[&](auto &nested) -> normalizedAST::AtomicFormula
{
auto normalizedLiteral = normalizeNested(nested, derivedPredicates);
// Multiple negations should be eliminated at this point
if (normalizedLiteral.template is<normalizedAST::NotPointer<normalizedAST::AtomicFormula>>())
throw std::logic_error("precondition not in normal form (multiple negation), please report to the bug tracker");
return std::move(normalizedLiteral.template get<normalizedAST::AtomicFormula>());
});
return std::make_unique<normalizedAST::Not<normalizedAST::AtomicFormula>>(std::move(normalizedArgument));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: refactor to avoid code duplication
normalizedAST::OrPointer<normalizedAST::Literal> normalizeTopLevel(ast::OrPointer<ast::Precondition> &or_, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
normalizedAST::Or<normalizedAST::Literal>::Arguments arguments;
arguments.reserve(or_->arguments.size());
const auto handleAtomicFormula =
[&](ast::AtomicFormula &atomicFormula) -> normalizedAST::Literal
{
return normalize(std::move(atomicFormula));
};
const auto handleNot =
[&](ast::NotPointer<ast::Precondition> &not_) -> normalizedAST::Literal
{
return normalizeTopLevel(not_, derivedPredicates);
};
const auto handleNested =
[&](auto &nested) -> normalizedAST::Literal
{
return normalizeNested(nested, derivedPredicates);
};
for (auto &argument : or_->arguments)
{
auto normalizedArgument = argument.match(handleAtomicFormula, handleNot, handleNested);
arguments.emplace_back(std::move(normalizedArgument));
}
return std::make_unique<normalizedAST::Or<normalizedAST::Literal>>(std::move(arguments));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::Precondition normalize(ast::Precondition &&precondition, normalizedAST::DerivedPredicateDeclarations &derivedPredicates)
{
// Bring precondition to normal form
reduce(precondition);
const auto handleAtomicFormula =
[&](ast::AtomicFormula &atomicFormula) -> normalizedAST::Precondition
{
return normalizeTopLevel(atomicFormula, derivedPredicates);
};
const auto handleAnd =
[&](ast::AndPointer<ast::Precondition> &and_) -> normalizedAST::Precondition
{
return normalizeTopLevel(and_, derivedPredicates);
};
const auto handleExists =
[&](ast::ExistsPointer<ast::Precondition> &exists) -> normalizedAST::Precondition
{
return normalizeTopLevel(exists, derivedPredicates);
};
const auto handleForAll =
[&](ast::ForAllPointer<ast::Precondition> &forAll) -> normalizedAST::Precondition
{
return normalizeTopLevel(forAll, derivedPredicates);
};
const auto handleImply =
[&](ast::ImplyPointer<ast::Precondition> &imply) -> normalizedAST::Precondition
{
return normalizeTopLevel(imply, derivedPredicates);
};
const auto handleNot =
[&](ast::NotPointer<ast::Precondition> &not_) -> normalizedAST::Precondition
{
return normalizeTopLevel(not_, derivedPredicates);
};
const auto handleOr =
[&](ast::OrPointer<ast::Precondition> &or_) -> normalizedAST::Precondition
{
return normalizeNested(or_, derivedPredicates);
};
return precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,36 @@
#include <pddl/detail/normalization/Problem.h>
#include <pddl/AST.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/InitialState.h>
#include <pddl/detail/normalization/Precondition.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Problem
//
////////////////////////////////////////////////////////////////////////////////////////////////////
normalizedAST::ProblemPointer normalize(ast::ProblemPointer &&problem, normalizedAST::Domain *domain)
{
auto normalizedProblem = std::make_unique<normalizedAST::Problem>(domain);
normalizedProblem->name = std::move(problem->name);
normalizedProblem->objects = std::move(problem->objects);
normalizedProblem->initialState = normalize(std::move(problem->initialState));
if (problem->goal)
normalizedProblem->goal = normalize(std::move(problem->goal.value()), normalizedProblem->derivedPredicates);
return normalizedProblem;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,287 @@
#include <pddl/detail/normalization/Reduction.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/NormalizedAST.h>
#include <pddl/detail/normalization/AtomicFormula.h>
#include <pddl/detail/normalization/CollectFreeVariables.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Reduction
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////////////////////////
void eliminateImply(ast::Precondition &precondition);
void negationNormalize(ast::Precondition &precondition);
void eliminateForAll(ast::Precondition &precondition);
void eliminateDoubleNegations(ast::Precondition &precondition);
////////////////////////////////////////////////////////////////////////////////////////////////////
void eliminateImply(ast::Precondition &precondition)
{
const auto handleAtomicFormula =
[](ast::AtomicFormula &)
{
};
const auto handleAnd =
[](ast::AndPointer<ast::Precondition> &and_)
{
for (auto &argument : and_->arguments)
eliminateImply(argument);
};
const auto handleExists =
[](ast::ExistsPointer<ast::Precondition> &exists)
{
eliminateImply(exists->argument);
};
const auto handleForAll =
[](ast::ForAllPointer<ast::Precondition> &forAll)
{
eliminateImply(forAll->argument);
};
const auto handleImply =
[&](ast::ImplyPointer<ast::Precondition> &imply)
{
eliminateImply(imply->argumentLeft);
eliminateImply(imply->argumentRight);
ast::Or<ast::Precondition>::Arguments arguments;
arguments.reserve(2);
arguments.emplace_back(std::make_unique<ast::Not<ast::Precondition>>(std::move(imply->argumentLeft)));
arguments.emplace_back(std::move(imply->argumentRight));
precondition = std::make_unique<ast::Or<ast::Precondition>>(std::move(arguments));
};
const auto handleNot =
[](ast::NotPointer<ast::Precondition> &not_)
{
eliminateImply(not_->argument);
};
const auto handleOr =
[](ast::OrPointer<ast::Precondition> &or_)
{
for (auto &argument : or_->arguments)
eliminateImply(argument);
};
precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Negation-normalize an expression whose parent is a “not” expression
void negationNormalizeNegated(ast::Precondition &precondition, ast::Precondition &parent)
{
const auto handleAtomicFormula =
[](ast::AtomicFormula &)
{
};
const auto handleAnd =
[&](ast::AndPointer<ast::Precondition> &and_)
{
ast::Or<ast::Precondition>::Arguments arguments;
arguments.reserve(and_->arguments.size());
// Apply De Morgan
for (auto &argument : and_->arguments)
arguments.emplace_back(std::make_unique<ast::Not<ast::Precondition>>(std::move(argument)));
// Finally, negation-normalize each argument
for (auto &argument : arguments)
negationNormalize(argument);
// Replace the parent “not” containing this “and” with an “or” over the negated arguments
parent = std::make_unique<ast::Or<ast::Precondition>>(std::move(arguments));
};
const auto handleExists =
[](ast::ExistsPointer<ast::Precondition> &exists)
{
negationNormalize(exists->argument);
};
const auto handleForAll =
[](ast::ForAllPointer<ast::Precondition> &forAll)
{
negationNormalize(forAll->argument);
};
const auto handleImply =
[](ast::ImplyPointer<ast::Precondition> &)
{
throw std::logic_error("precondition not ready for negation normalization (imply), please report to the bug tracker");
};
const auto handleNot =
[&](ast::NotPointer<ast::Precondition> &not_)
{
negationNormalize(not_->argument);
// As the parent contains the argument, the argument needs to be saved before overwriting the parent
// TODO: check whether this workaround can be avoided
auto argument = std::move(not_->argument);
parent = std::move(argument);
};
const auto handleOr =
[&](ast::OrPointer<ast::Precondition> &or_)
{
ast::And<ast::Precondition>::Arguments arguments;
arguments.reserve(or_->arguments.size());
// Apply De Morgan
for (auto &argument : or_->arguments)
arguments.emplace_back(std::make_unique<ast::Not<ast::Precondition>>(std::move(argument)));
// Finally, negation-normalize each argument
for (auto &argument : arguments)
negationNormalize(argument);
// Replace the parent “not” containing this “or” with an “and” over the negated arguments
parent = std::make_unique<ast::And<ast::Precondition>>(std::move(arguments));
};
precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void negationNormalize(ast::Precondition &precondition)
{
const auto handleAtomicFormula =
[](ast::AtomicFormula &)
{
};
const auto handleAnd =
[](ast::AndPointer<ast::Precondition> &and_)
{
for (auto &argument : and_->arguments)
negationNormalize(argument);
};
const auto handleExists =
[](ast::ExistsPointer<ast::Precondition> &exists)
{
negationNormalize(exists->argument);
};
const auto handleForAll =
[](ast::ForAllPointer<ast::Precondition> &forAll)
{
negationNormalize(forAll->argument);
};
const auto handleImply =
[](ast::ImplyPointer<ast::Precondition> &)
{
throw std::logic_error("precondition not ready for negation normalization (imply), please report to the bug tracker");
};
const auto handleNot =
[&](ast::NotPointer<ast::Precondition> &not_)
{
negationNormalizeNegated(not_->argument, precondition);
};
const auto handleOr =
[](ast::OrPointer<ast::Precondition> &or_)
{
for (auto &argument : or_->arguments)
negationNormalize(argument);
};
precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void eliminateForAll(ast::Precondition &precondition)
{
const auto handleAtomicFormula =
[](ast::AtomicFormula &)
{
};
const auto handleAnd =
[](ast::AndPointer<ast::Precondition> &and_)
{
for (auto &argument : and_->arguments)
eliminateForAll(argument);
};
const auto handleExists =
[](ast::ExistsPointer<ast::Precondition> &exists)
{
eliminateForAll(exists->argument);
};
const auto handleForAll =
[&](ast::ForAllPointer<ast::Precondition> &forAll)
{
eliminateForAll(forAll->argument);
auto negatedArgument = std::make_unique<ast::Not<ast::Precondition>>(std::move(forAll->argument));
auto exists = std::make_unique<ast::Exists<ast::Precondition>>(std::move(forAll->parameters), std::move(negatedArgument));
precondition = std::make_unique<ast::Not<ast::Precondition>>(std::move(exists));
};
const auto handleImply =
[&](ast::ImplyPointer<ast::Precondition> &imply)
{
eliminateForAll(imply->argumentLeft);
eliminateForAll(imply->argumentRight);
};
const auto handleNot =
[](ast::NotPointer<ast::Precondition> &not_)
{
eliminateForAll(not_->argument);
};
const auto handleOr =
[](ast::OrPointer<ast::Precondition> &or_)
{
for (auto &argument : or_->arguments)
eliminateForAll(argument);
};
precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void reduce(ast::Precondition &precondition)
{
// Replace “imply” statements with disjunctions
eliminateImply(precondition);
// Eliminate “forall” statements
eliminateForAll(precondition);
// Negation-normalize the precondition
negationNormalize(precondition);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,194 @@
#include <pddl/detail/parsing/Action.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/detail/ASTContext.h>
#include <pddl/detail/VariableStack.h>
#include <pddl/detail/parsing/Effect.h>
#include <pddl/detail/parsing/Precondition.h>
#include <pddl/detail/parsing/Utils.h>
#include <pddl/detail/parsing/VariableDeclaration.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Action
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ActionParser::ActionParser(Context &context, ast::Domain &domain)
: m_context{context},
m_domain{domain},
m_parametersPosition{tokenize::InvalidStreamPosition},
m_preconditionPosition{tokenize::InvalidStreamPosition},
m_effectPosition{tokenize::InvalidStreamPosition},
m_varsPosition{tokenize::InvalidStreamPosition}
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::ActionPointer ActionParser::parse()
{
auto action = std::make_unique<ast::Action>();
findSections(*action);
auto &tokenizer = m_context.tokenizer;
if (m_parametersPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_parametersPosition);
parseParameterSection(*action);
}
// For compatibility with old PDDL versions, vars sections are parsed in addition to parameters
if (m_varsPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_varsPosition);
parseVarsSection(*action);
}
if (m_preconditionPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_preconditionPosition);
parsePreconditionSection(*action);
}
if (m_effectPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_effectPosition);
parseEffectSection(*action);
}
return action;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ActionParser::findSections(ast::Action &action)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("action");
action.name = tokenizer.getIdentifier();
// TODO: rename parameters appropriately
const auto setSectionPosition =
[&](const std::string &sectionName, auto &sectionPosition, const auto value, bool unique = false)
{
if (unique && sectionPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(value);
throw ParserException(tokenizer.location(), "only one “:" + sectionName + "” section allowed");
}
sectionPosition = value;
};
tokenizer.skipWhiteSpace();
while (tokenizer.currentCharacter() != ')')
{
const auto position = tokenizer.position();
tokenizer.expect<std::string>(":");
if (tokenizer.testIdentifierAndSkip("parameters"))
setSectionPosition("parameters", m_parametersPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("precondition"))
setSectionPosition("precondition", m_preconditionPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("effect"))
setSectionPosition("effect", m_effectPosition, position, true);
else if (m_context.mode == Mode::Compatibility && tokenizer.testIdentifierAndSkip("vars"))
setSectionPosition("vars", m_varsPosition, position, true);
else
{
const auto sectionIdentifier = tokenizer.getIdentifier();
tokenizer.seek(position);
throw ParserException(tokenizer.location(), "unknown action section “" + sectionIdentifier + "");
}
tokenizer.expect<std::string>("(");
// Skip section for now and parse it later
skipSection(tokenizer);
tokenizer.skipWhiteSpace();
}
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ActionParser::parseParameterSection(ast::Action &action)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>(":parameters");
tokenizer.expect<std::string>("(");
parseAndAddVariableDeclarations(m_context, m_domain, action.parameters);
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ActionParser::parsePreconditionSection(ast::Action &action)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>(":precondition");
ASTContext astContext(m_domain);
VariableStack variableStack;
variableStack.push(&action.parameters);
action.precondition = parsePrecondition(m_context, astContext, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ActionParser::parseEffectSection(ast::Action &action)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>(":effect");
ASTContext astContext(m_domain);
VariableStack variableStack;
variableStack.push(&action.parameters);
action.effect = parseEffect(m_context, astContext, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ActionParser::parseVarsSection(ast::Action &action)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>(":vars");
tokenizer.expect<std::string>("(");
m_context.warningCallback(tokenizer.location(), "“vars” section is not part of the PDDL 3.1 specification, treating it like additional “parameters” section");
parseAndAddVariableDeclarations(m_context, m_domain, action.parameters);
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,40 @@
#include <pddl/detail/parsing/AtomicFormula.h>
#include <pddl/AST.h>
#include <pddl/detail/parsing/Predicate.h>
#include <pddl/detail/parsing/Unsupported.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// AtomicFormula
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::AtomicFormula> parseAtomicFormula(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
// Test unsupported expressions first
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
tokenizer.skipWhiteSpace();
if (tokenizer.testIdentifierAndReturn("="))
throw exceptUnsupportedExpression(position, context);
tokenizer.seek(position);
// Now, test supported expressions
return parsePredicate(context, astContext, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,84 @@
#include <pddl/detail/parsing/Constant.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Constant
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::ConstantPointer> findConstant(const std::string &constantName, ast::ConstantDeclarations &constantDeclarations)
{
const auto matchingConstant = std::find_if(constantDeclarations.begin(), constantDeclarations.end(),
[&](const auto &constantDeclaration)
{
return constantDeclaration->name == constantName;
});
if (matchingConstant == constantDeclarations.end())
return std::experimental::nullopt;
return std::make_unique<ast::Constant>(matchingConstant->get());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::ConstantPointer> findConstant(const std::string &constantName, ASTContext &astContext)
{
auto constant = findConstant(constantName, astContext.domain->constants);
if (constant)
return std::move(constant.value());
if (astContext.problem)
{
constant = findConstant(constantName, astContext.problem.value()->objects);
if (constant)
return std::move(constant.value());
}
return std::experimental::nullopt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::ConstantPointer> testParsingConstant(Context &context, ASTContext &astContext)
{
auto &tokenizer = context.tokenizer;
const auto constantName = tokenizer.getIdentifier();
auto constant = findConstant(constantName, astContext);
if (!constant)
return std::experimental::nullopt;
return std::move(constant.value());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::ConstantPointer parseConstant(Context &context, ASTContext &astContext)
{
auto &tokenizer = context.tokenizer;
const auto constantName = tokenizer.getIdentifier();
auto constant = findConstant(constantName, astContext);
if (!constant)
throw ParserException(tokenizer.location(), "undeclared constant “" + constantName + "");
return std::move(constant.value());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,83 @@
#include <pddl/detail/parsing/ConstantDeclaration.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/detail/ASTCopy.h>
#include <pddl/detail/parsing/PrimitiveType.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ConstantDeclaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddUntypedConstantDeclaration(Context &context, ast::ConstantDeclarations &constantDeclarations)
{
auto &tokenizer = context.tokenizer;
auto constantName = tokenizer.getIdentifier();
assert(constantName != "-");
constantDeclarations.emplace_back(std::make_unique<ast::ConstantDeclaration>(std::move(constantName)));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddConstantDeclarations(Context &context, ast::Domain &domain, ast::ConstantDeclarations &constantDeclarations)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
// Index on the first element of the current inheritance list
size_t inheritanceIndex = constantDeclarations.size();
while (tokenizer.currentCharacter() != ')')
{
parseAndAddUntypedConstantDeclaration(context, constantDeclarations);
tokenizer.skipWhiteSpace();
if (!tokenizer.testAndSkip<char>('-'))
continue;
// If existing, parse and store parent type
auto parentType = parsePrimitiveType(context, domain);
for (size_t i = inheritanceIndex; i < constantDeclarations.size(); i++)
constantDeclarations[i]->type = ast::deepCopy(parentType);
// All types up to now are labeled with their parent types
inheritanceIndex = constantDeclarations.size();
tokenizer.skipWhiteSpace();
}
const bool isTypingUsed = !domain.types.empty();
if (isTypingUsed && !constantDeclarations.empty() && !constantDeclarations.back()->type)
throw ParserException(tokenizer.location(), "missing type declaration for constant “" + constantDeclarations.back()->name + "");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddConstantDeclarations(Context &context, ast::Domain &domain)
{
parseAndAddConstantDeclarations(context, domain, domain.constants);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddConstantDeclarations(Context &context, ast::Problem &problem)
{
parseAndAddConstantDeclarations(context, *problem.domain, problem.objects);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,118 @@
#include <pddl/detail/parsing/Description.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/detail/parsing/Domain.h>
#include <pddl/detail/parsing/Problem.h>
#include <pddl/detail/parsing/Utils.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Description
//
////////////////////////////////////////////////////////////////////////////////////////////////////
DescriptionParser::DescriptionParser(Context &context)
: m_context{context},
m_domainPosition{tokenize::InvalidStreamPosition},
m_problemPosition{tokenize::InvalidStreamPosition}
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Description DescriptionParser::parse()
{
auto &tokenizer = m_context.tokenizer;
tokenizer.removeComments(";", "\n", false);
findSections();
if (m_domainPosition == tokenize::InvalidStreamPosition)
throw ParserException("no PDDL domain specified");
tokenizer.seek(m_domainPosition);
auto domain = DomainParser(m_context).parse();
// If no problem is given, return just the domain
if (m_problemPosition == tokenize::InvalidStreamPosition)
return {std::move(domain), std::experimental::nullopt};
tokenizer.seek(m_problemPosition);
auto problem = ProblemParser(m_context, *domain).parse();
// TODO: check consistency
// * check typing requirement
// * check that typing is used consistently
// * check that constants/objects, variables, and predicates aren't declared twice
// * check section order
// * check that preconditions and effects are well-formed
return {std::move(domain), std::move(problem)};
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void DescriptionParser::findSections()
{
auto &tokenizer = m_context.tokenizer;
tokenizer.skipWhiteSpace();
while (!tokenizer.atEnd())
{
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
if (m_context.mode == Mode::Compatibility && tokenizer.testAndReturn<std::string>("in-package"))
{
m_context.warningCallback(tokenizer.location(), "“in-package” section is not part of the PDDL 3.1 specification, ignoring section");
skipSection(tokenizer);
tokenizer.skipWhiteSpace();
continue;
}
tokenizer.expect<std::string>("define");
tokenizer.expect<std::string>("(");
if (tokenizer.testAndSkip<std::string>("domain"))
{
if (m_domainPosition != tokenize::InvalidStreamPosition)
throw ParserException(tokenizer.location(), "PDDL description may not contain two domains");
m_domainPosition = position;
skipSection(tokenizer);
skipSection(tokenizer);
}
else if (m_context.tokenizer.testAndSkip<std::string>("problem"))
{
if (m_problemPosition != tokenize::InvalidStreamPosition)
throw ParserException("PDDL description may not contain two problems currently");
m_problemPosition = position;
skipSection(tokenizer);
skipSection(tokenizer);
}
else
{
const auto sectionIdentifier = tokenizer.get<std::string>();
throw ParserException(tokenizer.location(), "unknown PDDL section “" + sectionIdentifier + "");
}
tokenizer.skipWhiteSpace();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,296 @@
#include <pddl/detail/parsing/Domain.h>
#include <pddl/Exception.h>
#include <pddl/detail/Requirements.h>
#include <pddl/detail/parsing/Action.h>
#include <pddl/detail/parsing/ConstantDeclaration.h>
#include <pddl/detail/parsing/PredicateDeclaration.h>
#include <pddl/detail/parsing/PrimitiveTypeDeclaration.h>
#include <pddl/detail/parsing/Requirement.h>
#include <pddl/detail/parsing/Unsupported.h>
#include <pddl/detail/parsing/Utils.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Domain
//
////////////////////////////////////////////////////////////////////////////////////////////////////
DomainParser::DomainParser(Context &context)
: m_context{context},
m_requirementsPosition{tokenize::InvalidStreamPosition},
m_typesPosition{tokenize::InvalidStreamPosition},
m_constantsPosition{tokenize::InvalidStreamPosition},
m_predicatesPosition{tokenize::InvalidStreamPosition}
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::DomainPointer DomainParser::parse()
{
auto domain = std::make_unique<ast::Domain>();
findSections(*domain);
auto &tokenizer = m_context.tokenizer;
if (m_requirementsPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_requirementsPosition);
parseRequirementSection(*domain);
}
if (m_typesPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_typesPosition);
parseTypeSection(*domain);
}
if (m_constantsPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_constantsPosition);
parseConstantSection(*domain);
}
if (m_predicatesPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_predicatesPosition);
parsePredicateSection(*domain);
}
for (size_t i = 0; i < m_actionPositions.size(); i++)
if (m_actionPositions[i] != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_actionPositions[i]);
parseActionSection(*domain);
}
computeDerivedRequirements(*domain);
return domain;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void DomainParser::findSections(ast::Domain &domain)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>("define");
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>("domain");
domain.name = tokenizer.getIdentifier();
tokenizer.expect<std::string>(")");
const auto setSectionPosition =
[&](const std::string &sectionName, auto &sectionPosition, const auto value, bool unique = false)
{
if (unique && sectionPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(value);
throw ParserException(tokenizer.location(), "only one “:" + sectionName + "” section allowed");
}
sectionPosition = value;
};
tokenizer.skipWhiteSpace();
// Find sections
while (tokenizer.currentCharacter() != ')')
{
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
// Save the parser position of the individual sections for later parsing
if (tokenizer.testIdentifierAndSkip("requirements"))
setSectionPosition("requirements", m_requirementsPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("types"))
setSectionPosition("types", m_typesPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("constants"))
setSectionPosition("constants", m_constantsPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("predicates"))
setSectionPosition("predicates", m_predicatesPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("action"))
{
m_actionPositions.emplace_back(tokenize::InvalidStreamPosition);
setSectionPosition("action", m_actionPositions.back(), position);
}
else if (tokenizer.testIdentifierAndSkip("functions")
|| tokenizer.testIdentifierAndSkip("constraints")
|| tokenizer.testIdentifierAndSkip("durative-action")
|| tokenizer.testIdentifierAndSkip("derived"))
{
throw exceptUnsupportedSection(position, m_context);
}
else
{
const auto sectionIdentifier = tokenizer.getIdentifier();
tokenizer.seek(position);
throw ParserException(tokenizer.location(), "unknown domain section “" + sectionIdentifier + "");
}
// Skip section for now and parse it later
skipSection(tokenizer);
tokenizer.skipWhiteSpace();
}
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void DomainParser::parseRequirementSection(ast::Domain &domain)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("requirements");
while (tokenizer.currentCharacter() != ')')
{
tokenizer.expect<std::string>(":");
const auto requirement = parseRequirement(m_context);
if (requirement)
domain.requirements.emplace_back(requirement.value());
tokenizer.skipWhiteSpace();
}
// TODO: do this check only once the problem is parsed
// If no requirements are specified, assume STRIPS
if (domain.requirements.empty())
domain.requirements.emplace_back(ast::Requirement::STRIPS);
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void DomainParser::computeDerivedRequirements(ast::Domain &domain)
{
const auto addRequirementUnique =
[&](auto requirement)
{
if (hasRequirement(domain, requirement))
return;
domain.requirements.push_back(requirement);
};
if (hasRequirement(domain, ast::Requirement::ADL))
{
addRequirementUnique(ast::Requirement::STRIPS);
addRequirementUnique(ast::Requirement::Typing);
addRequirementUnique(ast::Requirement::NegativePreconditions);
addRequirementUnique(ast::Requirement::DisjunctivePreconditions);
addRequirementUnique(ast::Requirement::Equality);
addRequirementUnique(ast::Requirement::QuantifiedPreconditions);
addRequirementUnique(ast::Requirement::ConditionalEffects);
}
if (hasRequirement(domain, ast::Requirement::QuantifiedPreconditions))
{
addRequirementUnique(ast::Requirement::ExistentialPreconditions);
addRequirementUnique(ast::Requirement::UniversalPreconditions);
}
if (hasRequirement(domain, ast::Requirement::Fluents))
{
addRequirementUnique(ast::Requirement::NumericFluents);
addRequirementUnique(ast::Requirement::ObjectFluents);
}
if (hasRequirement(domain, ast::Requirement::TimedInitialLiterals))
addRequirementUnique(ast::Requirement::DurativeActions);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void DomainParser::parseTypeSection(ast::Domain &domain)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("types");
checkRequirement(domain, ast::Requirement::Typing, m_context);
tokenizer.skipWhiteSpace();
// Store types and their parent types
while (tokenizer.currentCharacter() != ')')
{
if (tokenizer.currentCharacter() == '(')
throw ParserException(tokenizer.location(), "only primitive types are allowed in type section");
parseAndAddPrimitiveTypeDeclarations(m_context, domain);
tokenizer.skipWhiteSpace();
}
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void DomainParser::parseConstantSection(ast::Domain &domain)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("constants");
// Store constants
parseAndAddConstantDeclarations(m_context, domain);
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void DomainParser::parsePredicateSection(ast::Domain &domain)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("predicates");
tokenizer.skipWhiteSpace();
// Store predicates
parseAndAddPredicateDeclarations(m_context, domain);
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void DomainParser::parseActionSection(ast::Domain &domain)
{
domain.actions.emplace_back(ActionParser(m_context, domain).parse());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,151 @@
#include <pddl/detail/parsing/Effect.h>
#include <pddl/AST.h>
#include <pddl/detail/parsing/AtomicFormula.h>
#include <pddl/detail/parsing/Expressions.h>
#include <pddl/detail/parsing/Precondition.h>
#include <pddl/detail/parsing/Unsupported.h>
#include <pddl/detail/parsing/Utils.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Effect
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Effect> parseEffectBody(Context &context, ASTContext &astContext, VariableStack &variableStack);
std::experimental::optional<ast::ConditionalEffect> parseConditionalEffect(Context &context, ASTContext &astContext, VariableStack &variableStack);
std::experimental::optional<ast::Literal> parseConditionalEffectBody(Context &context, ASTContext &astContext, VariableStack &variableStack);
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Effect> parseEffect(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
std::experimental::optional<ast::Effect> effect;
if ((effect = parseAnd<ast::Effect>(context, astContext, variableStack, parseEffect))
|| (effect = parseForAll<ast::Effect>(context, astContext, variableStack, parseEffect))
|| (effect = parseWhen<ast::Precondition, ast::ConditionalEffect>(context, astContext, variableStack, parsePreconditionBody, parseConditionalEffect)))
{
return std::move(effect.value());
}
return parseEffectBody(context, astContext, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Effect> parseEffectBody(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
// Test unsupported expressions first
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
tokenizer.skipWhiteSpace();
const auto expressionIdentifierPosition = tokenizer.position();
if (tokenizer.testIdentifierAndReturn("assign")
|| tokenizer.testIdentifierAndReturn("scale-up")
|| tokenizer.testIdentifierAndReturn("scale-down")
|| tokenizer.testIdentifierAndReturn("increase")
|| tokenizer.testIdentifierAndReturn("decrease"))
{
throw exceptUnsupportedExpression(position, context);
}
tokenizer.seek(position);
// Now, test supported expressions
std::experimental::optional<ast::Effect> effect;
if ((effect = parseNot<ast::AtomicFormula>(context, astContext, variableStack, parseAtomicFormula))
|| (effect = parseAtomicFormula(context, astContext, variableStack)))
{
return std::move(effect.value());
}
tokenizer.seek(expressionIdentifierPosition);
const auto expressionIdentifier = tokenizer.getIdentifier();
tokenizer.seek(position);
throw ParserException(tokenizer.location(), "expression type “" + expressionIdentifier + "” unknown or not allowed in effect body");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::ConditionalEffect> parseConditionalEffect(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
std::experimental::optional<ast::ConditionalEffect> conditionalEffect;
if ((conditionalEffect = parseAnd<ast::Literal>(context, astContext, variableStack, parseConditionalEffectBody)))
return std::move(conditionalEffect.value());
return parseConditionalEffectBody(context, astContext, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Literal> parseConditionalEffectBody(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
// Test unsupported expressions first
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
tokenizer.skipWhiteSpace();
const auto expressionIdentifierPosition = tokenizer.position();
if (tokenizer.testIdentifierAndReturn("=")
|| tokenizer.testIdentifierAndReturn("assign")
|| tokenizer.testIdentifierAndReturn("scale-up")
|| tokenizer.testIdentifierAndReturn("scale-down")
|| tokenizer.testIdentifierAndReturn("increase")
|| tokenizer.testIdentifierAndReturn("decrease"))
{
throw exceptUnsupportedExpression(position, context);
}
tokenizer.seek(position);
// Now, test supported expressions
std::experimental::optional<ast::Literal> literal;
if ((literal = parseNot<ast::AtomicFormula>(context, astContext, variableStack, parseAtomicFormula))
|| (literal = parseAtomicFormula(context, astContext, variableStack)))
{
return std::move(literal.value());
}
tokenizer.seek(expressionIdentifierPosition);
const auto expressionIdentifier = tokenizer.getIdentifier();
tokenizer.seek(position);
throw ParserException(tokenizer.location(), "expression type “" + expressionIdentifier + "” unknown or not allowed in conditional effect body");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,54 @@
#include <pddl/detail/parsing/Fact.h>
#include <pddl/AST.h>
#include <pddl/detail/parsing/AtomicFormula.h>
#include <pddl/detail/parsing/Expressions.h>
#include <pddl/detail/parsing/Unsupported.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Fact
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Fact> parseFact(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
// Test unsupported expressions first
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
tokenizer.skipWhiteSpace();
if (tokenizer.testIdentifierAndReturn("="))
throw exceptUnsupportedExpression(position, context);
tokenizer.seek(position);
// Now, test supported expressions
std::experimental::optional<ast::Fact> fact;
if ((fact = parseNot<ast::AtomicFormula>(context, astContext, variableStack, parseAtomicFormula))
|| (fact = parseAtomicFormula(context, astContext, variableStack)))
{
return std::move(fact.value());
}
// Test for “at” expressions only now to allow “at” as a predicate name
// TODO: allow this in compatibility mode only?
if (tokenizer.testIdentifierAndReturn("at"))
throw exceptUnsupportedExpression(position, context);
return std::experimental::nullopt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,44 @@
#include <pddl/detail/parsing/InitialState.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/detail/parsing/Fact.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// InitialState
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::InitialState parseInitialState(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
ast::InitialState initialState;
tokenizer.skipWhiteSpace();
while (tokenizer.currentCharacter() != ')')
{
auto fact = parseFact(context, astContext, variableStack);
if (!fact)
throw ParserException(tokenizer.location(), "invalid initial state fact");
initialState.facts.emplace_back(std::move(fact.value()));
tokenizer.skipWhiteSpace();
}
return initialState;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,104 @@
#include <pddl/detail/parsing/Precondition.h>
#include <pddl/AST.h>
#include <pddl/detail/parsing/AtomicFormula.h>
#include <pddl/detail/parsing/Expressions.h>
#include <pddl/detail/parsing/Unsupported.h>
#include <pddl/detail/parsing/Utils.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Precondition
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Precondition> parsePrecondition(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
// Test unsupported expressions first
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
if (tokenizer.testIdentifierAndReturn("preference"))
throw exceptUnsupportedExpression(position, context);
tokenizer.seek(position);
// Now, test supported expressions
std::experimental::optional<ast::Precondition> precondition;
if ((precondition = parseAnd<ast::Precondition>(context, astContext, variableStack, parsePrecondition))
|| (precondition = parseForAll<ast::Precondition>(context, astContext, variableStack, parsePrecondition)))
{
return std::move(precondition.value());
}
tokenizer.seek(position);
return parsePreconditionBody(context, astContext, variableStack);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Precondition> parsePreconditionBody(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
// Test unsupported expressions first
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
tokenizer.skipWhiteSpace();
const auto expressionIdentifierPosition = tokenizer.position();
if (tokenizer.testIdentifierAndReturn("-")
|| tokenizer.testIdentifierAndReturn("*")
|| tokenizer.testIdentifierAndReturn("+")
|| tokenizer.testIdentifierAndReturn("-")
|| tokenizer.testIdentifierAndReturn("/")
|| tokenizer.testIdentifierAndReturn(">")
|| tokenizer.testIdentifierAndReturn("<")
|| tokenizer.testIdentifierAndReturn(">=")
|| tokenizer.testIdentifierAndReturn("<="))
{
throw exceptUnsupportedExpression(position, context);
}
tokenizer.seek(position);
// Now, test supported expressions
std::experimental::optional<ast::Precondition> precondition;
if ((precondition = parseAnd<ast::Precondition>(context, astContext, variableStack, parsePrecondition))
|| (precondition = parseOr<ast::Precondition>(context, astContext, variableStack, parsePrecondition))
|| (precondition = parseExists<ast::Precondition>(context, astContext, variableStack, parsePrecondition))
|| (precondition = parseForAll<ast::Precondition>(context, astContext, variableStack, parsePrecondition))
|| (precondition = parseNot<ast::Precondition>(context, astContext, variableStack, parsePrecondition))
|| (precondition = parseImply<ast::Precondition>(context, astContext, variableStack, parsePrecondition))
|| (precondition = parseAtomicFormula(context, astContext, variableStack)))
{
return std::move(precondition.value());
}
tokenizer.seek(expressionIdentifierPosition);
const auto expressionIdentifier = tokenizer.getIdentifier();
tokenizer.seek(position);
throw ParserException(tokenizer.location(), "expression type “" + expressionIdentifier + "” unknown or not allowed in precondition body");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,94 @@
#include <pddl/detail/parsing/Predicate.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/detail/SignatureMatching.h>
#include <pddl/detail/parsing/Constant.h>
#include <pddl/detail/parsing/Variable.h>
#include <pddl/detail/parsing/VariableDeclaration.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Predicate
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::PredicatePointer> parsePredicate(Context &context, ASTContext &astContext, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
const auto previousPosition = tokenizer.position();
if (!tokenizer.testAndSkip<std::string>("("))
{
tokenizer.seek(previousPosition);
return std::experimental::nullopt;
}
const auto name = tokenizer.getIdentifier();
ast::Predicate::Arguments arguments;
tokenizer.skipWhiteSpace();
// Parse arguments
while (tokenizer.currentCharacter() != ')')
{
// Parse argument if it is a variable
auto variable = testParsingVariable(context, variableStack);
if (variable)
{
arguments.emplace_back(std::move(variable.value()));
tokenizer.skipWhiteSpace();
continue;
}
// Parse argument if it is a constant
auto constant = testParsingConstant(context, astContext);
if (constant)
{
arguments.emplace_back(std::move(constant.value()));
tokenizer.skipWhiteSpace();
continue;
}
// If argument is neither variable nor constant, this is not a valid predicate
tokenizer.seek(previousPosition);
return std::experimental::nullopt;
}
const auto &predicates = astContext.domain->predicates;
const auto matchingPredicateDeclaration = std::find_if(predicates.cbegin(), predicates.cend(),
[&](const auto &predicateDeclaration)
{
return matches(name, arguments, *predicateDeclaration);
});
if (matchingPredicateDeclaration == predicates.cend())
{
// TODO: enumerate candidates and why they are incompatible
tokenizer.seek(previousPosition);
throw ParserException(tokenizer.location(), "no matching declaration found for predicate “" + name + "");
}
auto *declaration = matchingPredicateDeclaration->get();
tokenizer.expect<std::string>(")");
return std::make_unique<ast::Predicate>(std::move(arguments), declaration);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,53 @@
#include <pddl/detail/parsing/PredicateDeclaration.h>
#include <pddl/Exception.h>
#include <pddl/detail/ASTContext.h>
#include <pddl/detail/parsing/VariableDeclaration.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PredicateDeclaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddPredicateDeclaration(Context &context, ast::Domain &domain)
{
auto &tokenizer = context.tokenizer;
tokenizer.expect<std::string>("(");
auto name = tokenizer.getIdentifier();
tokenizer.skipWhiteSpace();
// Parse parameters
auto parameters = parseVariableDeclarations(context, domain);
tokenizer.expect<std::string>(")");
domain.predicates.emplace_back(std::make_unique<ast::PredicateDeclaration>(std::move(name), std::move(parameters)));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddPredicateDeclarations(Context &context, ast::Domain &domain)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
while (tokenizer.currentCharacter() != ')')
{
parseAndAddPredicateDeclaration(context, domain);
tokenizer.skipWhiteSpace();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,56 @@
#include <pddl/detail/parsing/PrimitiveType.h>
#include <pddl/Exception.h>
#include <pddl/detail/Requirements.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PrimitiveType
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::PrimitiveTypePointer parsePrimitiveType(Context &context, ast::Domain &domain)
{
auto &tokenizer = context.tokenizer;
auto &types = domain.types;
auto typeName = tokenizer.getIdentifier();
if (typeName.empty())
throw ParserException(tokenizer.location(), "could not parse primitive type, expected identifier");
auto matchingType = std::find_if(types.begin(), types.end(),
[&](auto &primitiveTypeDeclaration)
{
return primitiveTypeDeclaration->name == typeName;
});
// If the type has not been declared yet, add it but issue a warning
if (matchingType == types.end())
{
// “object” type is always allowed without warning
if (typeName != "object")
{
if (context.mode != Mode::Compatibility)
throw ParserException(tokenizer.location(), "primitive type “" + typeName + "” used without or before declaration");
context.warningCallback(tokenizer.location(), "primitive type “" + typeName + "” used without or before declaration, silently adding declaration");
}
types.emplace_back(std::make_unique<ast::PrimitiveTypeDeclaration>(std::move(typeName)));
return std::make_unique<ast::PrimitiveType>(types.back().get());
}
return std::make_unique<ast::PrimitiveType>(matchingType->get());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,93 @@
#include <pddl/detail/parsing/PrimitiveTypeDeclaration.h>
#include <pddl/Exception.h>
#include <pddl/detail/ASTCopy.h>
#include <pddl/detail/parsing/PrimitiveType.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PrimitiveTypeDeclaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::PrimitiveTypeDeclarationPointer *> findPrimitiveTypeDeclaration(ast::Domain &domain, const std::string &typeName)
{
auto &types = domain.types;
const auto matchingPrimitiveType = std::find_if(types.begin(), types.end(),
[&](const auto &primitiveType)
{
return primitiveType->name == typeName;
});
if (matchingPrimitiveType != types.end())
return &*matchingPrimitiveType;
return std::experimental::nullopt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::PrimitiveTypeDeclarationPointer &parseAndAddUntypedPrimitiveTypeDeclaration(Context &context, ast::Domain &domain, std::vector<bool> &flaggedTypes)
{
auto &tokenizer = context.tokenizer;
auto typeName = tokenizer.getIdentifier();
auto &types = domain.types;
auto matchingPrimitiveTypeDeclaration = findPrimitiveTypeDeclaration(domain, typeName);
if (matchingPrimitiveTypeDeclaration)
return *matchingPrimitiveTypeDeclaration.value();
types.emplace_back(std::make_unique<ast::PrimitiveTypeDeclaration>(std::move(typeName)));
flaggedTypes.emplace_back(false);
return types.back();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddPrimitiveTypeDeclarations(Context &context, ast::Domain &domain)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
auto &types = domain.types;
assert(types.empty());
std::vector<bool> flaggedTypes;
while (tokenizer.currentCharacter() != ')')
{
auto &childType = parseAndAddUntypedPrimitiveTypeDeclaration(context, domain, flaggedTypes);
flaggedTypes[&childType - &types.front()] = true;
tokenizer.skipWhiteSpace();
if (!tokenizer.testAndSkip<char>('-'))
continue;
// Skip parent type information for now
auto &parentType = parseAndAddUntypedPrimitiveTypeDeclaration(context, domain, flaggedTypes);
for (size_t i = 0; i < flaggedTypes.size(); i++)
if (flaggedTypes[i])
{
flaggedTypes[i] = false;
types[i]->parentTypes.emplace_back(std::make_unique<ast::PrimitiveType>(parentType.get()));
}
tokenizer.skipWhiteSpace();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,293 @@
#include <pddl/detail/parsing/Problem.h>
#include <pddl/Exception.h>
#include <pddl/detail/Requirements.h>
#include <pddl/detail/parsing/ConstantDeclaration.h>
#include <pddl/detail/parsing/InitialState.h>
#include <pddl/detail/parsing/Precondition.h>
#include <pddl/detail/parsing/Requirement.h>
#include <pddl/detail/parsing/Unsupported.h>
#include <pddl/detail/parsing/Utils.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Problem
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ProblemParser::ProblemParser(Context &context, ast::Domain &domain)
: m_context{context},
m_domain{domain},
m_domainPosition{tokenize::InvalidStreamPosition},
m_requirementsPosition{tokenize::InvalidStreamPosition},
m_objectsPosition{tokenize::InvalidStreamPosition},
m_initialStatePosition{tokenize::InvalidStreamPosition},
m_goalPosition{tokenize::InvalidStreamPosition}
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::ProblemPointer ProblemParser::parse()
{
auto problem = std::make_unique<ast::Problem>(&m_domain);
findSections(*problem);
auto &tokenizer = m_context.tokenizer;
if (m_domainPosition == tokenize::InvalidStreamPosition)
throw ParserException(tokenizer.location(), "problem description does not specify a corresponding domain");
tokenizer.seek(m_domainPosition);
parseDomainSection(*problem);
if (m_requirementsPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_requirementsPosition);
parseRequirementSection(*problem);
}
if (m_objectsPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(m_objectsPosition);
parseObjectSection(*problem);
}
if (m_initialStatePosition == tokenize::InvalidStreamPosition)
throw ParserException(tokenizer.location(), "problem description does not specify an initial state");
tokenizer.seek(m_initialStatePosition);
parseInitialStateSection(*problem);
if (m_goalPosition == tokenize::InvalidStreamPosition)
throw ParserException(tokenizer.location(), "problem description does not specify a goal");
tokenizer.seek(m_goalPosition);
parseGoalSection(*problem);
return problem;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ProblemParser::findSections(ast::Problem &problem)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>("define");
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>("problem");
problem.name = tokenizer.getIdentifier();
tokenizer.expect<std::string>(")");
const auto setSectionPosition =
[&](const std::string &sectionName, auto &sectionPosition, const auto value, bool unique = false)
{
if (unique && sectionPosition != tokenize::InvalidStreamPosition)
{
tokenizer.seek(value);
throw ParserException(tokenizer.location(), "only one “:" + sectionName + "” section allowed");
}
sectionPosition = value;
};
tokenizer.skipWhiteSpace();
while (tokenizer.currentCharacter() != ')')
{
const auto position = tokenizer.position();
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
if (tokenizer.testIdentifierAndSkip("domain"))
setSectionPosition("domain", m_domainPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("requirements"))
setSectionPosition("requirements", m_requirementsPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("objects"))
setSectionPosition("objects", m_objectsPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("init"))
setSectionPosition("init", m_initialStatePosition, position, true);
else if (tokenizer.testIdentifierAndSkip("goal"))
setSectionPosition("goal", m_goalPosition, position, true);
else if (tokenizer.testIdentifierAndSkip("constraints")
|| tokenizer.testIdentifierAndSkip("metric")
|| tokenizer.testIdentifierAndSkip("length"))
{
throw exceptUnsupportedSection(position, m_context);
}
else
{
const auto sectionIdentifier = tokenizer.getIdentifier();
tokenizer.seek(position);
throw ParserException(tokenizer.location(), "unknown problem section “" + sectionIdentifier + "");
}
// Skip section for now and parse it later
skipSection(tokenizer);
tokenizer.skipWhiteSpace();
}
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ProblemParser::parseDomainSection(ast::Problem &problem)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("domain");
tokenizer.skipWhiteSpace();
const auto domainName = tokenizer.getIdentifier();
if (problem.domain->name != domainName)
throw ParserException(tokenizer.location(), "domains do not match (“" + problem.domain->name + "” and “" + domainName + "”)");
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ProblemParser::parseRequirementSection(ast::Problem &problem)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("requirements");
while (tokenizer.currentCharacter() != ')')
{
tokenizer.expect<std::string>(":");
const auto requirement = parseRequirement(m_context);
if (requirement)
problem.requirements.emplace_back(requirement.value());
tokenizer.skipWhiteSpace();
}
// TODO: do this check only once the problem is parsed
// If no requirements are specified, assume STRIPS
if (problem.requirements.empty())
problem.requirements.emplace_back(ast::Requirement::STRIPS);
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: refactor, exists identically in DomainParser
void ProblemParser::computeDerivedRequirements(ast::Problem &problem)
{
const auto addRequirementUnique =
[&](const auto requirement)
{
if (hasRequirement(problem, requirement))
return;
problem.requirements.push_back(ast::Requirement(requirement));
};
if (hasRequirement(problem, ast::Requirement::ADL))
{
addRequirementUnique(ast::Requirement::STRIPS);
addRequirementUnique(ast::Requirement::Typing);
addRequirementUnique(ast::Requirement::NegativePreconditions);
addRequirementUnique(ast::Requirement::DisjunctivePreconditions);
addRequirementUnique(ast::Requirement::Equality);
addRequirementUnique(ast::Requirement::QuantifiedPreconditions);
addRequirementUnique(ast::Requirement::ConditionalEffects);
}
if (hasRequirement(problem, ast::Requirement::QuantifiedPreconditions))
{
addRequirementUnique(ast::Requirement::ExistentialPreconditions);
addRequirementUnique(ast::Requirement::UniversalPreconditions);
}
if (hasRequirement(problem, ast::Requirement::Fluents))
{
addRequirementUnique(ast::Requirement::NumericFluents);
addRequirementUnique(ast::Requirement::ObjectFluents);
}
if (hasRequirement(problem, ast::Requirement::TimedInitialLiterals))
addRequirementUnique(ast::Requirement::DurativeActions);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ProblemParser::parseObjectSection(ast::Problem &problem)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("objects");
// Store constants
parseAndAddConstantDeclarations(m_context, problem);
tokenizer.expect<std::string>(")");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ProblemParser::parseInitialStateSection(ast::Problem &problem)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("init");
ASTContext astContext(problem);
VariableStack variableStack;
problem.initialState = parseInitialState(m_context, astContext, variableStack);
tokenizer.expect<std::string>(")");
skipSection(tokenizer);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ProblemParser::parseGoalSection(ast::Problem &problem)
{
auto &tokenizer = m_context.tokenizer;
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
tokenizer.expect<std::string>("goal");
ASTContext astContext(problem);
VariableStack variableStack;
problem.goal = parsePrecondition(m_context, astContext, variableStack);
skipSection(tokenizer);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,93 @@
#include <pddl/detail/parsing/Requirement.h>
#include <cstring>
#include <map>
#include <pddl/AST.h>
#include <pddl/Exception.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Requirement
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct CompareStrings
{
bool operator()(const char *lhs, const char *rhs) const
{
return std::strcmp(lhs, rhs) < 0;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
using RequirementNameMap = std::map<const char *, ast::Requirement, CompareStrings>;
static const RequirementNameMap requirementNameMap =
{
{"strips", ast::Requirement::STRIPS},
{"typing", ast::Requirement::Typing},
{"negative-preconditions", ast::Requirement::NegativePreconditions},
{"disjunctive-preconditions", ast::Requirement::DisjunctivePreconditions},
{"equality", ast::Requirement::Equality},
{"existential-preconditions", ast::Requirement::ExistentialPreconditions},
{"universal-preconditions", ast::Requirement::UniversalPreconditions},
{"quantified-preconditions", ast::Requirement::QuantifiedPreconditions},
{"conditional-effects", ast::Requirement::ConditionalEffects},
{"fluents", ast::Requirement::Fluents},
{"numeric-fluents", ast::Requirement::NumericFluents},
{"object-fluents", ast::Requirement::ObjectFluents},
{"adl", ast::Requirement::ADL},
{"durative-actions", ast::Requirement::DurativeActions},
{"duration-inequalities", ast::Requirement::DurationInequalities},
{"continuous-effects", ast::Requirement::ContinuousEffects},
{"derived-predicates", ast::Requirement::DerivedPredicates},
{"timed-initial-literals", ast::Requirement::TimedInitialLiterals},
{"preferences", ast::Requirement::Preferences},
{"constraints", ast::Requirement::Constraints},
{"action-costs", ast::Requirement::ActionCosts},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::Requirement> parseRequirement(Context &context)
{
auto &tokenizer = context.tokenizer;
const auto requirementName = tokenizer.getIdentifier();
const auto matchingRequirement = requirementNameMap.find(requirementName.c_str());
if (matchingRequirement != requirementNameMap.cend())
return matchingRequirement->second;
if (context.mode == Mode::Compatibility && (requirementName == "goal-utilities" || requirementName == "domain-axioms"))
context.warningCallback(tokenizer.location(), "" + requirementName + "” requirement is not part of the PDDL 3.1 specification, ignoring requirement");
return std::experimental::nullopt;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
const char *toString(const ast::Requirement &requirement)
{
const auto matchingRequirement = std::find_if(requirementNameMap.cbegin(), requirementNameMap.cend(),
[&](const auto &requirementNamePair)
{
return requirementNamePair.second == requirement;
});
assert(matchingRequirement != requirementNameMap.cend());
return matchingRequirement->first;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,52 @@
#include <pddl/detail/parsing/Type.h>
#include <pddl/Exception.h>
#include <pddl/detail/parsing/Expressions.h>
#include <pddl/detail/parsing/PrimitiveType.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Type
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::Type parseType(Context &context, ast::Domain &domain)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
if (tokenizer.testAndReturn<char>('('))
{
// TODO: refactor
auto parsePrimitiveTypeWrapper =
[](auto &context, auto &astContext, auto &) -> std::experimental::optional<ast::PrimitiveTypePointer>
{
return parsePrimitiveType(context, *astContext.domain);
};
// TODO: refactor
ASTContext astContext(domain);
VariableStack variableStack;
auto eitherType = parseEither<ast::PrimitiveTypePointer>(context, astContext, variableStack, parsePrimitiveTypeWrapper);
if (!eitherType)
throw ParserException(tokenizer.location(), "expected primitive type or “either” expression");
return std::move(eitherType.value());
}
// If existing, parse and store parent type
return parsePrimitiveType(context, domain);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,45 @@
#include <pddl/detail/parsing/Unsupported.h>
#include <pddl/AST.h>
#include <pddl/detail/parsing/Utils.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Unsupported
//
////////////////////////////////////////////////////////////////////////////////////////////////////
ParserException exceptUnsupportedExpression(tokenize::StreamPosition position, Context &context)
{
auto &tokenizer = context.tokenizer;
tokenizer.seek(position);
tokenizer.expect<std::string>("(");
auto expressionType = tokenizer.getIdentifier();
return ParserException(tokenizer.location(position), "" + expressionType + "” expressions currently unsupported");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ParserException exceptUnsupportedSection(tokenize::StreamPosition position, Context &context)
{
auto &tokenizer = context.tokenizer;
tokenizer.seek(position);
tokenizer.expect<std::string>("(");
tokenizer.expect<std::string>(":");
auto sectionType = tokenizer.getIdentifier();
return ParserException(tokenizer.location(position), "“:" + sectionType + "” sections currently unsupported");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,75 @@
#include <pddl/detail/parsing/Variable.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Predicate
//
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<std::string> testParsingVariableName(Context &context)
{
auto &tokenizer = context.tokenizer;
if (!tokenizer.testAndReturn<std::string>("?"))
return std::experimental::nullopt;
tokenizer.expect<std::string>("?");
return tokenizer.getIdentifier();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::string parseVariableName(Context &context)
{
auto &tokenizer = context.tokenizer;
tokenizer.expect<std::string>("?");
return tokenizer.getIdentifier();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::experimental::optional<ast::VariablePointer> testParsingVariable(Context &context, VariableStack &variableStack)
{
auto variableName = testParsingVariableName(context);
if (!variableName)
return std::experimental::nullopt;
auto variableDeclaration = variableStack.findVariableDeclaration(variableName.value());
if (!variableDeclaration)
return std::experimental::nullopt;
return std::make_unique<ast::Variable>(variableDeclaration.value());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::VariablePointer parseVariable(Context &context, VariableStack &variableStack)
{
auto &tokenizer = context.tokenizer;
auto variableName = parseVariableName(context);
auto variableDeclaration = variableStack.findVariableDeclaration(variableName);
if (!variableDeclaration)
throw ParserException(tokenizer.location(), "undeclared variable “" + variableName + "");
return std::make_unique<ast::Variable>(variableDeclaration.value());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,87 @@
#include <pddl/detail/parsing/VariableDeclaration.h>
#include <pddl/AST.h>
#include <pddl/Exception.h>
#include <pddl/detail/ASTCopy.h>
#include <pddl/detail/parsing/Type.h>
namespace pddl
{
namespace detail
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// VariableDeclaration
//
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddUntypedVariableDeclaration(Context &context, ast::VariableDeclarations &variableDeclarations)
{
auto &tokenizer = context.tokenizer;
tokenizer.expect<std::string>("?");
const auto position = tokenizer.position();
auto variableName = tokenizer.getIdentifier();
if (variableName == "" || variableName == "-")
{
tokenizer.seek(position);
throw ParserException(tokenizer.location(), "could not parse variable name");
}
variableDeclarations.emplace_back(std::make_unique<ast::VariableDeclaration>(std::move(variableName)));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void parseAndAddVariableDeclarations(Context &context, ast::Domain &domain, ast::VariableDeclarations &variableDeclarations)
{
auto &tokenizer = context.tokenizer;
tokenizer.skipWhiteSpace();
// Index on the first element of the current inheritance list
size_t inheritanceIndex = variableDeclarations.size();
while (tokenizer.currentCharacter() != ')')
{
parseAndAddUntypedVariableDeclaration(context, variableDeclarations);
tokenizer.skipWhiteSpace();
if (!tokenizer.testAndSkip<char>('-'))
continue;
auto parentType = parseType(context, domain);
for (size_t i = inheritanceIndex; i < variableDeclarations.size(); i++)
variableDeclarations[i]->type = ast::deepCopy(parentType);
// All types up to now are labeled with their parent types
inheritanceIndex = variableDeclarations.size();
tokenizer.skipWhiteSpace();
}
const bool isTypingUsed = !domain.types.empty();
if (isTypingUsed && !variableDeclarations.empty() && !variableDeclarations.back()->type)
throw ParserException(tokenizer.location(), "missing type declaration for variable “?" + variableDeclarations.back()->name + "");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ast::VariableDeclarations parseVariableDeclarations(Context &context, ast::Domain &domain)
{
ast::VariableDeclarations result;
parseAndAddVariableDeclarations(context, domain, result);
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@@ -0,0 +1,24 @@
set(target pddl-tests)
file(GLOB core_sources "*.cpp")
set(includes
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/../../lib/catch/single_include
${PROJECT_SOURCE_DIR}/../../lib/tokenize/include
${PROJECT_SOURCE_DIR}/../../lib/variant/include
)
set(libraries
stdc++fs
pddl
)
add_executable(${target} ${core_sources})
target_include_directories(${target} PRIVATE ${includes})
target_link_libraries(${target} ${libraries})
add_custom_target(run-pddl-tests
COMMAND ${CMAKE_BINARY_DIR}/bin/pddl-tests --use-colour=yes
DEPENDS ${target}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/../../tests)

View File

@@ -0,0 +1,183 @@
#include <catch.hpp>
#include <experimental/filesystem>
#include <set>
#include <pddl/AST.h>
#include <pddl/Parse.h>
namespace fs = std::experimental::filesystem;
const pddl::Context::WarningCallback ignoreWarnings = [](const auto &, const auto &){};
const auto pddlInstanceBasePath = fs::path("data") / "pddl-instances";
const std::set<std::experimental::filesystem::path> unsupportedDomains =
{
// “=” expressions unsupported
pddlInstanceBasePath / "ipc-1998" / "domains" / "assembly-round-1-adl" / "domain.pddl",
// “=” expressions unsupported
pddlInstanceBasePath / "ipc-1998" / "domains" / "mystery-prime-round-1-strips" / "domain.pddl",
// “=” expressions unsupported
pddlInstanceBasePath / "ipc-1998" / "domains" / "mystery-prime-round-2-strips" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "depots-numeric-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "depots-numeric-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "depots-time-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "depots-time-hand-coded" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "depots-time-simple-automatic" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "depots-time-simple-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "driverlog-numeric-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "driverlog-numeric-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "driverlog-numeric-hard-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "driverlog-numeric-hard-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "driverlog-time-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "driverlog-time-hand-coded" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "driverlog-time-simple-automatic" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "driverlog-time-simple-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "rovers-numeric-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "rovers-numeric-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "rovers-time-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "rovers-time-hand-coded" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "rovers-time-simple-automatic" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "rovers-time-simple-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-complex-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-complex-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-numeric-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-numeric-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-numeric-hard-automatic" / "domain.pddl",
// “=” expressions unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-strips-automatic" / "domain.pddl",
// “=” expressions unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-strips-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-time-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-time-hand-coded" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-time-simple-automatic" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "satellite-time-simple-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "settlers-numeric-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "umtranslog-2-numeric-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-numeric-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-numeric-hand-coded" / "domain.pddl",
// “either” expressions unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-strips-automatic" / "domain.pddl",
// “either” expressions unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-strips-hand-coded" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-time-automatic" / "domain.pddl",
// “:functions” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-time-hand-coded" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-time-simple-automatic" / "domain.pddl",
// “:durative-action” sections unsupported
pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-time-simple-hand-coded" / "domain.pddl",
};
const std::set<std::experimental::filesystem::path> unsupportedInstances =
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[PDDL acceptance] All official PDDL domains are parsed without errors", "[PDDL acceptance]")
{
for (const auto &competitionDirectory : fs::directory_iterator(pddlInstanceBasePath))
{
if (!fs::is_directory(competitionDirectory))
continue;
for (const auto &domainDirectory : fs::directory_iterator(competitionDirectory.path() / "domains"))
{
if (!fs::is_directory(domainDirectory))
continue;
const auto domainFile = domainDirectory / "domain.pddl";
if (unsupportedDomains.find(domainFile) != unsupportedDomains.cend())
continue;
const auto testSectionName = competitionDirectory.path().stem().string() + ", "
+ domainDirectory.path().stem().string();
SECTION("domain [" + testSectionName + "]")
{
pddl::Tokenizer tokenizer;
tokenizer.read(domainFile);
pddl::Context context(std::move(tokenizer), ignoreWarnings, pddl::Mode::Compatibility);
CHECK_NOTHROW(pddl::parseDescription(context));
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[PDDL acceptance] The first instance for all official PDDL domains is parsed without errors", "[PDDL acceptance]")
{
for (const auto &competitionDirectory : fs::directory_iterator(pddlInstanceBasePath))
{
if (!fs::is_directory(competitionDirectory))
continue;
for (const auto &domainDirectory : fs::directory_iterator(competitionDirectory.path() / "domains"))
{
if (!fs::is_directory(domainDirectory))
continue;
const auto domainFile = domainDirectory / "domain.pddl";
const auto instanceFile = domainDirectory / "instances" / "instance-1.pddl";
if (unsupportedDomains.find(domainFile) != unsupportedDomains.cend()
|| unsupportedInstances.find(instanceFile) != unsupportedInstances.cend())
{
continue;
}
const auto testSectionName = competitionDirectory.path().stem().string() + ", "
+ domainDirectory.path().stem().string() + ", "
+ instanceFile.stem().string();
SECTION("instance [" + testSectionName + "]")
{
pddl::Tokenizer tokenizer;
tokenizer.read(domainFile);
tokenizer.read(instanceFile);
pddl::Context context(std::move(tokenizer), ignoreWarnings, pddl::Mode::Compatibility);
CHECK_NOTHROW(pddl::parseDescription(context));
}
}
}
}

View File

@@ -0,0 +1,87 @@
#include <catch.hpp>
#include <experimental/filesystem>
#include <pddl/AST.h>
#include <pddl/Parse.h>
namespace fs = std::experimental::filesystem;
const pddl::Context::WarningCallback ignoreWarnings = [](const auto &, const auto &){};
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[PDDL parser issues] Check past issues", "[PDDL parser issues]")
{
pddl::Tokenizer tokenizer;
pddl::Context context(std::move(tokenizer), ignoreWarnings);
SECTION("white space issues with constants and parsing unsupported sections")
{
const auto domainFile = fs::path("data") / "issues" / "issue-1.pddl";
context.tokenizer.read(domainFile);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("white space issues with empty n-ary predicates")
{
const auto domainFile = fs::path("data") / "issues" / "issue-2.pddl";
context.tokenizer.read(domainFile);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("comments are correctly ignored")
{
const auto domainFile = fs::path("data") / "issues" / "issue-3.pddl";
context.tokenizer.read(domainFile);
CHECK_NOTHROW(pddl::parseDescription(context));
}
// Check that no infinite loop occurs
SECTION("“either” in typing section")
{
const auto domainFile = fs::path("data") / "issues" / "issue-7.pddl";
context.tokenizer.read(domainFile);
CHECK_THROWS(pddl::parseDescription(context));
}
// Check that whitespace is correctly ignored in type section
SECTION("whitespace in typing section")
{
const auto domainFile = fs::path("data") / "issues" / "issue-8.pddl";
context.tokenizer.read(domainFile);
CHECK_NOTHROW(pddl::parseDescription(context));
}
// Check that accidentally unnamed variables lead to an exception and not a segfault
SECTION("whitespace in typing section")
{
const auto domainFile = fs::path("data") / "issues" / "issue-9.pddl";
context.tokenizer.read(domainFile);
CHECK_THROWS(pddl::parseDescription(context));
}
// Check that “at” is allowed as a predicate name and not exclusively for “at” expressions
SECTION("“at” as predicate name")
{
const auto domainFile = fs::path("data") / "issues" / "issue-10.pddl";
context.tokenizer.read(domainFile);
const auto description = pddl::parseDescription(context);
REQUIRE(description.problem);
const auto &problem = description.problem.value();
const auto &facts = problem->initialState.facts;
const auto invalidFact = std::find_if(facts.cbegin(), facts.cend(),
[](const auto &fact)
{
return fact.template is<pddl::ast::AtPointer<pddl::ast::Literal>>();
});
const auto containsInvalidFact = (invalidFact != facts.cend());
CHECK(!containsInvalidFact);
}
}

View File

@@ -0,0 +1,383 @@
#include <catch.hpp>
#include <experimental/filesystem>
#include <pddl/AST.h>
#include <pddl/Parse.h>
namespace fs = std::experimental::filesystem;
const pddl::Context::WarningCallback ignoreWarnings = [](const auto &, const auto &){};
const auto pddlInstanceBasePath = fs::path("data") / "pddl-instances";
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[PDDL instances] The official PDDL instances are parsed correctly", "[PDDL instances]")
{
pddl::Tokenizer tokenizer;
pddl::Context context(std::move(tokenizer), ignoreWarnings);
SECTION("types, predicates, and actions in blocksworld domain")
{
const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "blocks-strips-typed" / "domain.pddl";
context.tokenizer.read(domainFile);
auto description = pddl::parseDescription(context);
CHECK(description.domain->name == "blocks");
CHECK(description.domain->constants.empty());
const auto &types = description.domain->types;
REQUIRE(types.size() == 1);
const auto &typeBlock = types[0];
CHECK(typeBlock->name == "block");
const auto &predicates = description.domain->predicates;
REQUIRE(predicates.size() == 5);
CHECK(predicates[0]->name == "on");
REQUIRE(predicates[0]->parameters.size() == 2);
CHECK(predicates[0]->parameters[0]->name == "x");
CHECK(predicates[0]->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(predicates[0]->parameters[1]->name == "y");
CHECK(predicates[0]->parameters[1]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(predicates[1]->name == "ontable");
REQUIRE(predicates[1]->parameters.size() == 1);
CHECK(predicates[1]->parameters[0]->name == "x");
CHECK(predicates[1]->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(predicates[2]->name == "clear");
REQUIRE(predicates[2]->parameters.size() == 1);
CHECK(predicates[2]->parameters[0]->name == "x");
CHECK(predicates[2]->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(predicates[3]->name == "handempty");
CHECK(predicates[3]->parameters.empty());
CHECK(predicates[4]->name == "holding");
REQUIRE(predicates[4]->parameters.size() == 1);
CHECK(predicates[4]->parameters[0]->name == "x");
CHECK(predicates[4]->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &actions = description.domain->actions;
REQUIRE(actions.size() == 4);
CHECK(actions[3]->name == "unstack");
REQUIRE(actions[3]->parameters.size() == 2);
CHECK(actions[3]->parameters[0]->name == "x");
CHECK(actions[3]->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(actions[3]->parameters[1]->name == "y");
CHECK(actions[3]->parameters[1]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &preconditionAnd = actions[3]->precondition.value().get<pddl::ast::AndPointer<pddl::ast::Precondition>>();
const auto &precondition0 = preconditionAnd->arguments[0].get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(precondition0->arguments.size() == 2);
CHECK(precondition0->arguments[0].get<pddl::ast::VariablePointer>()->declaration->name == "x");
CHECK(precondition0->arguments[0].get<pddl::ast::VariablePointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(precondition0->arguments[1].get<pddl::ast::VariablePointer>()->declaration->name == "y");
CHECK(precondition0->arguments[1].get<pddl::ast::VariablePointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &precondition1 = preconditionAnd->arguments[1].get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(precondition1->arguments.size() == 1);
CHECK(precondition1->arguments[0].get<pddl::ast::VariablePointer>()->declaration->name == "x");
CHECK(precondition1->arguments[0].get<pddl::ast::VariablePointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &precondition2 = preconditionAnd->arguments[2].get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(precondition2->arguments.empty());
const auto &effectAnd = actions[3]->effect.value().get<pddl::ast::AndPointer<pddl::ast::Effect>>();
const auto &effect0 = effectAnd->arguments[0].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(effect0->arguments.size() == 1);
CHECK(effect0->arguments[0].get<pddl::ast::VariablePointer>()->declaration->name == "x");
CHECK(effect0->arguments[0].get<pddl::ast::VariablePointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &effect1 = effectAnd->arguments[1].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(effect1->arguments.size() == 1);
CHECK(effect1->arguments[0].get<pddl::ast::VariablePointer>()->declaration->name == "y");
CHECK(effect1->arguments[0].get<pddl::ast::VariablePointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &effectNot2 = effectAnd->arguments[2].get<pddl::ast::Literal>().get<pddl::ast::NotPointer<pddl::ast::AtomicFormula>>()->argument.get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(effectNot2->arguments.size() == 1);
CHECK(effectNot2->arguments[0].get<pddl::ast::VariablePointer>()->declaration->name == "x");
CHECK(effectNot2->arguments[0].get<pddl::ast::VariablePointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &effectNot3 = effectAnd->arguments[3].get<pddl::ast::Literal>().get<pddl::ast::NotPointer<pddl::ast::AtomicFormula>>()->argument.get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(effectNot3->arguments.empty());
const auto &effectNot4 = effectAnd->arguments[4].get<pddl::ast::Literal>().get<pddl::ast::NotPointer<pddl::ast::AtomicFormula>>()->argument.get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(effectNot4->arguments.size() == 2);
CHECK(effectNot4->arguments[0].get<pddl::ast::VariablePointer>()->declaration->name == "x");
CHECK(effectNot4->arguments[0].get<pddl::ast::VariablePointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(effectNot4->arguments[1].get<pddl::ast::VariablePointer>()->declaration->name == "y");
CHECK(effectNot4->arguments[1].get<pddl::ast::VariablePointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
}
SECTION("types, predicates, and actions in blocksworld instance")
{
const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "blocks-strips-typed" / "domain.pddl";
const auto instanceFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "blocks-strips-typed" / "instances" / "instance-1.pddl";
context.tokenizer.read(domainFile);
context.tokenizer.read(instanceFile);
auto description = pddl::parseDescription(context);
const auto &types = description.domain->types;
const auto &typeBlock = types[0];
REQUIRE(description.problem);
const auto &problem = description.problem.value();
CHECK(problem->name == "blocks-4-0");
CHECK(problem->domain->name == "blocks");
const auto &objects = problem->objects;
REQUIRE(objects.size() == 4);
CHECK(objects[0]->name == "d");
CHECK(objects[1]->name == "b");
CHECK(objects[2]->name == "a");
CHECK(objects[3]->name == "c");
const auto &facts = problem->initialState.facts;
REQUIRE(facts.size() == 9);
const auto &fact0 = facts[0].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(fact0->arguments.size() == 1);
CHECK(fact0->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->name == "c");
CHECK(fact0->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &fact5 = facts[5].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(fact5->arguments.size() == 1);
CHECK(fact5->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->name == "a");
CHECK(fact5->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &fact8 = facts[8].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(fact8->arguments.empty());
REQUIRE(problem->goal);
const auto &goal = problem->goal.value();
const auto &goalAnd = goal.get<pddl::ast::AndPointer<pddl::ast::Precondition>>();
REQUIRE(goalAnd->arguments.size() == 3);
const auto &goal0 = goalAnd->arguments[0].get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(goal0->arguments.size() == 2);
CHECK(goal0->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->name == "d");
CHECK(goal0->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(goal0->arguments[1].get<pddl::ast::ConstantPointer>()->declaration->name == "c");
CHECK(goal0->arguments[1].get<pddl::ast::ConstantPointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &goal1 = goalAnd->arguments[1].get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(goal0->arguments.size() == 2);
CHECK(goal1->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->name == "c");
CHECK(goal1->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(goal1->arguments[1].get<pddl::ast::ConstantPointer>()->declaration->name == "b");
CHECK(goal1->arguments[1].get<pddl::ast::ConstantPointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
const auto &goal2 = goalAnd->arguments[2].get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>();
// TODO: check declaration once implemented
REQUIRE(goal0->arguments.size() == 2);
CHECK(goal2->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->name == "b");
CHECK(goal2->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
CHECK(goal2->arguments[1].get<pddl::ast::ConstantPointer>()->declaration->name == "a");
CHECK(goal2->arguments[1].get<pddl::ast::ConstantPointer>()->declaration->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration == typeBlock.get());
}
SECTION("“either” type in zenotravel domain")
{
context.mode = pddl::Mode::Compatibility;
const auto domainFile = pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-strips-hand-coded" / "domain.pddl";
context.tokenizer.read(domainFile);
auto description = pddl::parseDescription(context);
const auto &predicates = description.domain->predicates;
REQUIRE(predicates.size() == 4);
REQUIRE(predicates[0]->name == "at");
REQUIRE(predicates[0]->parameters.size() == 2);
REQUIRE(predicates[0]->parameters[0]->name == "x");
REQUIRE(predicates[0]->parameters[0]->type);
CHECK(predicates[0]->parameters[0]->type.value().get<pddl::ast::EitherPointer<pddl::ast::PrimitiveTypePointer>>()->arguments[0]->declaration->name == "person");
CHECK(predicates[0]->parameters[0]->type.value().get<pddl::ast::EitherPointer<pddl::ast::PrimitiveTypePointer>>()->arguments[1]->declaration->name == "aircraft");
REQUIRE(predicates[0]->parameters[1]->name == "c");
REQUIRE(predicates[0]->parameters[1]->type);
CHECK(predicates[0]->parameters[1]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "city");
}
SECTION("typed constants in schedule domain")
{
context.mode = pddl::Mode::Compatibility;
const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "schedule-adl-typed" / "domain.pddl";
context.tokenizer.read(domainFile);
auto description = pddl::parseDescription(context);
const auto &constants = description.domain->constants;
REQUIRE(constants.size() == 14);
CHECK(constants[0]->name == "cold");
CHECK(constants[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "temperature");
CHECK(constants[1]->name == "hot");
CHECK(constants[1]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "temperature");
CHECK(constants[2]->name == "cylindrical");
CHECK(constants[2]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "ashape");
CHECK(constants[3]->name == "polisher");
CHECK(constants[3]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "machine");
CHECK(constants[4]->name == "roller");
CHECK(constants[4]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "machine");
CHECK(constants[10]->name == "immersion-painter");
CHECK(constants[10]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "machine");
CHECK(constants[11]->name == "polished");
CHECK(constants[11]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "surface");
CHECK(constants[13]->name == "smooth");
CHECK(constants[13]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "surface");
}
SECTION("type inheritance in logistics domain")
{
context.mode = pddl::Mode::Compatibility;
const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "logistics-strips-typed" / "domain.pddl";
context.tokenizer.read(domainFile);
auto description = pddl::parseDescription(context);
const auto &types = description.domain->types;
REQUIRE(types.size() == 10);
CHECK(types[0]->name == "truck");
REQUIRE(types[0]->parentTypes.size() == 1);
CHECK(types[0]->parentTypes[0]->declaration->name == "vehicle");
CHECK(types[1]->name == "airplane");
REQUIRE(types[1]->parentTypes.size() == 1);
CHECK(types[1]->parentTypes[0]->declaration->name == "vehicle");
CHECK(types[2]->name == "vehicle");
REQUIRE(types[2]->parentTypes.size() == 1);
CHECK(types[2]->parentTypes[0]->declaration->name == "physobj");
CHECK(types[3]->name == "package");
REQUIRE(types[3]->parentTypes.size() == 1);
CHECK(types[3]->parentTypes[0]->declaration->name == "physobj");
CHECK(types[4]->name == "physobj");
REQUIRE(types[4]->parentTypes.size() == 1);
CHECK(types[4]->parentTypes[0]->declaration->name == "object");
CHECK(types[5]->name == "airport");
REQUIRE(types[5]->parentTypes.size() == 1);
CHECK(types[5]->parentTypes[0]->declaration->name == "place");
CHECK(types[6]->name == "location");
REQUIRE(types[6]->parentTypes.size() == 1);
CHECK(types[6]->parentTypes[0]->declaration->name == "place");
CHECK(types[7]->name == "place");
REQUIRE(types[7]->parentTypes.size() == 1);
CHECK(types[7]->parentTypes[0]->declaration->name == "object");
CHECK(types[8]->name == "city");
REQUIRE(types[8]->parentTypes.size() == 1);
CHECK(types[8]->parentTypes[0]->declaration->name == "object");
CHECK(types[9]->name == "object");
REQUIRE(types[9]->parentTypes.empty());
}
SECTION("typing in mystery domain")
{
context.mode = pddl::Mode::Compatibility;
const auto domainFile = pddlInstanceBasePath / "ipc-1998" / "domains" / "mystery-round-1-adl" / "domain.pddl";
const auto instanceFile = pddlInstanceBasePath / "ipc-1998" / "domains" / "mystery-round-1-adl" / "instances" / "instance-1.pddl";
context.tokenizer.read(domainFile);
context.tokenizer.read(instanceFile);
auto description = pddl::parseDescription(context);
const auto &actions = description.domain->actions;
REQUIRE(actions.size() == 3);
// TODO: adjust if there are changes to handling :vars section
REQUIRE(actions[0]->parameters.size() == 5);
CHECK(actions[0]->parameters[0]->name == "c");
CHECK(actions[0]->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "pain");
CHECK(actions[0]->parameters[1]->name == "v");
CHECK(actions[0]->parameters[1]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "pleasure");
CHECK(actions[0]->parameters[2]->name == "n");
CHECK(actions[0]->parameters[2]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "food");
CHECK(actions[0]->parameters[3]->name == "s1");
CHECK(actions[0]->parameters[3]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "planet");
CHECK(actions[0]->parameters[4]->name == "s2");
CHECK(actions[0]->parameters[4]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "planet");
REQUIRE(description.problem);
const auto &problem = description.problem.value();
const auto &objects = problem->objects;
REQUIRE(objects.size() == 21);
CHECK(objects[0]->name == "rice");
CHECK(objects[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "food");
CHECK(objects[1]->name == "pear");
CHECK(objects[1]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "food");
CHECK(objects[2]->name == "flounder");
CHECK(objects[2]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "food");
CHECK(objects[5]->name == "lamb");
CHECK(objects[5]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "food");
CHECK(objects[6]->name == "rest");
CHECK(objects[6]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "pleasure");
CHECK(objects[7]->name == "hangover");
CHECK(objects[7]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "pain");
CHECK(objects[8]->name == "depression");
CHECK(objects[8]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "pain");
CHECK(objects[9]->name == "abrasion");
CHECK(objects[9]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "pain");
CHECK(objects[10]->name == "kentucky");
CHECK(objects[10]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "province");
CHECK(objects[16]->name == "guanabara");
CHECK(objects[16]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "province");
CHECK(objects[17]->name == "mars");
CHECK(objects[17]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "planet");
CHECK(objects[20]->name == "venus");
CHECK(objects[20]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "planet");
}
SECTION("complicated nested effect expressions in schedule domain")
{
context.mode = pddl::Mode::Compatibility;
const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "schedule-adl-typed" / "domain.pddl";
context.tokenizer.read(domainFile);
auto description = pddl::parseDescription(context);
const auto &actions = description.domain->actions;
REQUIRE(actions.size() == 9);
CHECK(actions[1]->name == "do-roll");
const auto &effectAnd = actions[1]->effect.value().get<pddl::ast::AndPointer<pddl::ast::Effect>>();
REQUIRE(effectAnd->arguments.size() == 10);
CHECK(effectAnd->arguments[0].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().get<pddl::ast::PredicatePointer>()->arguments[0].get<pddl::ast::ConstantPointer>()->declaration->name == "roller");
CHECK(effectAnd->arguments[1].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().is<pddl::ast::PredicatePointer>());
CHECK(effectAnd->arguments[2].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().is<pddl::ast::PredicatePointer>());
CHECK(effectAnd->arguments[3].get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().is<pddl::ast::PredicatePointer>());
const auto &effectWhen4 = effectAnd->arguments[4].get<pddl::ast::WhenPointer<pddl::ast::Precondition, pddl::ast::ConditionalEffect>>();
// TODO: check name of declaration
CHECK(effectWhen4->argumentLeft.get<pddl::ast::NotPointer<pddl::ast::Precondition>>()->argument.get<pddl::ast::AtomicFormula>().is<pddl::ast::PredicatePointer>());
CHECK(effectWhen4->argumentRight.get<pddl::ast::Literal>().get<pddl::ast::AtomicFormula>().is<pddl::ast::PredicatePointer>());
const auto &effectForAll5 = effectAnd->arguments[5].get<pddl::ast::ForAllPointer<pddl::ast::Effect>>();
REQUIRE(effectForAll5->parameters.size() == 1);
CHECK(effectForAll5->parameters[0]->name == "oldsurface");
CHECK(effectForAll5->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "surface");
const auto &effectForAll5When = effectForAll5->argument.get<pddl::ast::WhenPointer<pddl::ast::Precondition, pddl::ast::ConditionalEffect>>();
// TODO: check name of declaration
CHECK(effectForAll5When->argumentLeft.get<pddl::ast::AtomicFormula>().is<pddl::ast::PredicatePointer>());
CHECK(effectForAll5When->argumentRight.get<pddl::ast::Literal>().get<pddl::ast::NotPointer<pddl::ast::AtomicFormula>>()->argument.is<pddl::ast::PredicatePointer>());
const auto &effectForAll6 = effectAnd->arguments[6].get<pddl::ast::ForAllPointer<pddl::ast::Effect>>();
REQUIRE(effectForAll6->parameters.size() == 1);
CHECK(effectForAll6->parameters[0]->name == "oldpaint");
CHECK(effectForAll6->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "colour");
const auto &effectForAll9 = effectAnd->arguments[9].get<pddl::ast::ForAllPointer<pddl::ast::Effect>>();
REQUIRE(effectForAll9->parameters.size() == 1);
CHECK(effectForAll9->parameters[0]->name == "oldtemp");
CHECK(effectForAll9->parameters[0]->type.value().get<pddl::ast::PrimitiveTypePointer>()->declaration->name == "temperature");
const auto &effectForAll9When = effectForAll9->argument.get<pddl::ast::WhenPointer<pddl::ast::Precondition, pddl::ast::ConditionalEffect>>();
// TODO: check name of declaration
CHECK(effectForAll9When->argumentLeft.get<pddl::ast::AtomicFormula>().is<pddl::ast::PredicatePointer>());
CHECK(effectForAll9When->argumentRight.get<pddl::ast::Literal>().get<pddl::ast::NotPointer<pddl::ast::AtomicFormula>>()->argument.is<pddl::ast::PredicatePointer>());
}
}

View File

@@ -0,0 +1,125 @@
#include <catch.hpp>
#include <experimental/filesystem>
#include <pddl/AST.h>
#include <pddl/Parse.h>
namespace fs = std::experimental::filesystem;
const pddl::Context::WarningCallback ignoreWarnings = [](const auto &, const auto &){};
const auto pddlInstanceBasePath = fs::path("data") / "pddl-instances";
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[PDDL parser] The PDDL parser behaves correctly", "[PDDL parser]")
{
pddl::Tokenizer tokenizer;
pddl::Context context(std::move(tokenizer), ignoreWarnings);
// Check that no infinite loop occurs
SECTION("“either” in typing section")
{
const auto domainFile = fs::path("data") / "test-cases" / "typing-1.pddl";
context.tokenizer.read(domainFile);
const auto description = pddl::parseDescription(context);
const auto &types = description.domain->types;
REQUIRE(types.size() == 5);
CHECK(types[0]->name == "object");
REQUIRE(types[0]->parentTypes.size() == 1);
CHECK(types[0]->parentTypes[0]->declaration == types[0].get());
CHECK(types[1]->name == "a1");
REQUIRE(types[1]->parentTypes.size() == 1);
CHECK(types[1]->parentTypes[0]->declaration == types[0].get());
CHECK(types[2]->name == "a2");
REQUIRE(types[2]->parentTypes.size() == 1);
CHECK(types[2]->parentTypes[0]->declaration == types[0].get());
CHECK(types[3]->name == "a3");
REQUIRE(types[3]->parentTypes.size() == 1);
CHECK(types[3]->parentTypes[0]->declaration == types[0].get());
CHECK(types[4]->name == "bx");
REQUIRE(types[4]->parentTypes.size() == 3);
CHECK(types[4]->parentTypes[0]->declaration == types[1].get());
CHECK(types[4]->parentTypes[1]->declaration == types[2].get());
CHECK(types[4]->parentTypes[2]->declaration == types[3].get());
}
SECTION("missing domains are detected")
{
const auto instanceFile = fs::path("data") / "pddl-instances" / "ipc-2000" / "domains" / "blocks-strips-typed" / "instances" / "instance-1.pddl";
context.tokenizer.read(instanceFile);
CHECK_THROWS(pddl::parseDescription(context));
}
SECTION("mismatched domains are detected")
{
const auto domainFile = fs::path("data") / "pddl-instances" / "ipc-2000" / "domains" / "blocks-strips-typed" / "domain.pddl";
const auto instanceFile = fs::path("data") / "pddl-instances" / "ipc-2000" / "domains" / "freecell-strips-typed" / "instances" / "instance-1.pddl";
context.tokenizer.read(domainFile);
context.tokenizer.read(instanceFile);
CHECK_THROWS(pddl::parseDescription(context));
}
}
TEST_CASE("[PDDL parser] Syntax errors are correctly recognized", "[PDDL parser]")
{
pddl::Tokenizer tokenizer;
pddl::Context context(std::move(tokenizer), ignoreWarnings);
SECTION("valid domain")
{
const auto domainFile = fs::path("data") / "pddl-syntax" / "domain-valid.pddl";
context.tokenizer.read(domainFile);
CHECK_NOTHROW(pddl::parseDescription(context));
}
for (size_t i = 1; i <= 3; i++)
SECTION("syntax errors in expressions (" + std::to_string(i) + ")")
{
const auto domainFile = fs::path("data") / "pddl-syntax" / ("domain-expressions-" + std::to_string(i) + ".pddl");
context.tokenizer.read(domainFile);
CHECK_THROWS(pddl::parseDescription(context));
}
for (size_t i = 1; i <= 3; i++)
SECTION("syntax errors in expression names (" + std::to_string(i) + ")")
{
const auto domainFile = fs::path("data") / "pddl-syntax" / ("domain-expression-name-" + std::to_string(i) + ".pddl");
context.tokenizer.read(domainFile);
CHECK_THROWS(pddl::parseDescription(context));
}
for (size_t i = 1; i <= 8; i++)
SECTION("syntax errors with parentheses (" + std::to_string(i) + ")")
{
const auto domainFile = fs::path("data") / "pddl-syntax" / ("domain-parentheses-" + std::to_string(i) + ".pddl");
context.tokenizer.read(domainFile);
CHECK_THROWS(pddl::parseDescription(context));
}
for (size_t i = 1; i <= 7; i++)
SECTION("syntax errors in section names (" + std::to_string(i) + ")")
{
const auto domainFile = fs::path("data") / "pddl-syntax" / ("domain-section-name-" + std::to_string(i) + ".pddl");
context.tokenizer.read(domainFile);
CHECK_THROWS(pddl::parseDescription(context));
}
for (size_t i = 1; i <= 4; i++)
SECTION("syntax errors in types (" + std::to_string(i) + ")")
{
const auto domainFile = fs::path("data") / "pddl-syntax" / ("domain-types-" + std::to_string(i) + ".pddl");
context.tokenizer.read(domainFile);
CHECK_THROWS(pddl::parseDescription(context));
}
for (size_t i = 1; i <= 3; i++)
SECTION("syntax errors in variables (" + std::to_string(i) + ")")
{
const auto domainFile = fs::path("data") / "pddl-syntax" / ("domain-variables-" + std::to_string(i) + ".pddl");
context.tokenizer.read(domainFile);
CHECK_THROWS(pddl::parseDescription(context));
}
}

View File

@@ -0,0 +1,149 @@
#include <catch.hpp>
#include <experimental/filesystem>
#include <pddl/AST.h>
#include <pddl/Parse.h>
namespace fs = std::experimental::filesystem;
const pddl::Context::WarningCallback ignoreWarnings = [](const auto &, const auto &){};
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[PDDL signature matching] Predicate signatures are matched correctly", "[PDDL signature matching]")
{
std::stringstream input;
pddl::Tokenizer tokenizer;
pddl::Context context(std::move(tokenizer), ignoreWarnings);
const auto domainFile = fs::path("data") / "test-cases" / "skeleton.pddl";
context.tokenizer.read(domainFile);
SECTION("directly matching primitive types")
{
input
<< "(:action test :parameters (?x - a1 ?y - a2 ?z - a3) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("derived primitive types (direct children)")
{
input
<< "(:action test :parameters (?x - b1 ?y - b2 ?z - b3) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("derived primitive types (indirect children)")
{
input
<< "(:action test :parameters (?x - c1 ?y - c2 ?z - c3) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("incompatible primitive types")
{
input
<< "(:action test :parameters (?x - a3 ?y - a2 ?z - a3) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_THROWS(pddl::parseDescription(context));
}
SECTION("unrelated primitive types")
{
input
<< "(:action test :parameters (?x - b1 ?y - b2 ?z - b1) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_THROWS(pddl::parseDescription(context));
}
SECTION("incompatible parent types (1)")
{
input
<< "(:action test :parameters (?x - object ?y - b2 ?z - c3) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_THROWS(pddl::parseDescription(context));
}
SECTION("incompatible parent types (2)")
{
input
<< "(:action test :parameters (?x - a1 ?y - a2 ?z - a3) :precondition (p2 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_THROWS(pddl::parseDescription(context));
}
SECTION("matching types with multiple inheritance (1)")
{
input
<< "(:action test :parameters (?x - b1 ?y - b2 ?z - cx) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("matching types with multiple inheritance (2)")
{
input
<< "(:action test :parameters (?x - bx ?y - b2 ?z - c3) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("“either” type not matching primitive type")
{
input
<< "(:action test :parameters (?x - either (a1 a2) ?y - b2 ?z - c3) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_THROWS(pddl::parseDescription(context));
}
SECTION("1-ary “either” type matching primitive type")
{
input
<< "(:action test :parameters (?x - (either a1) ?y - a2 ?z - a3) :precondition (p1 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("“either” type directly matching another “either” type")
{
input
<< "(:action test :parameters (?x - (either a1 a2) ?y ?z - (either b1 b3)) :precondition (p3 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("“either” type matching another “either” type via inheritance")
{
input
<< "(:action test :parameters (?x - (either b1 a2) ?y ?z - (either c1 b3)) :precondition (p3 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("“either” type incompatible with another “either” type")
{
input
<< "(:action test :parameters (?x - (either b1 a2) ?y ?z - (either c2 b3)) :precondition (p3 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_THROWS(pddl::parseDescription(context));
}
SECTION("“either” type compatible with another “either” type via multiple inheritance")
{
input
<< "(:action test :parameters (?x - (either cx c2) ?y ?z - (either cx c3)) :precondition (p3 ?x ?y ?z)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
SECTION("constants compatible with “either” type via multiple inheritance")
{
input
<< "(:action test :precondition (p3 cbx cb1 cb3)))";
context.tokenizer.read("input", input);
CHECK_NOTHROW(pddl::parseDescription(context));
}
}

2
lib/pddl/tests/main.cpp Normal file
View File

@@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include <catch.hpp>