From 78b463602887dedba678fe000d71cbaf5e956257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Fri, 16 Jun 2017 04:45:04 +0200 Subject: [PATCH] Continued working on reimplementing action parser. --- .../include/pddlparse/detail/parsing/Action.h | 27 ++- .../pddlparse/detail/parsing/Expressions.h | 47 ++++- .../detail/parsing/VariableDeclaration.h | 1 + .../src/pddlparse/detail/parsing/Action.cpp | 185 +++++++++++++++--- .../src/pddlparse/detail/parsing/Domain.cpp | 2 +- .../detail/parsing/VariableDeclaration.cpp | 15 +- 6 files changed, 244 insertions(+), 33 deletions(-) diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Action.h b/lib/pddlparse/include/pddlparse/detail/parsing/Action.h index dff8ad5..a26382e 100644 --- a/lib/pddlparse/include/pddlparse/detail/parsing/Action.h +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Action.h @@ -15,7 +15,32 @@ namespace detail // //////////////////////////////////////////////////////////////////////////////////////////////////// -void parseAndAddAction(Context &context, ast::Domain &domain); +class ActionParser +{ + public: + ActionParser(Context &context, ast::Domain &domain); + ast::ActionPointer parse(); + + private: + void findSections(ast::Action &action); + + void parseParameterSection(ast::Action &action); + void parsePreconditionSection(ast::Action &action); + void parseEffectSection(ast::Action &action); + + // For compatibility with old PDDL versions + void parseVarsSection(ast::Action &action); + + Context &m_context; + ast::Domain &m_domain; + + tokenize::Stream::Position m_parametersPosition; + tokenize::Stream::Position m_preconditionPosition; + tokenize::Stream::Position m_effectPosition; + + // For compatibility with old PDDL versions + tokenize::Stream::Position m_varsPosition; +}; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/Expressions.h b/lib/pddlparse/include/pddlparse/detail/parsing/Expressions.h index 8fd61d8..e98a644 100644 --- a/lib/pddlparse/include/pddlparse/detail/parsing/Expressions.h +++ b/lib/pddlparse/include/pddlparse/detail/parsing/Expressions.h @@ -146,7 +146,7 @@ std::experimental::optional> parseQuantified(Context &c auto argument = parseArgument(context, astContext, variableStack); if (!argument) - throw ParserException(tokenizer.location(), "could not parse argument of “" + Derived::Identifier + "” expression"); + throw ParserException(tokenizer.location(), "could not parse argument of “" + std::string(Derived::Identifier) + "” expression"); // Clean up variable stack variableStack.pop(); @@ -176,6 +176,22 @@ std::experimental::optional> parseEither(Context &c //////////////////////////////////////////////////////////////////////////////////////////////////// +template +std::experimental::optional> parseExists(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument) +{ + return parseQuantified, ArgumentParser>(context, astContext, variableStack, parseArgument); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +std::experimental::optional> parseForAll(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument) +{ + return parseQuantified, ArgumentParser>(context, astContext, variableStack, parseArgument); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + template std::experimental::optional> parseImply(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument) { @@ -184,6 +200,35 @@ std::experimental::optional> parseImply(Context &con //////////////////////////////////////////////////////////////////////////////////////////////////// +template +std::experimental::optional> parseNot(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument) +{ + auto &tokenizer = context.tokenizer; + + const auto position = tokenizer.position(); + + if (!tokenizer.testAndSkip("(") + || !tokenizer.testIdentifierAndSkip("not")) + { + tokenizer.seek(position); + return std::experimental::nullopt; + } + + tokenizer.skipWhiteSpace(); + + // Parse argument + auto argument = parseArgument(context, astContext, variableStack); + + if (!argument) + throw ParserException(tokenizer.location(), "could not parse argument of “not” expression"); + + tokenizer.expect(")"); + + return std::make_unique>(std::move(argument.value())); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + template std::experimental::optional> parseOr(Context &context, ASTContext &astContext, VariableStack &variableStack, ArgumentParser parseArgument) { diff --git a/lib/pddlparse/include/pddlparse/detail/parsing/VariableDeclaration.h b/lib/pddlparse/include/pddlparse/detail/parsing/VariableDeclaration.h index 4952613..3396fa2 100644 --- a/lib/pddlparse/include/pddlparse/detail/parsing/VariableDeclaration.h +++ b/lib/pddlparse/include/pddlparse/detail/parsing/VariableDeclaration.h @@ -15,6 +15,7 @@ namespace detail // //////////////////////////////////////////////////////////////////////////////////////////////////// +void parseAndAddVariableDeclarations(Context &context, ast::Domain &domain, ast::VariableDeclarations &variableDeclarations); ast::VariableDeclarations parseVariableDeclarations(Context &context, ast::Domain &domain); //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Action.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Action.cpp index c060bdf..f8de932 100644 --- a/lib/pddlparse/src/pddlparse/detail/parsing/Action.cpp +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Action.cpp @@ -1,6 +1,9 @@ #include #include +#include +#include +#include // TODO: remove #include #include @@ -16,50 +19,180 @@ namespace detail // //////////////////////////////////////////////////////////////////////////////////////////////////// -void parseAndAddAction(Context &context, ast::Domain &domain) +ActionParser::ActionParser(Context &context, ast::Domain &domain) +: m_context{context}, + m_domain{domain}, + m_parametersPosition{-1}, + m_preconditionPosition{-1}, + m_effectPosition{-1}, + m_varsPosition{-1} { - auto &tokenizer = context.tokenizer; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::ActionPointer ActionParser::parse() +{ + auto action = std::make_unique(); + + findSections(*action); + + auto &tokenizer = m_context.tokenizer; + + if (m_parametersPosition != -1) + { + tokenizer.seek(m_parametersPosition); + parseParameterSection(*action); + } + + // For compatibility with old PDDL versions, vars sections are parsed in addition to parameters + if (m_varsPosition != -1) + { + tokenizer.seek(m_varsPosition); + parseVarsSection(*action); + } + + if (m_preconditionPosition != -1) + { + tokenizer.seek(m_preconditionPosition); + parsePreconditionSection(*action); + } + + if (m_effectPosition != -1) + { + tokenizer.seek(m_effectPosition); + parseEffectSection(*action); + } + + return action; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ActionParser::findSections(ast::Action &action) +{ + auto &tokenizer = m_context.tokenizer; tokenizer.expect("("); tokenizer.expect(":"); tokenizer.expect("action"); - auto action = std::make_unique(); - action->name = tokenizer.getIdentifier(); + action.name = tokenizer.getIdentifier(); + + // TODO: rename parameters appropriately + const auto setSectionPosition = + [&](const std::string §ionName, auto §ionPosition, const auto value, bool unique = false) + { + if (unique && sectionPosition != -1) + { + tokenizer.seek(value); + throw tokenize::TokenizerException(tokenizer.location(), "only one “:" + sectionName + "” section allowed"); + } + + sectionPosition = value; + }; + + tokenizer.skipWhiteSpace(); + + while (tokenizer.currentCharacter() != ')') + { + const auto position = tokenizer.position(); + + tokenizer.expect(":"); + + 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 (tokenizer.testIdentifierAndSkip("vars")) + setSectionPosition("vars", m_varsPosition, position, true); + else + { + const auto sectionIdentifier = tokenizer.getIdentifier(); + + tokenizer.seek(position); + throw tokenize::TokenizerException(tokenizer.location(), "unknown action section “" + sectionIdentifier + "”"); + } + + tokenizer.expect("("); + + // Skip section for now and parse it later + skipSection(tokenizer); + + tokenizer.skipWhiteSpace(); + } + + tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ActionParser::parseParameterSection(ast::Action &action) +{ + auto &tokenizer = m_context.tokenizer; tokenizer.expect(":parameters"); tokenizer.expect("("); - // Read parameters - action->parameters = parseVariableDeclarations(context, domain); + parseAndAddVariableDeclarations(m_context, m_domain, action.parameters); tokenizer.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ActionParser::parsePreconditionSection(ast::Action &action) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect(":precondition"); + + VariableStack variableStack; + variableStack.push(&action.parameters); + + ASTContext astContext(m_domain); + + action.precondition = parsePrecondition(m_context, astContext, variableStack); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ActionParser::parseEffectSection(ast::Action &) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect(":effect"); + tokenizer.expect("("); // TODO: reimplement - skipSection(tokenizer); + //VariableStack variableStack; + //variableStack.push(&action.parameters); - /* - // Parse preconditions and effects - while (!tokenizer.testAndReturn(')')) - { - tokenizer.expect(":"); + //ASTContext astContext(m_domain); - if (tokenizer.testIdentifierAndSkip("precondition")) - // TODO: reimplement - //action->precondition = parsePreconditionExpression(context, expressionContext); - skipSection(tokenizer); - else if (tokenizer.testIdentifierAndSkip("effect")) - // TODO: reimplement - //action->effect = parseEffectExpression(context, expressionContext); - skipSection(tokenizer); - - tokenizer.skipWhiteSpace(); - }*/ - - // Store new action - domain.actions.emplace_back(std::move(action)); + //action.precondition = parseEffect(m_context, astContext, variableStack); //tokenizer.expect(")"); + + skipSection(tokenizer); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ActionParser::parseVarsSection(ast::Action &action) +{ + auto &tokenizer = m_context.tokenizer; + + tokenizer.expect(":vars"); + tokenizer.expect("("); + + 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(")"); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/Domain.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/Domain.cpp index cc0e4d3..1f51920 100644 --- a/lib/pddlparse/src/pddlparse/detail/parsing/Domain.cpp +++ b/lib/pddlparse/src/pddlparse/detail/parsing/Domain.cpp @@ -294,7 +294,7 @@ void DomainParser::parsePredicateSection(ast::Domain &domain) void DomainParser::parseActionSection(ast::Domain &domain) { - parseAndAddAction(m_context, domain); + domain.actions.emplace_back(ActionParser(m_context, domain).parse()); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/lib/pddlparse/src/pddlparse/detail/parsing/VariableDeclaration.cpp b/lib/pddlparse/src/pddlparse/detail/parsing/VariableDeclaration.cpp index dfa25c1..ff66267 100644 --- a/lib/pddlparse/src/pddlparse/detail/parsing/VariableDeclaration.cpp +++ b/lib/pddlparse/src/pddlparse/detail/parsing/VariableDeclaration.cpp @@ -29,10 +29,8 @@ void parseAndAddUntypedVariableDeclaration(Context &context, ast::VariableDeclar //////////////////////////////////////////////////////////////////////////////////////////////////// -ast::VariableDeclarations parseVariableDeclarations(Context &context, ast::Domain &domain) +void parseAndAddVariableDeclarations(Context &context, ast::Domain &domain, ast::VariableDeclarations &variableDeclarations) { - ast::VariableDeclarations variableDeclarations; - auto &tokenizer = context.tokenizer; tokenizer.skipWhiteSpace(); @@ -58,8 +56,17 @@ ast::VariableDeclarations parseVariableDeclarations(Context &context, ast::Domai tokenizer.skipWhiteSpace(); } +} - return variableDeclarations; +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ast::VariableDeclarations parseVariableDeclarations(Context &context, ast::Domain &domain) +{ + ast::VariableDeclarations result; + + parseAndAddVariableDeclarations(context, domain, result); + + return result; } ////////////////////////////////////////////////////////////////////////////////////////////////////