diff --git a/.gitmodules b/.gitmodules index b4b58b4..995e15b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "lib/catch"] path = lib/catch url = https://github.com/philsquared/Catch +[submodule "lib/variant"] + path = lib/variant + url = https://github.com/mapbox/variant diff --git a/lib/pddlparse/include/pddlparse/AST.h b/lib/pddlparse/include/pddlparse/AST.h index 882d8ca..7c5d388 100644 --- a/lib/pddlparse/include/pddlparse/AST.h +++ b/lib/pddlparse/include/pddlparse/AST.h @@ -26,7 +26,7 @@ namespace ast struct Constant { - explicit Constant(ConstantDeclaration &declaration) + explicit Constant(ConstantDeclaration *declaration) : declaration{declaration} { } @@ -36,7 +36,7 @@ struct Constant Constant(Constant &&other) = default; Constant &operator=(Constant &&other) = default; - ConstantDeclaration &declaration; + ConstantDeclaration *declaration; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -51,8 +51,8 @@ struct ConstantDeclaration ConstantDeclaration(const ConstantDeclaration &other) = delete; ConstantDeclaration &operator=(const ConstantDeclaration &&other) = delete; - ConstantDeclaration(ConstantDeclaration &&other) = default; - ConstantDeclaration &operator=(ConstantDeclaration &&other) = default; + ConstantDeclaration(ConstantDeclaration &&other) = delete; + ConstantDeclaration &operator=(ConstantDeclaration &&other) = delete; std::string name; std::experimental::optional type; @@ -79,7 +79,7 @@ struct Dummy struct PrimitiveType { - explicit PrimitiveType(PrimitiveTypeDeclaration &declaration) + explicit PrimitiveType(PrimitiveTypeDeclaration *declaration) : declaration{declaration} { } @@ -89,7 +89,7 @@ struct PrimitiveType PrimitiveType(PrimitiveType &&other) = default; PrimitiveType &operator=(PrimitiveType &&other) = default; - PrimitiveTypeDeclaration &declaration; + PrimitiveTypeDeclaration *declaration; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -103,11 +103,11 @@ struct PrimitiveTypeDeclaration PrimitiveTypeDeclaration(const PrimitiveTypeDeclaration &other) = delete; PrimitiveTypeDeclaration &operator=(const PrimitiveTypeDeclaration &&other) = delete; - PrimitiveTypeDeclaration(PrimitiveTypeDeclaration &&other) = default; - PrimitiveTypeDeclaration &operator=(PrimitiveTypeDeclaration &&other) = default; + PrimitiveTypeDeclaration(PrimitiveTypeDeclaration &&other) = delete; + PrimitiveTypeDeclaration &operator=(PrimitiveTypeDeclaration &&other) = delete; std::string name; - std::vector parentTypes; + std::vector parentTypes; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -127,7 +127,7 @@ struct Unsupported struct Variable { - explicit Variable(VariableDeclaration &declaration) + explicit Variable(VariableDeclaration *declaration) : declaration{declaration} { } @@ -137,7 +137,7 @@ struct Variable Variable(Variable &&other) = default; Variable &operator=(Variable &&other) = default; - VariableDeclaration &declaration; + VariableDeclaration *declaration; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -152,8 +152,8 @@ struct VariableDeclaration VariableDeclaration(const VariableDeclaration &other) = delete; VariableDeclaration &operator=(const VariableDeclaration &&other) = delete; - VariableDeclaration(VariableDeclaration &&other) = default; - VariableDeclaration &operator=(VariableDeclaration &&other) = default; + VariableDeclaration(VariableDeclaration &&other) = delete; + VariableDeclaration &operator=(VariableDeclaration &&other) = delete; std::string name; std::experimental::optional type; @@ -165,7 +165,7 @@ struct VariableDeclaration struct Predicate { - explicit Predicate(PredicateDeclaration &declaration) + explicit Predicate(PredicateDeclaration *declaration) : declaration{declaration} { } @@ -176,8 +176,7 @@ struct Predicate Predicate &operator=(Predicate &&other) = default; Terms arguments; - - PredicateDeclaration &declaration; + PredicateDeclaration *declaration; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -416,9 +415,9 @@ struct Action std::string name; - ast::VariableDeclarations parameters; - std::experimental::optional precondition; - std::experimental::optional effect; + VariableDeclarations parameters; + std::experimental::optional precondition; + std::experimental::optional effect; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -429,15 +428,15 @@ struct Domain Domain(const Domain &other) = delete; Domain &operator=(const Domain &&other) = delete; - Domain(Domain &&other) = default; - Domain &operator=(Domain &&other) = default; + Domain(Domain &&other) = delete; + Domain &operator=(Domain &&other) = delete; std::string name; Requirements requirements; - ast::PrimitiveTypeDeclarations types; - ast::ConstantDeclarations constants; - ast::PredicateDeclarations predicates; - std::vector actions; + PrimitiveTypeDeclarations types; + ConstantDeclarations constants; + PredicateDeclarations predicates; + Actions actions; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -451,7 +450,7 @@ struct InitialState InitialState(InitialState &&other) = default; InitialState &operator=(InitialState &&other) = default; - ast::Facts facts; + Facts facts; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -460,17 +459,22 @@ 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; + Domain *domain; std::string name; Requirements requirements; - ast::ConstantDeclarations objects; + ConstantDeclarations objects; InitialState initialState; - std::experimental::optional goal; + std::experimental::optional goal; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -512,8 +516,8 @@ struct Description Description(Description &&other) = default; Description &operator=(Description &&other) = default; - Domain domain; - std::experimental::optional problem; + DomainPointer domain; + std::experimental::optional problem; }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/pddlparse/include/pddlparse/ASTForward.h b/lib/pddlparse/include/pddlparse/ASTForward.h index 206f4e3..c14d06e 100644 --- a/lib/pddlparse/include/pddlparse/ASTForward.h +++ b/lib/pddlparse/include/pddlparse/ASTForward.h @@ -26,27 +26,37 @@ namespace ast //////////////////////////////////////////////////////////////////////////////////////////////////// struct Constant; +using ConstantPointer = std::unique_ptr; struct ConstantDeclaration; -using ConstantDeclarations = std::vector; +using ConstantDeclarationPointer = std::unique_ptr; +using ConstantDeclarations = std::vector; struct Dummy; +using DummyPointer = std::unique_ptr; struct PrimitiveType; -using PrimitiveTypes = std::vector; +using PrimitiveTypePointer = std::unique_ptr; +using PrimitiveTypes = std::vector; struct PrimitiveTypeDeclaration; -using PrimitiveTypeDeclarations = std::vector; +using PrimitiveTypeDeclarationPointer = std::unique_ptr; +using PrimitiveTypeDeclarations = std::vector; struct Unsupported; +using UnsupportedPointer = std::unique_ptr; struct Variable; -using Variables = std::vector; +using VariablePointer = std::unique_ptr; +using Variables = std::vector; struct VariableDeclaration; -using VariableDeclarations = std::vector; +using VariableDeclarationPointer = std::unique_ptr; +using VariableDeclarations = std::vector; //////////////////////////////////////////////////////////////////////////////////////////////////// // Compounds //////////////////////////////////////////////////////////////////////////////////////////////////// struct Predicate; -using Predicates = std::vector; +using PredicatePointer = std::unique_ptr; +using Predicates = std::vector; struct PredicateDeclaration; -using PredicateDeclarations = std::vector; +using PredicateDeclarationPointer = std::unique_ptr; +using PredicateDeclarations = std::vector; //////////////////////////////////////////////////////////////////////////////////////////////////// // Expressions @@ -55,29 +65,53 @@ using PredicateDeclarations = std::vector; template struct And; template +using AndPointer = std::unique_ptr>; +template struct At; template +using AtPointer = std::unique_ptr>; +template struct Either; template +using EitherPointer = std::unique_ptr>; +template struct Exists; template +using ExistsPointer = std::unique_ptr>; +template struct ForAll; template +using ForAllPointer = std::unique_ptr>; +template struct Imply; template +using ImplyPointer = std::unique_ptr>; +template struct Not; template +using NotPointer = std::unique_ptr>; +template struct Or; +template +using OrPointer = std::unique_ptr>; template struct When; +template +using WhenPointer = std::unique_ptr>; //////////////////////////////////////////////////////////////////////////////////////////////////// // PDDL Structure //////////////////////////////////////////////////////////////////////////////////////////////////// +struct Action; +using ActionPointer = std::unique_ptr; +using Actions = std::vector; struct Description; +using DescriptionPointer = std::unique_ptr; struct Domain; +using DomainPointer = std::unique_ptr; struct Problem; +using ProblemPointer = std::unique_ptr; enum class Requirement; using Requirements = std::vector; @@ -88,8 +122,8 @@ using Requirements = std::vector; namespace detail { using TermT = Variant< - Constant, - Variable>; + ConstantPointer, + VariablePointer>; } class Term : public detail::TermT @@ -104,8 +138,8 @@ using Terms = std::vector; namespace detail { using AtomicFormulaT = Variant< - Predicate, - Unsupported>; + PredicatePointer, + UnsupportedPointer>; } class AtomicFormula : public detail::AtomicFormulaT @@ -121,13 +155,13 @@ namespace detail { using PreconditionT = Variant< AtomicFormula, - And, - Exists, - ForAll, - Imply, - Not, - Or, - Unsupported>; + AndPointer, + ExistsPointer, + ForAllPointer, + ImplyPointer, + NotPointer, + OrPointer, + UnsupportedPointer>; } class Precondition : public detail::PreconditionT @@ -145,11 +179,11 @@ namespace detail { using EffectT = Variant< AtomicFormula, - And, - ForAll, - Not, - When, - Unsupported>; + AndPointer, + ForAllPointer, + NotPointer, + WhenPointer, + UnsupportedPointer>; } class Effect : public detail::EffectT @@ -162,8 +196,8 @@ class Effect : public detail::EffectT namespace detail { using TypeT = Variant< - Either, - PrimitiveType>; + EitherPointer, + PrimitiveTypePointer>; } class Type : public detail::TypeT @@ -177,7 +211,7 @@ namespace detail { using LiteralT = Variant< AtomicFormula, - Not>; + NotPointer>; } class Literal : public detail::LiteralT @@ -193,7 +227,7 @@ namespace detail { using FactT = Variant< AtomicFormula, - At>; + AtPointer>; } class Fact : public detail::FactT diff --git a/lib/pddlparse/include/pddlparse/Context.h b/lib/pddlparse/include/pddlparse/Context.h new file mode 100644 index 0000000..6859944 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/Context.h @@ -0,0 +1,49 @@ +#ifndef __PDDL_PARSE__CONTEXT_H +#define __PDDL_PARSE__CONTEXT_H + +#include + +#include + +namespace pddl +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Context +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Context +{ + constexpr static const char *auxiliaryPrefix() + { + return "__plasp_"; + } + + // TODO: replace std::string with char * + using WarningCallback = std::function; + + Context() = default; + ~Context() = default; + + explicit Context(Tokenizer &&tokenizer, WarningCallback warningCallback) + : tokenizer{std::move(tokenizer)}, + warningCallback{warningCallback} + { + } + + Context(const Context &other) = delete; + Context &operator=(const Context &other) = delete; + Context(Context &&other) = default; + Context &operator=(Context &&other) = default; + + Tokenizer tokenizer; + WarningCallback warningCallback; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/Parse.h b/lib/pddlparse/include/pddlparse/Parse.h new file mode 100644 index 0000000..053b332 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/Parse.h @@ -0,0 +1,24 @@ +#ifndef __PDDL_PARSE__PARSE_H +#define __PDDL_PARSE__PARSE_H + +#include + +#include +#include + +namespace pddl +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Parse +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::Description parseDescription(Context &context); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/Variant.h b/lib/pddlparse/include/pddlparse/Variant.h index 879e9c3..f790d34 100644 --- a/lib/pddlparse/include/pddlparse/Variant.h +++ b/lib/pddlparse/include/pddlparse/Variant.h @@ -1,233 +1,20 @@ #ifndef __PDDL_PARSE__VARIANT_H #define __PDDL_PARSE__VARIANT_H -#include -#include -#include -#include +#include namespace pddl { -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Variant (from clingo, written by Roland Kaminski) -// //////////////////////////////////////////////////////////////////////////////////////////////////// -namespace detail { - -template -struct TypeInList : std::false_type { }; - -template -struct TypeInList : std::true_type { }; - -template -struct TypeInList : TypeInList { }; - -template -struct VariantHolder; - -template -struct VariantHolder { - bool check_type() const { return type_ == 0; } - void emplace() { } - void emplace2() { } - void copy(VariantHolder const &) { } - void destroy() { - type_ = 0; - data_ = nullptr; - } - void print(std::ostream &) const { } - void swap(VariantHolder &other) { - std::swap(type_, other.type_); - std::swap(data_, other.data_); - } - unsigned type_ = 0; - void *data_ = nullptr; -}; - -template -struct VariantHolder : VariantHolder{ - using Helper = VariantHolder; - using Helper::check_type; - using Helper::emplace; - using Helper::emplace2; - using Helper::data_; - using Helper::type_; - bool check_type(T *) const { return type_ == n; } - template - void emplace(T *, Args&& ...x) { - data_ = new T{std::forward(x)...}; - type_ = n; - } - // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467 - template - void emplace2(T *, Args&& ...x) { - data_ = new T(std::forward(x)...); - type_ = n; - } - void copy(VariantHolder const &src) { - if (src.type_ == n) { - data_ = new T(*static_cast(src.data_)); - type_ = src.type_; - } - Helper::copy(src); - } - // NOTE: workaround for visual studio (C++14 can also simply use auto) -# define CLINGO_VARIANT_RETURN(Type) decltype(std::declval().visit(std::declval(), std::declval()...)) - template - using Ret_ = CLINGO_VARIANT_RETURN(T); - template - using ConstRet_ = CLINGO_VARIANT_RETURN(T const); - // non-const - template - auto accept_(V &&visitor, Args &&... args) -> CLINGO_VARIANT_RETURN(T) { - static_assert(std::is_same, typename Helper::template Ret_>::value, ""); - return n == type_ - ? visitor.visit(*static_cast(data_), std::forward(args)...) - : Helper::template accept(std::forward(visitor), std::forward(args)...); - } - template - auto accept_(V &&visitor, Args &&... args) -> CLINGO_VARIANT_RETURN(T) { - assert(n == type_); - return visitor.visit(*static_cast(data_), std::forward(args)...); - } - template - auto accept(V &&visitor, Args &&... args) -> CLINGO_VARIANT_RETURN(T) { - return accept_(std::forward(visitor), std::forward(args)...); - } - // const - template - auto accept_(V &&visitor, Args &&... args) const -> CLINGO_VARIANT_RETURN(T const) { - static_assert(std::is_same, typename Helper::template ConstRet_>::value, ""); - return n == type_ - ? visitor.visit(*static_cast(data_), std::forward(args)...) - : Helper::template accept(std::forward(visitor), std::forward(args)...); - } - template - auto accept_(V &&visitor, Args &&... args) const -> CLINGO_VARIANT_RETURN(T const) { - assert(n == type_); - return visitor.visit(*static_cast(data_), std::forward(args)...); - } - template - auto accept(V &&visitor, Args &&... args) const -> CLINGO_VARIANT_RETURN(T const) { - return accept_(std::forward(visitor), std::forward(args)...); - } -# undef CLINGO_VARIANT_RETURN - void destroy() { - if (n == type_) { delete static_cast(data_); } - Helper::destroy(); - } - void print(std::ostream &out) const { - if (n == type_) { out << *static_cast(data_); } - Helper::print(out); - } -}; - -} - -template -class Variant { - using Holder = detail::VariantHolder<1, T...>; -public: - Variant(Variant const &other) : Variant(other.data_) { } - Variant(Variant &&other) noexcept { data_.swap(other.data_); } - template - Variant(U &&u, typename std::enable_if::value>::type * = nullptr) { emplace2(std::forward(u)); } - template - Variant(U &u, typename std::enable_if::value>::type * = nullptr) { emplace2(u); } - template - Variant(U const &u, typename std::enable_if::value>::type * = nullptr) { emplace2(u); } - template - static Variant make(Args&& ...args) { - Variant x; - x.data_.emplace(static_cast(nullptr), std::forward(args)...); - return std::move(x); - } - ~Variant() { data_.destroy(); } - Variant &operator=(Variant const &other) { return *this = other.data_; } - Variant &operator=(Variant &&other) noexcept { return *this = std::move(other.data_); } - template - typename std::enable_if::value, Variant>::type &operator=(U &&u) { - emplace2(std::forward(u)); - return *this; - } - template - typename std::enable_if::value, Variant>::type &operator=(U &u) { - emplace2(u); - return *this; - } - template - typename std::enable_if::value, Variant>::type &operator=(U const &u) { - emplace2(u); - return *this; - } - template - U &get() { - if (!data_.check_type(static_cast(nullptr))) { throw std::bad_cast(); } - return *static_cast(data_.data_); - } - template - U const &get() const { - if (!data_.check_type(static_cast(nullptr))) { throw std::bad_cast(); } - return *static_cast(data_.data_); - } - template - void emplace(Args&& ...args) { - Variant x; - x.data_.emplace(static_cast(nullptr), std::forward(args)...); - data_.swap(x.data_); - } - template - bool is() const { return data_.check_type(static_cast(nullptr)); } - void swap(Variant &other) { data_.swap(other.data_); } - template - typename Holder::template Ret_ accept(V &&visitor, Args &&... args) { - return data_.accept(std::forward(visitor), std::forward(args)...); - } - template - typename Holder::template ConstRet_ accept(V &&visitor, Args &&... args) const { - return data_.accept(std::forward(visitor), std::forward(args)...); - } - friend std::ostream &operator<<(std::ostream &out, Variant const &x) { - x.data_.print(out); - return out; - } - -private: - Variant() { } - Variant(Holder const &data) { - data_.copy(data); - } - Variant &operator=(Holder const &data) { - Variant x(data); - data_.swap(x.data_); - return *this; - } - Variant &operator=(Holder &&data) noexcept { - Holder x; - x.swap(data); - // Destroy the old data_ only after securing the new data - // Otherwise, data would be destroyed together with data_ if it was a descendant of data_ - data_.destroy(); - x.swap(data_); - return *this; - } - template - void emplace2(Args&& ...args) { - Variant x; - x.data_.emplace2(static_cast(nullptr), std::forward(args)...); - data_.swap(x.data_); - } - -private: - Holder data_; -}; +template +using Variant = mapbox::util::variant; //////////////////////////////////////////////////////////////////////////////////////////////////// } +//////////////////////////////////////////////////////////////////////////////////////////////////// + #endif diff --git a/lib/pddlparse/include/pddlparse/detail/ASTContext.h b/lib/pddlparse/include/pddlparse/detail/ASTContext.h new file mode 100644 index 0000000..7e12161 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/ASTContext.h @@ -0,0 +1,48 @@ +#ifndef __PDDL_PARSE__DETAIL__AST_CONTEXT_H +#define __PDDL_PARSE__DETAIL__AST_CONTEXT_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// ASTContext +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct ASTContext +{ + ASTContext(ast::Description &description) + : domain{description.domain.get()}, + problem{description.problem.value() ? std::experimental::optional(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 problem; + + VariableStack variables; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/ASTCopy.h b/lib/pddlparse/include/pddlparse/detail/ASTCopy.h new file mode 100644 index 0000000..ced121d --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/ASTCopy.h @@ -0,0 +1,161 @@ +#ifndef __PDDL_PARSE__DETAIL__AST_COPY_H +#define __PDDL_PARSE__DETAIL__AST_COPY_H + +#include + +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 +inline Binary deepCopy(Binary &other); +template +inline NAry deepCopy(NAry &other); +template +inline Quantified deepCopy(Quantified &other); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Expressions +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline At deepCopy(At &other); +template +inline Not deepCopy(Not &other); + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Variants +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ast::Term deepCopy(ast::Term &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 +Binary deepCopy(Binary &other) +{ + auto argumentLeft = deepCopy(other.argumentLeft); + auto argumentRight = deepCopy(other.argumentRight); + + return Binary(std::move(argumentLeft), std::move(argumentRight)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +NAry deepCopy(NAry &other) +{ + typename NAry::Arguments arguments; + arguments.reserve(other.arguments.size()); + + for (auto &argument : other.arguments) + arguments.emplace_back(deepCopy(argument)); + + return NAry(std::move(arguments)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +Quantified deepCopy(Quantified &other) +{ + auto argument = deepCopy(other.argument); + + return Quantified(std::move(argument)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Expressions +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +At deepCopy(At &other) +{ + auto argument = deepCopy(other.argument); + + return At(other.timePoint, std::move(argument)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +Not deepCopy(Not &other) +{ + auto argument = deepCopy(other.argument); + + return Not(std::move(argument)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Variants +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct DeepCopyVisitor +{ + template + Argument visit(Argument &other) + { + return deepCopy(other); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Unique Pointers +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +std::unique_ptr deepCopy(std::unique_ptr &other) +{ + return std::make_unique(deepCopy(*other)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/Requirements.h b/lib/pddlparse/include/pddlparse/detail/Requirements.h new file mode 100644 index 0000000..e9e7dc9 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/Requirements.h @@ -0,0 +1,33 @@ +#ifndef __PDDL_PARSE__DETAIL__REQUIREMENTS_H +#define __PDDL_PARSE__DETAIL__REQUIREMENTS_H + +#include + +#include +#include + +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 diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/AST.h b/lib/pddlparse/include/pddlparse/detail/parsing/AST.h new file mode 100644 index 0000000..e6e12a6 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/AST.h @@ -0,0 +1,127 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__AST_H +#define __PDDL_PARSE__DETAIL__PARSING__AST_H + +#include +#include +#include + +namespace pddl +{ +namespace detail +{ +/* +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// ParseAST +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Primitives +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template<> +struct Parser +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template<> +struct Parser +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template<> +struct Parser +{ + std::experimental::optional parse(Context &context, ASTContext &astContext) + { + auto &tokenizer = context.tokenizer; + auto &types = astContext.description.domain.types; + + tokenizer.skipWhiteSpace(); + + auto typeName = tokenizer.getIdentifier(); + + if (typeName.empty()) + throw tokenize::TokenizerException(tokenizer.location(), "no type supplied"); + + auto matchingType = std::find_if(types.begin(), types.end(), + [&](auto &primitiveTypeDeclaration) + { + return primitiveTypeDeclaration->name == typeName; + }); + + if (matchingType == types.end()) + { + // Only “object” is allowed as an implicit type + if (typeName == "object" || typeName == "objects") + { + context.warningCallback(tokenizer.location(), "primitive type “" + typeName + "” should be declared"); + types.emplace_back(std::make_unique(std::move(typeName))); + + return ast::PrimitiveType(types.back()); + } + else + throw tokenize::TokenizerException(tokenizer.location(), "type “" + typeName + "” used but never declared"); + } + + auto &type = *matchingType; + + return ast::PrimitiveType(type); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template<> +struct Parser +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template<> +struct Parser +{ + std::experimental::optional parse(Context &context, ASTContext &) + { + auto &tokenizer = context.tokenizer; + + ast::Unsupported unsupported; + + tokenizer.expect("("); + + unsupported.type = tokenizer.getIdentifier(); + + context.warningCallback(tokenizer.location(), "expression type “" + unsupported.type + "” currently unsupported in this context"); + + skipSection(tokenizer); + + return unsupported; + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Expressions +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct Parser> +{ + template + std::experimental::optional> parse(Context &context, ASTContext &astContext, ArgumentParser parseArgument) + { + return Parser, Argument>>::parse(context, astContext, parseArgument); + } +}; +*/ +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Action.h b/lib/pddlparse/include/pddlparse/detail/parsing/Action.h new file mode 100644 index 0000000..dff8ad5 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Action.h @@ -0,0 +1,25 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__ACTION_H +#define __PDDL_PARSE__DETAIL__PARSING__ACTION_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Action +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parseAndAddAction(Context &context, ast::Domain &domain); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Constant.h b/lib/pddlparse/include/pddlparse/detail/parsing/Constant.h new file mode 100644 index 0000000..b62b25a --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Constant.h @@ -0,0 +1,26 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__CONSTANT_H +#define __PDDL_PARSE__DETAIL__PARSING__CONSTANT_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Constant +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::ConstantPointer parseConstant(Context &context, ast::Domain &domain); +ast::ConstantPointer parseConstant(Context &context, ast::Problem &problem); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/ConstantDeclaration.h b/lib/pddlparse/include/pddlparse/detail/parsing/ConstantDeclaration.h new file mode 100644 index 0000000..a39dbca --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/ConstantDeclaration.h @@ -0,0 +1,26 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__CONSTANT_DECLARATION_H +#define __PDDL_PARSE__DETAIL__PARSING__CONSTANT_DECLARATION_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// ConstantDeclaration +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parseAndAddConstantDeclarations(Context &context, ast::Domain &domain); +void parseAndAddConstantDeclarations(Context &context, ast::Problem &problem); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Description.h b/lib/pddlparse/include/pddlparse/detail/parsing/Description.h new file mode 100644 index 0000000..9ca20aa --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Description.h @@ -0,0 +1,39 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__DESCRIPTION_H +#define __PDDL_PARSE__DETAIL__PARSING__DESCRIPTION_H + +#include + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Description +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class DescriptionParser +{ + public: + DescriptionParser(Context &context); + ast::Description parse(); + + private: + void findSections(); + + Context &m_context; + tokenize::Stream::Position m_domainPosition; + tokenize::Stream::Position m_problemPosition; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Domain.h b/lib/pddlparse/include/pddlparse/detail/parsing/Domain.h new file mode 100644 index 0000000..e86e62b --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Domain.h @@ -0,0 +1,50 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__DOMAIN_H +#define __PDDL_PARSE__DETAIL__PARSING__DOMAIN_H + +#include + +#include +#include + +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::Stream::Position m_requirementsPosition; + tokenize::Stream::Position m_typesPosition; + tokenize::Stream::Position m_constantsPosition; + tokenize::Stream::Position m_predicatesPosition; + std::vector m_actionPositions; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/InitialState.h b/lib/pddlparse/include/pddlparse/detail/parsing/InitialState.h new file mode 100644 index 0000000..10afbe2 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/InitialState.h @@ -0,0 +1,25 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__INITIAL_STATE_H +#define __PDDL_PARSE__DETAIL__PARSING__INITIAL_STATE_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// InitialState +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::InitialState parseInitialState(Context &context, ASTContext &expressionContext); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Parser.h b/lib/pddlparse/include/pddlparse/detail/parsing/Parser.h new file mode 100644 index 0000000..81832a9 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Parser.h @@ -0,0 +1,43 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSER_H +#define __PDDL_PARSE__DETAIL__PARSER_H + +#include + +#include +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Parser +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct Parser +{ +}; + +template +std::experimental::optional parse(Context &context, ASTContext &astContext, ArgumentParser... argumentParsers) +{ + return detail::Parser().parse(context, astContext, argumentParsers...); +} + +template +std::experimental::optional parse(Context &context, ASTContext &astContext) +{ + return detail::Parser().parse(context, astContext); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/PredicateDeclaration.h b/lib/pddlparse/include/pddlparse/detail/parsing/PredicateDeclaration.h new file mode 100644 index 0000000..e891433 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/PredicateDeclaration.h @@ -0,0 +1,25 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__PREDICATE_DECLARATION_H +#define __PDDL_PARSE__DETAIL__PARSING__PREDICATE_DECLARATION_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// PredicateDeclaration +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parseAndAddPredicateDeclarations(Context &context, ast::Domain &domain); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/PrimitiveType.h b/lib/pddlparse/include/pddlparse/detail/parsing/PrimitiveType.h new file mode 100644 index 0000000..6ad1406 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/PrimitiveType.h @@ -0,0 +1,25 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__PRIMITIVE_TYPE_H +#define __PDDL_PARSE__DETAIL__PARSING__PRIMITIVE_TYPE_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// PrimitiveType +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::PrimitiveTypePointer parsePrimitiveType(Context &context, ast::Domain &domain); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/PrimitiveTypeDeclaration.h b/lib/pddlparse/include/pddlparse/detail/parsing/PrimitiveTypeDeclaration.h new file mode 100644 index 0000000..85384c3 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/PrimitiveTypeDeclaration.h @@ -0,0 +1,25 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__PRIMITIVE_TYPE_DECLARATION_H +#define __PDDL_PARSE__DETAIL__PARSING__PRIMITIVE_TYPE_DECLARATION_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// PrimitiveTypeDeclaration +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parseAndAddPrimitiveTypeDeclarations(Context &context, ast::Domain &domain); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Problem.h b/lib/pddlparse/include/pddlparse/detail/parsing/Problem.h new file mode 100644 index 0000000..110c241 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Problem.h @@ -0,0 +1,51 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__PROBLEM_H +#define __PDDL_PARSE__DETAIL__PARSING__PROBLEM_H + +#include + +#include +#include + +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::Stream::Position m_domainPosition; + tokenize::Stream::Position m_requirementsPosition; + tokenize::Stream::Position m_objectsPosition; + tokenize::Stream::Position m_initialStatePosition; + tokenize::Stream::Position m_goalPosition; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Requirement.h b/lib/pddlparse/include/pddlparse/detail/parsing/Requirement.h new file mode 100644 index 0000000..40bb71f --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Requirement.h @@ -0,0 +1,26 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__REQUIREMENT_H +#define __PDDL_PARSE__DETAIL__PARSING__REQUIREMENT_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Requirement +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::Requirement parseRequirement(Context &context); +const char *toString(const ast::Requirement &requirement); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Variable.h b/lib/pddlparse/include/pddlparse/detail/parsing/Variable.h new file mode 100644 index 0000000..5348813 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Variable.h @@ -0,0 +1,25 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__VARIABLE_H +#define __PDDL_PARSE__DETAIL__PARSING__VARIABLE_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Variable +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::Variable parseVariable(Context &context, ast::Domain &domain); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/VariableDeclaration.h b/lib/pddlparse/include/pddlparse/detail/parsing/VariableDeclaration.h new file mode 100644 index 0000000..4952613 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/parsing/VariableDeclaration.h @@ -0,0 +1,25 @@ +#ifndef __PDDL_PARSE__DETAIL__PARSING__VARIABLE_DECLARATION_H +#define __PDDL_PARSE__DETAIL__PARSING__VARIABLE_DECLARATION_H + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// VariableDeclaration +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::VariableDeclarations parseVariableDeclarations(Context &context, ast::Domain &domain); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/src/CMakeLists.txt b/lib/pddlparse/src/CMakeLists.txt index 372b4b4..5596a5e 100644 --- a/lib/pddlparse/src/CMakeLists.txt +++ b/lib/pddlparse/src/CMakeLists.txt @@ -12,6 +12,7 @@ file(GLOB detail_parsing_headers "../include/pddlparse/detail/parsing/*.h") set(includes ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/../../lib/tokenize/include + ${PROJECT_SOURCE_DIR}/../../lib/variant/include ) set(sources diff --git a/lib/pddlparse/src/pddlparse/Parse.cpp b/lib/pddlparse/src/pddlparse/Parse.cpp new file mode 100644 index 0000000..e4edaf8 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/Parse.cpp @@ -0,0 +1,22 @@ +#include + +#include +#include + +namespace pddl +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Parse +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::Description parseDescription(Context &context) +{ + return detail::DescriptionParser(context).parse(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} diff --git a/lib/pddlparse/src/pddlparse/detail/Requirements.cpp b/lib/pddlparse/src/pddlparse/detail/Requirements.cpp new file mode 100644 index 0000000..4b9980c --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/Requirements.cpp @@ -0,0 +1,92 @@ +#include + +#include + +#include + +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; + + context.warningCallback(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; + + context.warningCallback(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); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Action.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Action.cpp new file mode 100644 index 0000000..c060bdf --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Action.cpp @@ -0,0 +1,68 @@ +#include + +#include +// TODO: remove +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Action +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parseAndAddAction(Context &context, ast::Domain &domain) +{ + auto &tokenizer = context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect(":"); + tokenizer.expect("action"); + + auto action = std::make_unique(); + action->name = tokenizer.getIdentifier(); + + tokenizer.expect(":parameters"); + tokenizer.expect("("); + + // Read parameters + action->parameters = parseVariableDeclarations(context, domain); + + tokenizer.expect(")"); + + // TODO: reimplement + skipSection(tokenizer); + + /* + // Parse preconditions and effects + while (!tokenizer.testAndReturn(')')) + { + tokenizer.expect(":"); + + if (tokenizer.testIdentifierAndSkip("precondition")) + // TODO: reimplement + //action->precondition = parsePreconditionExpression(context, expressionContext); + skipSection(tokenizer); + else if (tokenizer.testIdentifierAndSkip("effect")) + // TODO: reimplement + //action->effect = parseEffectExpression(context, expressionContext); + skipSection(tokenizer); + + tokenizer.skipWhiteSpace(); + }*/ + + // Store new action + domain.actions.emplace_back(std::move(action)); + + //tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Constant.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Constant.cpp new file mode 100644 index 0000000..d518438 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Constant.cpp @@ -0,0 +1,69 @@ +#include + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Constant +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +std::experimental::optional 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(matchingConstant->get()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::ConstantPointer parseConstant(Context &context, ast::Domain &domain) +{ + auto &tokenizer = context.tokenizer; + const auto constantName = tokenizer.getIdentifier(); + + auto constant = findConstant(constantName, domain.constants); + + if (constant) + return std::move(constant.value()); + + throw ParserException(tokenizer.location(), "constant “" + constantName + "” used but never declared"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::ConstantPointer parseConstant(Context &context, ast::Problem &problem) +{ + auto &tokenizer = context.tokenizer; + const auto constantName = tokenizer.getIdentifier(); + + auto constant = findConstant(constantName, problem.domain->constants); + + if (constant) + return std::move(constant.value()); + + auto object = findConstant(constantName, problem.objects); + + if (object) + return std::move(object.value()); + + throw ParserException(tokenizer.location(), "constant “" + constantName + "” used but never declared"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/ConstantDeclaration.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/ConstantDeclaration.cpp new file mode 100644 index 0000000..a1c3196 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/ConstantDeclaration.cpp @@ -0,0 +1,78 @@ +#include + +#include +#include +#include +#include + +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(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 = 0; + + while (tokenizer.currentCharacter() != ')') + { + parseAndAddUntypedConstantDeclaration(context, constantDeclarations); + + tokenizer.skipWhiteSpace(); + + if (!tokenizer.testAndSkip('-')) + 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() + 1; + + tokenizer.skipWhiteSpace(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +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); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Description.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Description.cpp new file mode 100644 index 0000000..b7ded73 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Description.cpp @@ -0,0 +1,107 @@ +#include + +#include +#include +#include +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Description +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +DescriptionParser::DescriptionParser(Context &context) +: m_context{context}, + m_domainPosition{-1}, + m_problemPosition{-1} +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::Description DescriptionParser::parse() +{ + auto &tokenizer = m_context.tokenizer; + tokenizer.removeComments(";", "\n", false); + + findSections(); + + if (m_domainPosition == -1) + 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 == -1) + 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, 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("("); + tokenizer.expect("define"); + tokenizer.expect("("); + + if (tokenizer.testAndSkip("domain")) + { + if (m_domainPosition != -1) + throw ParserException(tokenizer.location(), "PDDL description may not contain two domains"); + + m_domainPosition = position; + skipSection(tokenizer); + skipSection(tokenizer); + } + else if (m_context.tokenizer.testAndSkip("problem")) + { + if (m_problemPosition != -1) + throw ParserException("PDDL description may not contain two problems currently"); + + m_problemPosition = position; + skipSection(tokenizer); + skipSection(tokenizer); + } + else + { + const auto sectionIdentifier = tokenizer.get(); + throw ParserException(tokenizer.location(), "unknown PDDL section “" + sectionIdentifier + "”"); + } + + tokenizer.skipWhiteSpace(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Domain.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Domain.cpp new file mode 100644 index 0000000..5351c21 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Domain.cpp @@ -0,0 +1,300 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Domain +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +DomainParser::DomainParser(Context &context) +: m_context{context}, + m_requirementsPosition{-1}, + m_typesPosition{-1}, + m_constantsPosition{-1}, + m_predicatesPosition{-1} +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::DomainPointer DomainParser::parse() +{ + auto domain = std::make_unique(); + + findSections(*domain); + + auto &tokenizer = m_context.tokenizer; + + if (m_requirementsPosition != -1) + { + tokenizer.seek(m_requirementsPosition); + parseRequirementSection(*domain); + } + + if (m_typesPosition != -1) + { + tokenizer.seek(m_typesPosition); + parseTypeSection(*domain); + } + + if (m_constantsPosition != -1) + { + tokenizer.seek(m_constantsPosition); + parseConstantSection(*domain); + } + + if (m_predicatesPosition != -1) + { + tokenizer.seek(m_predicatesPosition); + parsePredicateSection(*domain); + } + + for (size_t i = 0; i < m_actionPositions.size(); i++) + if (m_actionPositions[i] != -1) + { + tokenizer.seek(m_actionPositions[i]); + parseActionSection(*domain); + } + + computeDerivedRequirements(*domain); + + return domain; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void DomainParser::findSections(ast::Domain &domain) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect("define"); + tokenizer.expect("("); + tokenizer.expect("domain"); + + domain.name = tokenizer.getIdentifier(); + + tokenizer.expect(")"); + + const auto setSectionPosition = + [&](const std::string §ionName, auto §ionPosition, const auto value, bool unique = false) + { + if (unique && sectionPosition != -1) + { + tokenizer.seek(value); + throw tokenize::TokenizerException(tokenizer.location(), "only one “:" + sectionName + "” section allowed"); + } + + sectionPosition = value; + }; + + tokenizer.skipWhiteSpace(); + + // Find sections + while (tokenizer.currentCharacter() != ')') + { + const auto position = tokenizer.position(); + + tokenizer.expect("("); + tokenizer.expect(":"); + + const auto sectionIdentifierPosition = tokenizer.position(); + + // 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(-1); + setSectionPosition("action", m_actionPositions.back(), position); + } + else if (tokenizer.testIdentifierAndSkip("functions") + || tokenizer.testIdentifierAndSkip("constraints") + || tokenizer.testIdentifierAndSkip("durative-action") + || tokenizer.testIdentifierAndSkip("derived")) + { + tokenizer.seek(sectionIdentifierPosition); + + const auto sectionIdentifier = tokenizer.getIdentifier(); + + m_context.warningCallback(tokenizer.location(), "section type “" + sectionIdentifier + "” currently unsupported"); + + tokenizer.seek(sectionIdentifierPosition); + } + else + { + const auto sectionIdentifier = tokenizer.getIdentifier(); + + tokenizer.seek(position); + throw tokenize::TokenizerException(tokenizer.location(), "unknown domain section “" + sectionIdentifier + "”"); + } + + // Skip section for now and parse it later + skipSection(tokenizer); + + tokenizer.skipWhiteSpace(); + } + + tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void DomainParser::parseRequirementSection(ast::Domain &domain) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect(":"); + tokenizer.expect("requirements"); + + while (tokenizer.currentCharacter() != ')') + { + tokenizer.expect(":"); + + domain.requirements.emplace_back(parseRequirement(m_context)); + + 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(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +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("("); + tokenizer.expect(":"); + tokenizer.expect("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(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void DomainParser::parseConstantSection(ast::Domain &domain) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect(":"); + tokenizer.expect("constants"); + + // Store constants + parseAndAddConstantDeclarations(m_context, domain); + + tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void DomainParser::parsePredicateSection(ast::Domain &domain) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect(":"); + tokenizer.expect("predicates"); + + tokenizer.skipWhiteSpace(); + + // Store predicates + parseAndAddPredicateDeclarations(m_context, domain); + + tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void DomainParser::parseActionSection(ast::Domain &domain) +{ + parseAndAddAction(m_context, domain); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/InitialState.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/InitialState.cpp new file mode 100644 index 0000000..868756e --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/InitialState.cpp @@ -0,0 +1,79 @@ +#include + +#include +// TODO: remove +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// InitialState +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::InitialState parseInitialState(Context &context, ASTContext &) +{ + auto &tokenizer = context.tokenizer; + + ast::InitialState initialState; + + // TODO: reimplement + /*const auto parseInitialStateElement = + [&]() -> ExpressionPointer + { + ExpressionPointer expression; + + // TODO: do not allow negative initial state literals + if ((expression = parseLiteral(context, expressionContext)) + || (expression = expressions::At::parse(context, expressionContext, parseLiteral))) + { + return expression; + } + + const auto position = tokenizer.position(); + + tokenizer.expect("("); + + const auto expressionIdentifierPosition = tokenizer.position(); + + if (tokenizer.testIdentifierAndSkip("=")) + { + tokenizer.seek(expressionIdentifierPosition); + const auto expressionIdentifier = tokenizer.getIdentifier(); + + tokenizer.seek(position); + return expressions::Unsupported::parse(context); + } + + tokenizer.seek(expressionIdentifierPosition); + const auto expressionIdentifier = tokenizer.getIdentifier(); + + tokenizer.seek(position); + throw tokenize::TokenizerException(tokenizer.location(), "expression type “" + expressionIdentifier + "” unknown or not allowed in this context"); + }; + + tokenizer.skipWhiteSpace(); + + while (tokenizer.currentCharacter() != ')') + { + ast::Expression expression; + + if ((expression = parseInitialStateElement())) + initialState->m_facts.emplace_back(std::move(expression)); + + tokenizer.skipWhiteSpace(); + }*/ + + skipSection(tokenizer); + + return initialState; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/PredicateDeclaration.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/PredicateDeclaration.cpp new file mode 100644 index 0000000..b5291b2 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/PredicateDeclaration.cpp @@ -0,0 +1,53 @@ +#include + +#include +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// PredicateDeclaration +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parseAndAddPredicateDeclaration(Context &context, ast::Domain &domain) +{ + auto &tokenizer = context.tokenizer; + tokenizer.expect("("); + + auto name = tokenizer.getIdentifier(); + + tokenizer.skipWhiteSpace(); + + // Parse parameters + auto parameters = parseVariableDeclarations(context, domain); + + tokenizer.expect(")"); + + domain.predicates.emplace_back(std::make_unique(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(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/PrimitiveType.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/PrimitiveType.cpp new file mode 100644 index 0000000..1ffd915 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/PrimitiveType.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// PrimitiveType +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::PrimitiveTypePointer parsePrimitiveType(Context &context, ast::Domain &domain) +{ + auto &tokenizer = context.tokenizer; + auto &types = domain.types; + + tokenizer.skipWhiteSpace(); + + auto typeName = tokenizer.getIdentifier(); + + if (typeName.empty()) + throw tokenize::TokenizerException(tokenizer.location(), "no type supplied"); + + auto matchingType = std::find_if(types.begin(), types.end(), + [&](auto &primitiveTypeDeclaration) + { + return primitiveTypeDeclaration->name == typeName; + }); + + if (matchingType == types.end()) + { + // Only “object” is allowed as an implicit type + if (typeName == "object" || typeName == "objects") + { + context.warningCallback(tokenizer.location(), "primitive type “" + typeName + "” should be declared"); + types.emplace_back(std::make_unique(std::move(typeName))); + + return std::make_unique(types.back().get()); + } + else + throw tokenize::TokenizerException(tokenizer.location(), "type “" + typeName + "” used but never declared"); + } + + return std::make_unique(matchingType->get()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/PrimitiveTypeDeclaration.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/PrimitiveTypeDeclaration.cpp new file mode 100644 index 0000000..ae22764 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/PrimitiveTypeDeclaration.cpp @@ -0,0 +1,77 @@ +#include + +#include +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// PrimitiveTypeDeclaration +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::PrimitiveTypeDeclarationPointer &parseAndAddUntypedPrimitiveTypeDeclaration(Context &context, ast::Domain &domain) +{ + auto &tokenizer = context.tokenizer; + auto typeName = tokenizer.getIdentifier(); + + auto &types = domain.types; + + const auto matchingPrimitiveType = std::find_if(types.begin(), types.end(), + [&](const auto &primitiveType) + { + return primitiveType->name == typeName; + }); + + // Return existing primitive type + if (matchingPrimitiveType != types.cend()) + return *matchingPrimitiveType; + + types.emplace_back(std::make_unique(std::move(typeName))); + + return types.back(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parseAndAddPrimitiveTypeDeclarations(Context &context, ast::Domain &domain) +{ + auto &tokenizer = context.tokenizer; + tokenizer.skipWhiteSpace(); + + // Index on the first element of the current inheritance list + size_t inheritanceIndex = 0; + + while (tokenizer.currentCharacter() != ')') + { + parseAndAddUntypedPrimitiveTypeDeclaration(context, domain); + + tokenizer.skipWhiteSpace(); + + if (!tokenizer.testAndSkip('-')) + continue; + + // If existing, parse and store parent type + auto parentType = parsePrimitiveType(context, domain); + + auto &types = domain.types; + + for (size_t i = inheritanceIndex; i < types.size(); i++) + types[i]->parentTypes.emplace_back(ast::deepCopy(parentType)); + + // All types up to now are labeled with their parent types + inheritanceIndex = types.size() + 1; + + tokenizer.skipWhiteSpace(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Problem.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Problem.cpp new file mode 100644 index 0000000..d577852 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Problem.cpp @@ -0,0 +1,297 @@ +#include + +#include +#include +#include +#include +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Problem +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ProblemParser::ProblemParser(Context &context, ast::Domain &domain) +: m_context{context}, + m_domain{domain}, + m_domainPosition{-1}, + m_requirementsPosition{-1}, + m_objectsPosition{-1}, + m_initialStatePosition{-1}, + m_goalPosition{-1} +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::ProblemPointer ProblemParser::parse() +{ + auto problem = std::make_unique(&m_domain); + + findSections(*problem); + + auto &tokenizer = m_context.tokenizer; + + if (m_domainPosition == -1) + throw ParserException(tokenizer.location(), "problem description does not specify a corresponding domain"); + + tokenizer.seek(m_domainPosition); + parseDomainSection(*problem); + + if (m_requirementsPosition != -1) + { + tokenizer.seek(m_requirementsPosition); + parseRequirementSection(*problem); + } + + if (m_objectsPosition != -1) + { + tokenizer.seek(m_objectsPosition); + parseObjectSection(*problem); + } + + if (m_initialStatePosition == -1) + throw ParserException(tokenizer.location(), "problem description does not specify an initial state"); + + tokenizer.seek(m_initialStatePosition); + parseInitialStateSection(*problem); + + if (m_goalPosition == -1) + 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("("); + tokenizer.expect("define"); + tokenizer.expect("("); + tokenizer.expect("problem"); + + problem.name = tokenizer.getIdentifier(); + + tokenizer.expect(")"); + + const auto setSectionPosition = + [&](const std::string §ionName, auto §ionPosition, const auto value, bool unique = false) + { + if (unique && sectionPosition != -1) + { + tokenizer.seek(value); + throw tokenize::TokenizerException(tokenizer.location(), "only one “:" + sectionName + "” section allowed"); + } + + sectionPosition = value; + }; + + tokenizer.skipWhiteSpace(); + + while (tokenizer.currentCharacter() != ')') + { + const auto position = tokenizer.position(); + + tokenizer.expect("("); + tokenizer.expect(":"); + + const auto sectionIdentifierPosition = tokenizer.position(); + + 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")) + { + tokenizer.seek(sectionIdentifierPosition); + + const auto sectionIdentifier = tokenizer.getIdentifier(); + + m_context.warningCallback(tokenizer.location(), "section type “" + sectionIdentifier + "” currently unsupported"); + + tokenizer.seek(sectionIdentifierPosition); + } + else + { + const auto sectionIdentifier = tokenizer.getIdentifier(); + + tokenizer.seek(position); + throw tokenize::TokenizerException(tokenizer.location(), "unknown problem section “" + sectionIdentifier + "”"); + } + + // Skip section for now and parse it later + skipSection(tokenizer); + + tokenizer.skipWhiteSpace(); + } + + tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ProblemParser::parseDomainSection(ast::Problem &problem) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect(":"); + tokenizer.expect("domain"); + + tokenizer.skipWhiteSpace(); + + const auto domainName = tokenizer.getIdentifier(); + + if (problem.domain->name != domainName) + throw tokenize::TokenizerException(tokenizer.location(), "domains do not match (“" + problem.domain->name + "” and “" + domainName + "”)"); + + tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ProblemParser::parseRequirementSection(ast::Problem &problem) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect(":"); + tokenizer.expect("requirements"); + + while (tokenizer.currentCharacter() != ')') + { + tokenizer.expect(":"); + + problem.requirements.emplace_back(parseRequirement(m_context)); + + 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(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// 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("("); + tokenizer.expect(":"); + tokenizer.expect("objects"); + + // Store constants + parseAndAddConstantDeclarations(m_context, problem); + + tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ProblemParser::parseInitialStateSection(ast::Problem &problem) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect(":"); + tokenizer.expect("init"); + + ASTContext astContext(problem); + + // TODO: reimplement + //problem.initialState = parseInitialState(m_context, astContext); + //tokenizer.expect(")"); + + skipSection(tokenizer); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ProblemParser::parseGoalSection(ast::Problem &problem) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect("("); + tokenizer.expect(":"); + tokenizer.expect("goal"); + + ASTContext expressionContext(problem); + + // TODO: reimplement + //problem.goal = parsePreconditionExpression(m_context, expressionContext); + //tokenizer.expect(")"); + + skipSection(tokenizer); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Requirement.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Requirement.cpp new file mode 100644 index 0000000..fcc6375 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Requirement.cpp @@ -0,0 +1,102 @@ +#include + +#include +#include + +#include +#include + +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; +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}, + {"goal-utilities", ast::Requirement::GoalUtilities}, + }; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::Requirement parseRequirement(Tokenizer &tokenizer) +{ + const auto requirementName = tokenizer.getIdentifier(); + const auto matchingRequirement = requirementNameMap.find(requirementName.c_str()); + + if (matchingRequirement == requirementNameMap.cend()) + throw ParserException(tokenizer.location(), "unknown PDDL requirement “" + requirementName + "”"); + + return matchingRequirement->second; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::Requirement parseRequirement(Context &context) +{ + auto &tokenizer = context.tokenizer; + + auto requirement = parseRequirement(tokenizer); + + if (requirement == ast::Requirement::GoalUtilities) + context.warningCallback(tokenizer.location(), "requirement “goal-utilities” is not part of the PDDL 3.1 specification"); + + return requirement; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +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; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/VariableDeclaration.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/VariableDeclaration.cpp new file mode 100644 index 0000000..811b233 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/parsing/VariableDeclaration.cpp @@ -0,0 +1,69 @@ +#include + +#include +#include +#include +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// VariableDeclaration +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void parseAndAddUntypedVariableDeclaration(Context &context, ast::VariableDeclarations &variableDeclarations) +{ + auto &tokenizer = context.tokenizer; + tokenizer.expect("?"); + auto variableName = tokenizer.getIdentifier(); + + assert(variableName != "-"); + + variableDeclarations.emplace_back(std::make_unique(std::move(variableName))); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::VariableDeclarations parseVariableDeclarations(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 = 0; + + while (tokenizer.currentCharacter() != ')') + { + parseAndAddUntypedVariableDeclaration(context, variableDeclarations); + + tokenizer.skipWhiteSpace(); + + if (!tokenizer.testAndSkip('-')) + continue; + + // If existing, parse and store parent type + auto parentType = parsePrimitiveType(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() + 1; + + tokenizer.skipWhiteSpace(); + } + + return variableDeclarations; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/tests/CMakeLists.txt b/lib/pddlparse/tests/CMakeLists.txt index 9b3c78a..1a89722 100644 --- a/lib/pddlparse/tests/CMakeLists.txt +++ b/lib/pddlparse/tests/CMakeLists.txt @@ -5,6 +5,8 @@ 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 @@ -18,4 +20,4 @@ target_link_libraries(${target} ${libraries}) add_custom_target(run-pddlparse-tests COMMAND ${CMAKE_BINARY_DIR}/bin/pddlparse-tests DEPENDS ${target} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests) + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/../../tests) diff --git a/lib/pddlparse/tests/TestParser.cpp b/lib/pddlparse/tests/TestParser.cpp new file mode 100644 index 0000000..978ed58 --- /dev/null +++ b/lib/pddlparse/tests/TestParser.cpp @@ -0,0 +1,90 @@ +/*#include + +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +TEST_CASE("[parser] The Blocksworld domain is parsed correctly", "[parser]") +{ + const pddl::Context::WarningCallback ignoreWarnings = [](const auto &, const auto &){}; + + pddl::Tokenizer tokenizer; + tokenizer.read("data/blocksworld-domain.pddl"); + pddl::Context context(std::move(tokenizer), ignoreWarnings); + + const auto description = pddl::parseDescription(context); + + REQUIRE_NOTHROW(description.domain()); + + const auto &domain = description.domain(); + + // Name + CHECK(domain.name() == "blocks"); + + // Requirements + REQUIRE(domain.requirements().size() == 2u); + CHECK(domain.requirements()[0].type() == Requirement::Type::STRIPS); + CHECK(domain.requirements()[1].type() == Requirement::Type::Typing); + + // Types + REQUIRE(domain.types().size() == 1u); + + const auto &block = *domain.types()[0]; + + CHECK(block.name() == "block"); + REQUIRE(block.parentTypes().size() == 0u); + + // Predicates + REQUIRE(domain.predicates().size() == 5u); + + const auto &on = *domain.predicates()[0]; + + CHECK(on.name() == "on"); + REQUIRE(on.parameters().size() == 2u); + CHECK(on.parameters()[0]->name() == "x"); + const auto &onArgument0Type = on.parameters()[0]->type()->as(); + CHECK(&onArgument0Type == &block); + CHECK(on.parameters()[1]->name() == "y"); + const auto &onArgument1Type = on.parameters()[1]->type()->as(); + CHECK(&onArgument1Type == &block); + + const auto &handempty = *domain.predicates()[3]; + + CHECK(handempty.name() == "handempty"); + CHECK(handempty.parameters().empty()); + + // Actions + REQUIRE(domain.actions().size() == 4u); + + const auto &pickUp = *domain.actions()[0]; + + CHECK(pickUp.name() == "pick-up"); + REQUIRE(pickUp.parameters().size() == 1u); + CHECK(pickUp.parameters()[0]->name() == "x"); + CHECK(pickUp.parameters()[0]->type() == &block); + + const auto &pickUpPre = pickUp.precondition()->as(); + REQUIRE(pickUpPre.arguments().size() == 3u); + const auto &pickUpPre0 = pickUpPre.arguments()[0]->as(); + CHECK(pickUpPre0.name() == "clear"); + REQUIRE(pickUpPre0.arguments().size() == 1u); + const auto &pickUpPre00 = pickUpPre0.arguments()[0]->as(); + CHECK(pickUpPre00.name() == "x"); + CHECK(pickUpPre00.type() == &block); + CHECK(&pickUpPre00 == pickUp.parameters()[0].get()); + const auto &pickUpPre2 = pickUpPre.arguments()[2]->as(); + CHECK(pickUpPre2.name() == "handempty"); + CHECK(pickUpPre2.arguments().empty()); + + const auto &pickUpEff = pickUp.effect()->as(); + REQUIRE(pickUpEff.arguments().size() == 4u); + const auto &pickUpEff0 = pickUpEff.arguments()[0]->as(); + const auto &pickUpEff00 = pickUpEff0.argument()->as(); + CHECK(pickUpEff00.name() == "ontable"); + REQUIRE(pickUpEff00.arguments().size() == 1u); + const auto &pickUpEff000 = pickUpEff00.arguments()[0]->as(); + CHECK(pickUpEff000.name() == "x"); + CHECK(pickUpEff000.type() == &block); +} +*/ diff --git a/lib/pddlparse/tests/main.cpp b/lib/pddlparse/tests/main.cpp index b3143fb..e622792 100644 --- a/lib/pddlparse/tests/main.cpp +++ b/lib/pddlparse/tests/main.cpp @@ -1,2 +1,22 @@ -#define CATCH_CONFIG_MAIN +/*#define CATCH_CONFIG_MAIN #include +*/ + +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +int main() +{ + const pddl::Context::WarningCallback ignoreWarnings = [](const auto &, const auto &){}; + + pddl::Tokenizer tokenizer; + tokenizer.read("data/blocksworld-domain.pddl"); + tokenizer.read("data/blocksworld-problem.pddl"); + pddl::Context context(std::move(tokenizer), ignoreWarnings); + + const auto description = pddl::parseDescription(context); + + std::cout << description.domain->requirements.size() << std::endl; +} diff --git a/lib/variant b/lib/variant new file mode 160000 index 0000000..d2588a8 --- /dev/null +++ b/lib/variant @@ -0,0 +1 @@ +Subproject commit d2588a8f1d6b5d480d228e6d8a906ce634bdea9a