Started reimplementing expression parsing.

This commit is contained in:
Patrick Lühne 2017-06-16 01:29:49 +02:00
parent fa9fd0935b
commit 62b9da844a
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
3 changed files with 208 additions and 127 deletions

View File

@ -1,127 +0,0 @@
#ifndef __PDDL_PARSE__DETAIL__PARSING__AST_H
#define __PDDL_PARSE__DETAIL__PARSING__AST_H
#include <pddlparse/AST.h>
#include <pddlparse/detail/parsing/Parser.h>
#include <pddlparse/detail/parsing/Utils.h>
namespace pddl
{
namespace detail
{
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ParseAST
//
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Primitives
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
struct Parser<ast::Constant>
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
struct Parser<ast::ConstantDeclaration>
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
struct Parser<ast::PrimitiveType>
{
std::experimental::optional<ast::PrimitiveType> parse(Context &context, ASTContext &astContext)
{
auto &tokenizer = context.tokenizer;
auto &types = astContext.description.domain.types;
tokenizer.skipWhiteSpace();
auto typeName = tokenizer.getIdentifier();
if (typeName.empty())
throw tokenize::TokenizerException(tokenizer.location(), "no type supplied");
auto matchingType = std::find_if(types.begin(), types.end(),
[&](auto &primitiveTypeDeclaration)
{
return primitiveTypeDeclaration->name == typeName;
});
if (matchingType == types.end())
{
// Only “object” is allowed as an implicit type
if (typeName == "object" || typeName == "objects")
{
context.warningCallback(tokenizer.location(), "primitive type “" + typeName + "” should be declared");
types.emplace_back(std::make_unique<ast::PrimitiveTypeDeclaration>(std::move(typeName)));
return ast::PrimitiveType(types.back());
}
else
throw tokenize::TokenizerException(tokenizer.location(), "type “" + typeName + "” used but never declared");
}
auto &type = *matchingType;
return ast::PrimitiveType(type);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
struct Parser<ast::PrimitiveTypeDeclaration>
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
struct Parser<ast::Unsupported>
{
std::experimental::optional<ast::Unsupported> parse(Context &context, ASTContext &)
{
auto &tokenizer = context.tokenizer;
ast::Unsupported unsupported;
tokenizer.expect<std::string>("(");
unsupported.type = tokenizer.getIdentifier();
context.warningCallback(tokenizer.location(), "expression type “" + unsupported.type + "” currently unsupported in this context");
skipSection(tokenizer);
return unsupported;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Expressions
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Argument>
struct Parser<ast::And<Argument>>
{
template<typename ArgumentParser>
std::experimental::optional<ast::And<Argument>> parse(Context &context, ASTContext &astContext, ArgumentParser parseArgument)
{
return Parser<ast::NAry<ast::And<Argument>, Argument>>::parse(context, astContext, parseArgument);
}
};
*/
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

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

View File

@ -48,6 +48,8 @@ ast::VariableDeclarations parseVariableDeclarations(Context &context, ast::Domai
if (!tokenizer.testAndSkip<char>('-'))
continue;
// TODO: reimplement parsing “either” types
// If existing, parse and store parent type
auto parentType = parsePrimitiveType(context, domain);