Renamed “pddlparse” library to simply “pddl”.

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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