From 6ce4eecb18d2b4a6c602a4d99bf0d975ee8b7f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Sun, 18 Jun 2017 04:19:42 +0200 Subject: [PATCH] Implemented predicate signature checks. --- .../pddlparse/detail/SignatureMatching.h | 34 +++++ .../pddlparse/detail/SignatureMatching.cpp | 140 ++++++++++++++++++ .../pddlparse/detail/parsing/Predicate.cpp | 42 +++--- 3 files changed, 194 insertions(+), 22 deletions(-) create mode 100644 lib/pddlparse/include/pddlparse/detail/SignatureMatching.h create mode 100644 lib/pddlparse/src/pddlparse/detail/SignatureMatching.cpp diff --git a/lib/pddlparse/include/pddlparse/detail/SignatureMatching.h b/lib/pddlparse/include/pddlparse/detail/SignatureMatching.h new file mode 100644 index 0000000..273d537 --- /dev/null +++ b/lib/pddlparse/include/pddlparse/detail/SignatureMatching.h @@ -0,0 +1,34 @@ +#ifndef __PDDL_PARSE__DETAIL__SIGNATURE_MATCHING_H +#define __PDDL_PARSE__DETAIL__SIGNATURE_MATCHING_H + +#include + +#include + +namespace pddl +{ +namespace detail +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// SignatureMatching +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bool matches(const ast::PrimitiveTypeDeclaration &lhs, const ast::PrimitiveTypeDeclaration &rhs); +bool matches(const ast::Either &lhs, const ast::PrimitiveTypeDeclaration &rhs); +bool matches(const ast::PrimitiveTypeDeclaration &lhs, const ast::Either &rhs); +bool matches(const ast::Either &lhs, const ast::Either &rhs); +bool matches(const ast::VariableDeclaration &lhs, const std::experimental::optional &rhs); +bool matches(const ast::ConstantDeclaration &lhs, const std::experimental::optional &rhs); +bool matches(const ast::Term &lhs, const std::experimental::optional &rhs); + +bool matches(const std::string &predicateName, const ast::Predicate::Arguments &predicateArguments, const ast::PredicateDeclaration &predicateDeclaration); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/lib/pddlparse/src/pddlparse/detail/SignatureMatching.cpp b/lib/pddlparse/src/pddlparse/detail/SignatureMatching.cpp new file mode 100644 index 0000000..d8b0911 --- /dev/null +++ b/lib/pddlparse/src/pddlparse/detail/SignatureMatching.cpp @@ -0,0 +1,140 @@ +#include + +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 &rhs) +{ + for (const auto &rhsType : rhs.arguments) + if (matches(lhs, *rhsType->declaration)) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bool matches(const ast::Either &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 &lhs, const ast::Either &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 +bool matches(const T &lhs, const ast::Type &rhs) +{ + return rhs.match( + [&](const ast::PrimitiveTypePointer &x){return matches(lhs, *x->declaration);}, + [&](const ast::EitherPointer &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 &x){return matches(*x, rhs);}); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bool matches(const ast::VariableDeclaration &lhs, const std::experimental::optional &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 &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 &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; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Predicate.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Predicate.cpp index b3aecbc..73805ef 100644 --- a/lib/pddlparse/src/pddlparse/detail/parsing/Predicate.cpp +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Predicate.cpp @@ -1,6 +1,8 @@ #include #include +#include +#include #include #include #include @@ -19,6 +21,7 @@ namespace detail std::experimental::optional parsePredicate(Context &context, ASTContext &astContext, VariableStack &variableStack) { auto &tokenizer = context.tokenizer; + tokenizer.skipWhiteSpace(); const auto previousPosition = tokenizer.position(); @@ -28,26 +31,9 @@ std::experimental::optional parsePredicate(Context &conte return std::experimental::nullopt; } - const auto predicateName = tokenizer.getIdentifier(); - + const auto name = tokenizer.getIdentifier(); ast::Predicate::Arguments arguments; - /*const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(), - [&](const auto &predicate) - { - return predicate->name() == predicateName; - }); - - if (matchingPredicate == predicates.cend()) - { - tokenizer.seek(position); - return std::experimental::nullopt; - } - - auto predicate = PredicatePointer(new Predicate); - - predicate->m_name = predicateName;*/ - tokenizer.skipWhiteSpace(); // Parse arguments @@ -80,14 +66,26 @@ std::experimental::optional parsePredicate(Context &conte return std::experimental::nullopt; } - //const auto &predicates = astContext.domain->predicates; + const auto &predicates = astContext.domain->predicates; - // TODO: check that signature matches one of the declared ones + 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(")"); - // TODO: add matching predicate declaration - return std::make_unique(std::move(arguments), nullptr); + return std::make_unique(std::move(arguments), declaration); } ////////////////////////////////////////////////////////////////////////////////////////////////////