Major refactoring of underlying Parser class.

This commit is contained in:
Patrick Lühne 2016-08-02 19:58:54 +02:00
parent 73c9d6c1f3
commit 544d4e0635
63 changed files with 1498 additions and 1021 deletions

View File

@ -104,9 +104,7 @@ int main(int argc, char **argv)
try try
{ {
plasp::utils::Parser parser; plasp::utils::Parser<plasp::utils::CaseInsensitiveParserPolicy> parser;
parser.setCaseSensitive(false);
if (variablesMap.count("input")) if (variablesMap.count("input"))
{ {
@ -115,11 +113,11 @@ int main(int argc, char **argv)
std::for_each(inputFiles.cbegin(), inputFiles.cend(), std::for_each(inputFiles.cbegin(), inputFiles.cend(),
[&](const auto &inputFile) [&](const auto &inputFile)
{ {
parser.readFile(inputFile); parser.read(inputFile);
}); });
} }
else else
parser.readStream("std::cin", std::cin); parser.read("std::cin", std::cin);
const auto detectLanguage = const auto detectLanguage =
[&]() [&]()

View File

@ -13,13 +13,12 @@ namespace plasp
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Language::Type detectLanguage(utils::Parser &parser) Language::Type detectLanguage(utils::Parser<utils::CaseInsensitiveParserPolicy> &parser)
{ {
parser.setCaseSensitive(false);
parser.skipWhiteSpace(); parser.skipWhiteSpace();
// SAS begins with "begin_version" // SAS begins with "begin_version"
if (parser.probe<std::string>("begin")) if (parser.testAndSkip<std::string>("begin"))
{ {
parser.seek(0); parser.seek(0);
return Language::Type::SAS; return Language::Type::SAS;
@ -33,7 +32,7 @@ Language::Type detectLanguage(utils::Parser &parser)
} }
// PDDL contains sections starting with "(define" // PDDL contains sections starting with "(define"
if (parser.probe<std::string>("(") && parser.probe<std::string>("define")) if (parser.testAndSkip<std::string>("(") && parser.testAndSkip<std::string>("define"))
{ {
parser.seek(std::ios::beg); parser.seek(std::ios::beg);
return Language::Type::PDDL; return Language::Type::PDDL;

View File

@ -5,6 +5,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <plasp/pddl/Parser.h>
#include <plasp/utils/Logger.h> #include <plasp/utils/Logger.h>
namespace plasp namespace plasp
@ -22,20 +23,21 @@ class Context
{ {
public: public:
Context() = default; Context() = default;
~Context() = default;
explicit Context(utils::Parser &&parser) explicit Context(Parser &&otherParser)
: parser{std::move(parser)} : parser{std::move(otherParser)}
{ {
} }
explicit Context(utils::Logger &&logger) explicit Context(utils::Logger &&otherLogger)
: logger{std::move(logger)} : logger{std::move(otherLogger)}
{ {
} }
explicit Context(utils::Parser &&parser, utils::Logger &&logger) explicit Context(Parser &&otherParser, utils::Logger &&otherLogger)
: parser{std::move(parser)}, : parser{std::move(otherParser)},
logger{std::move(logger)} logger{std::move(otherLogger)}
{ {
} }
@ -56,7 +58,7 @@ class Context
return *this; return *this;
} }
utils::Parser parser; Parser parser;
utils::Logger logger; utils::Logger logger;
}; };

View File

@ -45,9 +45,9 @@ class Description
Context m_context; Context m_context;
utils::Parser::Position m_domainPosition; utils::Stream::Position m_domainPosition;
std::unique_ptr<Domain> m_domain; std::unique_ptr<Domain> m_domain;
utils::Parser::Position m_problemPosition; utils::Stream::Position m_problemPosition;
std::unique_ptr<Problem> m_problem; std::unique_ptr<Problem> m_problem;
}; };

View File

@ -4,10 +4,11 @@
#include <plasp/pddl/Action.h> #include <plasp/pddl/Action.h>
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Parser.h>
#include <plasp/pddl/Requirement.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/pddl/expressions/PredicateDeclaration.h> #include <plasp/pddl/expressions/PredicateDeclaration.h>
#include <plasp/pddl/expressions/PrimitiveType.h> #include <plasp/pddl/expressions/PrimitiveType.h>
#include <plasp/pddl/Requirement.h>
namespace plasp namespace plasp
{ {
@ -68,19 +69,19 @@ class Domain
std::string m_name; std::string m_name;
utils::Parser::Position m_requirementsPosition; utils::Stream::Position m_requirementsPosition;
Requirements m_requirements; Requirements m_requirements;
utils::Parser::Position m_typesPosition; utils::Stream::Position m_typesPosition;
expressions::PrimitiveTypes m_types; expressions::PrimitiveTypes m_types;
utils::Parser::Position m_constantsPosition; utils::Stream::Position m_constantsPosition;
expressions::Constants m_constants; expressions::Constants m_constants;
utils::Parser::Position m_predicatesPosition; utils::Stream::Position m_predicatesPosition;
expressions::PredicateDeclarations m_predicates; expressions::PredicateDeclarations m_predicates;
std::vector<utils::Parser::Position> m_actionPositions; std::vector<utils::Stream::Position> m_actionPositions;
std::vector<std::unique_ptr<Action>> m_actions; std::vector<std::unique_ptr<Action>> m_actions;
}; };

View File

@ -3,7 +3,7 @@
#include <iostream> #include <iostream>
#include <plasp/utils/Parser.h> #include <plasp/pddl/Parser.h>
namespace plasp namespace plasp
{ {
@ -16,7 +16,7 @@ namespace pddl
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
inline void skipSection(utils::Parser &parser) inline void skipSection(Parser &parser)
{ {
size_t openParentheses = 1; size_t openParentheses = 1;

View File

@ -0,0 +1,49 @@
#ifndef __PLASP__PDDL__PARSER_H
#define __PLASP__PDDL__PARSER_H
#include <plasp/utils/Parser.h>
namespace plasp
{
namespace pddl
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Parser
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class PDDLParserPolicy
{
public:
static char transformCharacter(char c) noexcept
{
return std::tolower(c);
}
static bool isWhiteSpace(char c)
{
return std::iswspace(c);
}
static bool isIdentifierCharacter(char c)
{
return c != '?'
&& c != '('
&& c != ')'
&& c != ';'
&& std::isgraph(c);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
using Parser = utils::Parser<PDDLParserPolicy>;
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -4,6 +4,7 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/InitialState.h> #include <plasp/pddl/InitialState.h>
#include <plasp/pddl/Parser.h>
#include <plasp/pddl/Requirement.h> #include <plasp/pddl/Requirement.h>
namespace plasp namespace plasp
@ -61,18 +62,18 @@ class Problem
std::string m_name; std::string m_name;
utils::Parser::Position m_domainPosition; utils::Stream::Position m_domainPosition;
utils::Parser::Position m_requirementsPosition; utils::Stream::Position m_requirementsPosition;
Requirements m_requirements; Requirements m_requirements;
utils::Parser::Position m_objectsPosition; utils::Stream::Position m_objectsPosition;
expressions::Constants m_objects; expressions::Constants m_objects;
utils::Parser::Position m_initialStatePosition; utils::Stream::Position m_initialStatePosition;
std::unique_ptr<InitialState> m_initialState; std::unique_ptr<InitialState> m_initialState;
utils::Parser::Position m_goalPosition; utils::Stream::Position m_goalPosition;
ExpressionPointer m_goal; ExpressionPointer m_goal;
}; };

View File

@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
namespace plasp namespace plasp
{ {
@ -57,8 +56,8 @@ AtPointer At::parse(Context &context, ExpressionContext &expressionContext,
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(") if (!parser.testAndSkip<std::string>("(")
|| !parser.probeIdentifier("at", isIdentifier)) || !parser.testIdentifierAndSkip("at"))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;
@ -68,9 +67,9 @@ AtPointer At::parse(Context &context, ExpressionContext &expressionContext,
const auto timePointPosition = parser.position(); const auto timePointPosition = parser.position();
if (parser.probeIdentifier("start", isIdentifier)) if (parser.testIdentifierAndSkip("start"))
timePoint = TimePointStart; timePoint = TimePointStart;
else if (parser.probeIdentifier("end", isIdentifier)) else if (parser.testIdentifierAndSkip("end"))
timePoint = TimePointEnd; timePoint = TimePointEnd;
else if (parser.probeNumber()) else if (parser.probeNumber())
{ {

View File

@ -4,7 +4,6 @@
#include <plasp/pddl/ConsistencyException.h> #include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Variable.h> #include <plasp/pddl/expressions/Variable.h>
namespace plasp namespace plasp
@ -52,8 +51,8 @@ std::unique_ptr<Derived> Binary<Derived>::parse(Context &context,
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(") if (!parser.testAndSkip<std::string>("(")
|| !parser.probeIdentifier(Derived::Identifier, isIdentifier)) || !parser.testIdentifierAndSkip(Derived::Identifier))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;

View File

@ -2,7 +2,6 @@
#define __PLASP__PDDL__EXPRESSIONS__CONSTANT_H #define __PLASP__PDDL__EXPRESSIONS__CONSTANT_H
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/utils/Parser.h> #include <plasp/utils/Parser.h>
#include <plasp/utils/ParserException.h> #include <plasp/utils/ParserException.h>

View File

@ -4,7 +4,6 @@
#include <plasp/pddl/ConsistencyException.h> #include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Variable.h> #include <plasp/pddl/expressions/Variable.h>
namespace plasp namespace plasp
@ -50,8 +49,8 @@ std::unique_ptr<Derived> NAry<Derived>::parse(Context &context,
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(") if (!parser.testAndSkip<std::string>("(")
|| !parser.probeIdentifier(Derived::Identifier, isIdentifier)) || !parser.testIdentifierAndSkip(Derived::Identifier))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;
@ -71,7 +70,7 @@ std::unique_ptr<Derived> NAry<Derived>::parse(Context &context,
} }
if (expression->m_arguments.empty()) if (expression->m_arguments.empty())
context.logger.logWarning(context.parser, "" + Derived::Identifier + "” expressions should not be empty"); context.logger.logWarning(parser.coordinate(), "" + Derived::Identifier + "” expressions should not be empty");
parser.expect<std::string>(")"); parser.expect<std::string>(")");

View File

@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
namespace plasp namespace plasp
{ {
@ -50,8 +49,8 @@ NotPointer Not::parse(Context &context, ExpressionContext &expressionContext,
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(") if (!parser.testAndSkip<std::string>("(")
|| !parser.probeIdentifier("not", isIdentifier)) || !parser.testIdentifierAndSkip("not"))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;

View File

@ -3,7 +3,6 @@
#include <plasp/pddl/ConsistencyException.h> #include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Expression.h> #include <plasp/pddl/Expression.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/utils/ParserException.h> #include <plasp/utils/ParserException.h>
namespace plasp namespace plasp

View File

@ -27,8 +27,8 @@ using AssignedVariables = std::vector<AssignedVariable>;
class AssignedVariable class AssignedVariable
{ {
public: public:
static AssignedVariable fromSAS(utils::Parser &parser, const Variables &variables); static AssignedVariable fromSAS(utils::Parser<> &parser, const Variables &variables);
static AssignedVariable fromSAS(utils::Parser &parser, const Variable &variable); static AssignedVariable fromSAS(utils::Parser<> &parser, const Variable &variable);
public: public:
explicit AssignedVariable(const Variable &variable, const Value &value); explicit AssignedVariable(const Variable &variable, const Value &value);

View File

@ -29,7 +29,7 @@ class AxiomRule
using Condition = AssignedVariable; using Condition = AssignedVariable;
using Conditions = AssignedVariables; using Conditions = AssignedVariables;
static AxiomRule fromSAS(utils::Parser &parser, const Variables &variables); static AxiomRule fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Conditions &conditions() const; const Conditions &conditions() const;

View File

@ -29,7 +29,7 @@ namespace sas
class Description class Description
{ {
public: public:
static Description fromParser(utils::Parser &&parser); static Description fromParser(utils::Parser<> &&parser);
static Description fromStream(std::istream &istream); static Description fromStream(std::istream &istream);
static Description fromFile(const boost::filesystem::path &path); static Description fromFile(const boost::filesystem::path &path);
@ -48,16 +48,16 @@ class Description
private: private:
Description(); Description();
void parseContent(utils::Parser &parser); void parseContent(utils::Parser<> &parser);
void parseVersionSection(utils::Parser &parser) const; void parseVersionSection(utils::Parser<> &parser) const;
void parseMetricSection(utils::Parser &parser); void parseMetricSection(utils::Parser<> &parser);
void parseVariablesSection(utils::Parser &parser); void parseVariablesSection(utils::Parser<> &parser);
void parseMutexSection(utils::Parser &parser); void parseMutexSection(utils::Parser<> &parser);
void parseInitialStateSection(utils::Parser &parser); void parseInitialStateSection(utils::Parser<> &parser);
void parseGoalSection(utils::Parser &parser); void parseGoalSection(utils::Parser<> &parser);
void parseOperatorSection(utils::Parser &parser); void parseOperatorSection(utils::Parser<> &parser);
void parseAxiomSection(utils::Parser &parser); void parseAxiomSection(utils::Parser<> &parser);
bool m_usesActionCosts; bool m_usesActionCosts;

View File

@ -29,7 +29,7 @@ class Effect
using Condition = AssignedVariable; using Condition = AssignedVariable;
using Conditions = AssignedVariables; using Conditions = AssignedVariables;
static Effect fromSAS(utils::Parser &parser, const Variables &variables, Conditions &preconditions); static Effect fromSAS(utils::Parser<> &parser, const Variables &variables, Conditions &preconditions);
public: public:
const Conditions &conditions() const; const Conditions &conditions() const;

View File

@ -21,7 +21,7 @@ class Goal
using Fact = AssignedVariable; using Fact = AssignedVariable;
using Facts = AssignedVariables; using Facts = AssignedVariables;
static Goal fromSAS(utils::Parser &parser, const Variables &variables); static Goal fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Facts &facts() const; const Facts &facts() const;

View File

@ -21,7 +21,7 @@ class InitialState
using Fact = AssignedVariable; using Fact = AssignedVariable;
using Facts = AssignedVariables; using Facts = AssignedVariables;
static InitialState fromSAS(utils::Parser &parser, const Variables &variables); static InitialState fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Facts &facts() const; const Facts &facts() const;

View File

@ -28,7 +28,7 @@ class MutexGroup
using Fact = AssignedVariable; using Fact = AssignedVariable;
using Facts = AssignedVariables; using Facts = AssignedVariables;
static MutexGroup fromSAS(utils::Parser &parser, const Variables &variables); static MutexGroup fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Facts &facts() const; const Facts &facts() const;

View File

@ -33,7 +33,7 @@ class Operator
using Condition = AssignedVariable; using Condition = AssignedVariable;
using Conditions = AssignedVariables; using Conditions = AssignedVariables;
static Operator fromSAS(utils::Parser &parser, const Variables &variables); static Operator fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
void printPredicateAsASP(utils::LogStream &ostream) const; void printPredicateAsASP(utils::LogStream &ostream) const;

View File

@ -22,7 +22,7 @@ namespace sas
class Predicate class Predicate
{ {
public: public:
static Predicate fromSAS(utils::Parser &parser); static Predicate fromSAS(utils::Parser<> &parser);
using Arguments = std::vector<std::string>; using Arguments = std::vector<std::string>;

View File

@ -39,8 +39,8 @@ struct Value
static const Value Any; static const Value Any;
static const Value None; static const Value None;
static Value fromSAS(utils::Parser &parser); static Value fromSAS(utils::Parser<> &parser);
static const Value &referenceFromSAS(utils::Parser &parser, const Variable &variable); static const Value &referenceFromSAS(utils::Parser<> &parser, const Variable &variable);
public: public:
Value negated() const; Value negated() const;

View File

@ -28,8 +28,8 @@ using Variables = std::vector<Variable>;
class Variable class Variable
{ {
public: public:
static Variable fromSAS(utils::Parser &parser); static Variable fromSAS(utils::Parser<> &parser);
static const Variable &referenceFromSAS(utils::Parser &parser, const Variables &variables); static const Variable &referenceFromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
void printNameAsASPPredicate(utils::LogStream &outputStream) const; void printNameAsASPPredicate(utils::LogStream &outputStream) const;

View File

@ -26,7 +26,7 @@ using VariableTransitions = std::vector<VariableTransition>;
class VariableTransition class VariableTransition
{ {
public: public:
static VariableTransition fromSAS(utils::Parser &parser, const Variables &variables); static VariableTransition fromSAS(utils::Parser<> &parser, const Variables &variables);
public: public:
const Variable &variable() const; const Variable &variable() const;

View File

@ -4,8 +4,8 @@
#include <string> #include <string>
#include <plasp/utils/LogStream.h> #include <plasp/utils/LogStream.h>
#include <plasp/utils/Parser.h>
#include <plasp/utils/ParserException.h> #include <plasp/utils/ParserException.h>
#include <plasp/utils/StreamCoordinate.h>
namespace plasp namespace plasp
{ {
@ -44,8 +44,8 @@ class Logger
void setColorPolicy(LogStream::ColorPolicy colorPolicy); void setColorPolicy(LogStream::ColorPolicy colorPolicy);
void logError(const std::string &message); void logError(const std::string &message);
void logError(const Parser::Coordinate &coordinate, const std::string &message); void logError(const StreamCoordinate &coordinate, const std::string &message);
void logWarning(const Parser &parser, const std::string &message); void logWarning(const StreamCoordinate &parserCoordinate, const std::string &message);
private: private:
LogStream m_outputStream; LogStream m_outputStream;

View File

@ -8,112 +8,192 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <plasp/utils/ParserException.h>
#include <plasp/utils/ParserPolicy.h>
#include <plasp/utils/ParserTraits.h>
#include <plasp/utils/Stream.h>
#include <plasp/utils/StreamCoordinate.h>
namespace plasp namespace plasp
{ {
namespace utils namespace utils
{ {
template<typename Type>
struct Tag
{
};
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Parser // Parser
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
class Parser template<class ParserPolicy = CaseSensitiveParserPolicy>
class Parser: public Stream, public ParserPolicy
{ {
public:
using Position = std::stringstream::pos_type;
struct Coordinate
{
std::string sectionName;
size_t row;
size_t column;
};
struct StreamDelimiter
{
Position position;
std::string sectionName;
};
public: public:
explicit Parser(); explicit Parser();
explicit Parser(std::string streamName, std::istream &istream); explicit Parser(std::string streamName, std::istream &istream);
// Forbid copy construction/assignment template<class OtherParser>
Parser(const Parser &other) = delete; Parser(OtherParser &&otherParser)
Parser &operator=(const Parser &other) = delete; {
m_stream = std::move(otherParser.m_stream);
Parser(Parser &&other); m_delimiters = std::move(otherParser.m_delimiters);
Parser &operator=(Parser &&other); }
void readStream(std::string streamName, std::istream &istream);
void readFile(const boost::filesystem::path &path);
void reset();
void seek(Position position);
Position position() const;
Coordinate coordinate() const;
void setCaseSensitive(bool isCaseInsensitive = true);
bool isCaseSensitive() const noexcept;
char currentCharacter() const;
void advance();
bool atEndOfStream() const;
void removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd); void removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd);
char currentCharacter() const;
template<typename Type> template<typename Type>
Type parse(); Type parse();
template<class CharacterPredicate, class WhiteSpacePredicate> template<typename Type>
std::string parseIdentifier(CharacterPredicate characterPredicate, WhiteSpacePredicate whiteSpacePredicate); bool testAndReturn(const Type &expectedValue);
template<class CharacterPredicate>
std::string parseIdentifier(CharacterPredicate characterPredicate);
template<typename Type> template<typename Type>
bool probe(const Type &expectedValue); bool testAndSkip(const Type &expectedValue);
template<class CharacterPredicate>
bool probeIdentifier(const std::string &identifier, CharacterPredicate characterPredicate);
bool probeNumber();
template<typename Type> template<typename Type>
void expect(const Type &expectedValue); void expect(const Type &expectedValue);
template<class WhiteSpacePredicate> std::string parseIdentifier();
void skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate); bool testIdentifierAndReturn(const std::string &identifier);
bool testIdentifierAndSkip(const std::string &identifier);
// TODO: remove
bool probeNumber();
std::string parseLine();
void skipWhiteSpace(); void skipWhiteSpace();
void skipLine(); void skipLine();
std::string getLine();
private: private:
static const std::istreambuf_iterator<char> EndOfFile; std::string parseImpl(Tag<std::string>);
char parseImpl(Tag<char>);
uint64_t parseImpl(Tag<uint64_t>);
int64_t parseImpl(Tag<int64_t>);
uint32_t parseImpl(Tag<uint32_t>);
int32_t parseImpl(Tag<int32_t>);
bool parseImpl(Tag<bool>);
private: bool testImpl(const std::string &expectedValue);
void checkStream() const; bool testImpl(char expectedValue);
bool testImpl(uint64_t expectedValue);
bool testImpl(int64_t expectedValue);
bool testImpl(uint32_t expectedValue);
bool testImpl(int32_t expectedValue);
bool testImpl(bool expectedValue);
uint64_t parseIntegerBody(); uint64_t parseIntegerBody();
mutable std::stringstream m_stream;
std::vector<StreamDelimiter> m_streamDelimiters;
bool m_isCaseSensitive;
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class CharacterPredicate, class WhiteSpacePredicate> template<class ParserPolicy>
std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, WhiteSpacePredicate whiteSpacePredicate) Parser<ParserPolicy>::Parser()
: Stream()
{ {
skipWhiteSpace(whiteSpacePredicate); }
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
Parser<ParserPolicy>::Parser(std::string streamName, std::istream &istream)
: Stream(streamName, istream)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
void Parser<ParserPolicy>::skipWhiteSpace()
{
check();
while (!atEnd() && ParserPolicy::isWhiteSpace(currentCharacter()))
advance();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
void Parser<ParserPolicy>::skipLine()
{
check();
while (currentCharacter() != '\n')
advance();
advance();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
template<typename Type>
Type Parser<ParserPolicy>::parse()
{
return parseImpl(Tag<Type>());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
template<typename Type>
bool Parser<ParserPolicy>::testAndReturn(const Type &expectedValue)
{
const auto previousPosition = position();
const auto result = testImpl(expectedValue);
seek(previousPosition);
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
template<typename Type>
bool Parser<ParserPolicy>::testAndSkip(const Type &expectedValue)
{
const auto previousPosition = position();
const auto result = testImpl(expectedValue);
if (result == false)
seek(previousPosition);
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
template<typename Type>
void Parser<ParserPolicy>::expect(const Type &expectedValue)
{
if (testAndSkip(expectedValue))
return;
std::stringstream message;
message << "unexpected value, expected “" << expectedValue << "";
throw ParserException(coordinate(), message.str());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
std::string Parser<ParserPolicy>::parseIdentifier()
{
skipWhiteSpace();
std::string value; std::string value;
@ -121,7 +201,7 @@ std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, White
{ {
const auto character = currentCharacter(); const auto character = currentCharacter();
if (!characterPredicate(character)) if (!ParserPolicy::isIdentifierCharacter(character))
return value; return value;
value.push_back(character); value.push_back(character);
@ -131,33 +211,342 @@ std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, White
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class CharacterPredicate> template<class ParserPolicy>
std::string Parser::parseIdentifier(CharacterPredicate characterPredicate) bool Parser<ParserPolicy>::testIdentifierAndSkip(const std::string &expectedValue)
{ {
return parseIdentifier(characterPredicate, return testAndSkip(expectedValue) && !ParserPolicy::isIdentifierCharacter(currentCharacter());
[&](const auto character)
{
return std::isspace(character);
});
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class CharacterPredicate> template<class ParserPolicy>
bool Parser::probeIdentifier(const std::string &expectedValue, CharacterPredicate characterPredicate) bool Parser<ParserPolicy>::probeNumber()
{ {
return probe<std::string>(expectedValue) && !characterPredicate(currentCharacter()); const auto previousPosition = position();
skipWhiteSpace();
while (!ParserPolicy::isWhiteSpace(currentCharacter()))
if (!std::isdigit(currentCharacter()))
{
seek(previousPosition);
return false;
}
return true;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class WhiteSpacePredicate> template<class ParserPolicy>
void Parser::skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate) std::string Parser<ParserPolicy>::parseLine()
{ {
checkStream(); std::string value;
while (!atEndOfStream() && whiteSpacePredicate(currentCharacter())) while (true)
{
const auto character = currentCharacter();
advance(); advance();
if (character == '\n')
break;
else if (character == '\r')
continue;
value.push_back(character);
}
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
void Parser<ParserPolicy>::removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd)
{
const auto inPosition = m_stream.tellg();
const auto outPosition = m_stream.tellp();
m_stream.seekg(0);
const auto removeRange =
[&](const auto &start, const auto &end)
{
BOOST_ASSERT(start != -1);
m_stream.clear();
m_stream.seekp(start);
m_stream.seekg(start);
auto position = start;
while (end == -1 || position < end)
{
m_stream.ignore(1);
if (atEnd())
return;
m_stream.put(' ');
position += static_cast<std::streamoff>(1);
}
};
while (!atEnd())
{
Position startPosition = m_stream.tellg();
while (!atEnd())
{
startPosition = m_stream.tellg();
if (testAndSkip(startSequence))
break;
advance();
}
Position endPosition = m_stream.tellg();
while (!atEnd())
{
endPosition = m_stream.tellg();
if (testAndSkip(endSequence))
break;
advance();
}
if (removeEnd)
endPosition = m_stream.tellg();
removeRange(startPosition, endPosition);
}
m_stream.clear();
m_stream.seekg(inPosition);
m_stream.seekp(outPosition);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
char Parser<ParserPolicy>::currentCharacter() const
{
return ParserPolicy::transformCharacter(Stream::currentCharacter());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
std::string Parser<ParserPolicy>::parseImpl(Tag<std::string>)
{
skipWhiteSpace();
const auto startPosition = position();
while (!ParserPolicy::isWhiteSpace(currentCharacter()))
advance();
const auto endPosition = position();
const auto length = static_cast<size_t>(endPosition - startPosition);
std::string value;
value.reserve(length);
seek(startPosition);
for (size_t i = 0; i < length; i++)
{
value.push_back(currentCharacter());
advance();
}
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
char Parser<ParserPolicy>::parseImpl(Tag<char>)
{
const auto value = currentCharacter();
advance();
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
uint64_t Parser<ParserPolicy>::parseIntegerBody()
{
check();
if (!std::isdigit(currentCharacter()))
throw ParserException(coordinate(), "could not parse integer value");
uint64_t value = 0;
while (!atEnd())
{
const auto character = currentCharacter();
if (!std::isdigit(character))
break;
value *= 10;
value += character - '0';
advance();
}
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
int64_t Parser<ParserPolicy>::parseImpl(Tag<int64_t>)
{
skipWhiteSpace();
bool positive = testAndSkip<char>('+') || !testAndSkip<char>('-');
const auto value = parseIntegerBody();
return (positive ? value : -value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
uint64_t Parser<ParserPolicy>::parseImpl(Tag<uint64_t>)
{
skipWhiteSpace();
if (currentCharacter() == '-')
throw ParserException(coordinate(), "expected unsigned integer, got signed one");
return parseIntegerBody();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
int32_t Parser<ParserPolicy>::parseImpl(Tag<int32_t>)
{
return static_cast<int32_t>(parseImpl(Tag<int64_t>()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
uint32_t Parser<ParserPolicy>::parseImpl(Tag<uint32_t>)
{
return static_cast<uint32_t>(parseImpl(Tag<uint64_t>()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::parseImpl(Tag<bool>)
{
skipWhiteSpace();
if (testAndSkip<char>('0'))
return false;
if (testAndSkip<char>('1'))
return true;
throw ParserException(coordinate(), "could not parse Boolean value");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::testImpl(const std::string &expectedValue)
{
if (!ParserPolicy::isWhiteSpace(expectedValue.front()))
skipWhiteSpace();
const auto match = std::find_if(expectedValue.cbegin(), expectedValue.cend(),
[&](const auto &expectedCharacter)
{
const auto character = static_cast<char>(this->currentCharacter());
if (character != expectedCharacter)
return true;
this->advance();
return false;
});
return (match == expectedValue.cend());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::testImpl(char expectedValue)
{
const auto result = (currentCharacter() == expectedValue);
advance();
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::testImpl(int64_t expectedValue)
{
const auto value = parseImpl(Tag<int64_t>());
return (value == expectedValue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::testImpl(uint64_t expectedValue)
{
const auto value = parseImpl(Tag<uint64_t>());
return (value == expectedValue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::testImpl(int32_t expectedValue)
{
return testImpl(static_cast<int64_t>(expectedValue));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::testImpl(uint32_t expectedValue)
{
return testImpl(static_cast<uint64_t>(expectedValue));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
bool Parser<ParserPolicy>::testImpl(bool expectedValue)
{
const auto value = parseImpl(Tag<bool>());
return (value == expectedValue);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -4,7 +4,7 @@
#include <exception> #include <exception>
#include <string> #include <string>
#include <plasp/utils/Parser.h> #include <plasp/utils/StreamCoordinate.h>
namespace plasp namespace plasp
{ {
@ -20,18 +20,18 @@ namespace utils
class ParserException: public std::exception class ParserException: public std::exception
{ {
public: public:
explicit ParserException(const utils::Parser &parser) explicit ParserException(const StreamCoordinate &coordinate)
: ParserException(parser, "unspecified parser error") : ParserException(coordinate, "unspecified parser error")
{ {
} }
explicit ParserException(const utils::Parser &parser, const char *message) explicit ParserException(const StreamCoordinate &coordinate, const char *message)
: ParserException(parser, static_cast<std::string>(message)) : ParserException(coordinate, static_cast<std::string>(message))
{ {
} }
explicit ParserException(const utils::Parser &parser, const std::string &message) explicit ParserException(const StreamCoordinate &coordinate, const std::string &message)
: m_coordinate{parser.coordinate()}, : m_coordinate{coordinate},
m_message{message}, m_message{message},
m_plainMessage{m_coordinate.sectionName + ":" + std::to_string(m_coordinate.row) m_plainMessage{m_coordinate.sectionName + ":" + std::to_string(m_coordinate.row)
+ ":" + std::to_string(m_coordinate.column) + " " + m_message} + ":" + std::to_string(m_coordinate.column) + " " + m_message}
@ -47,7 +47,7 @@ class ParserException: public std::exception
return m_plainMessage.c_str(); return m_plainMessage.c_str();
} }
const Parser::Coordinate &coordinate() const const StreamCoordinate &coordinate() const
{ {
return m_coordinate; return m_coordinate;
} }
@ -58,7 +58,7 @@ class ParserException: public std::exception
} }
private: private:
Parser::Coordinate m_coordinate; StreamCoordinate m_coordinate;
std::string m_message; std::string m_message;
std::string m_plainMessage; std::string m_plainMessage;
}; };

View File

@ -0,0 +1,62 @@
#ifndef __PLASP__UTILS__PARSER_POLICY_H
#define __PLASP__UTILS__PARSER_POLICY_H
#include <iostream>
namespace plasp
{
namespace utils
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ParserPolicy
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class CaseSensitiveParserPolicy
{
public:
static constexpr char transformCharacter(char c) noexcept
{
return c;
}
static bool isWhiteSpace(char c)
{
return std::iswspace(c);
}
static bool isIdentifierCharacter(char c)
{
return std::isgraph(c);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
class CaseInsensitiveParserPolicy
{
public:
static char transformCharacter(char c) noexcept
{
return std::tolower(c);
}
static bool isWhiteSpace(char c)
{
return std::iswspace(c);
}
static bool isIdentifierCharacter(char c)
{
return std::isgraph(c);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -0,0 +1,363 @@
#ifndef __PLASP__UTILS__PARSER_TRAITS_H
#define __PLASP__UTILS__PARSER_TRAITS_H
#include <algorithm>
#include <sstream>
#include <string>
namespace plasp
{
namespace utils
{
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ParserTraits
//
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy, typename Type>
class ParserTraits
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
class ParserTraits<ParserPolicy, std::string>
{
public:
static std::string parse(Parser<ParserPolicy> &parser);
static bool testAndReturn(Parser<ParserPolicy> &parser, const std::string &value);
static bool testAndSkip(Parser<ParserPolicy> &parser, const std::string &value);
static void expect(Parser<ParserPolicy> &parser, const std::string &expectedValue);
static bool test(Parser<ParserPolicy> &parser, const std::string &value);
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
class ParserTraits<ParserPolicy, char>
{
public:
static char parse(Parser<ParserPolicy> &parser);
static bool testAndReturn(Parser<ParserPolicy> &parser, const char &value);
static bool testAndSkip(Parser<ParserPolicy> &parser, const char &value);
static void expect(Parser<ParserPolicy> &parser, const char &expectedValue);
static bool test(Parser<ParserPolicy> &parser, const char &value);
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
class ParserTraits<ParserPolicy, uint64_t>
{
public:
static uint64_t parse(Parser<ParserPolicy> &parser);
static bool testAndReturn(Parser<ParserPolicy> &parser, const uint64_t &value);
static bool testAndSkip(Parser<ParserPolicy> &parser, const uint64_t &value);
static void expect(Parser<ParserPolicy> &parser, const uint64_t &expectedValue);
static bool test(Parser<ParserPolicy> &parser, const uint64_t &value);
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
class ParserTraits<ParserPolicy, int64_t>
{
public:
static int64_t parse(Parser<ParserPolicy> &parser);
static bool testAndReturn(Parser<ParserPolicy> &parser, const int64_t &value);
static bool testAndSkip(Parser<ParserPolicy> &parser, const int64_t &value);
static void expect(Parser<ParserPolicy> &parser, const int64_t &expectedValue);
static bool test(Parser<ParserPolicy> &parser, const int64_t &value);
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
class ParserTraits<ParserPolicy, uint32_t>
{
public:
static uint32_t parse(Parser<ParserPolicy> &parser);
static bool testAndReturn(Parser<ParserPolicy> &parser, const uint32_t &value);
static bool testAndSkip(Parser<ParserPolicy> &parser, const uint32_t &value);
static void expect(Parser<ParserPolicy> &parser, const uint32_t &expectedValue);
static bool test(Parser<ParserPolicy> &parser, const uint32_t &value);
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
class ParserTraits<ParserPolicy, int32_t>
{
public:
static int32_t parse(Parser<ParserPolicy> &parser);
static bool testAndReturn(Parser<ParserPolicy> &parser, const int32_t &value);
static bool testAndSkip(Parser<ParserPolicy> &parser, const int32_t &value);
static void expect(Parser<ParserPolicy> &parser, const int32_t &expectedValue);
static bool test(Parser<ParserPolicy> &parser, const int32_t &value);
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
class ParserTraits<ParserPolicy, bool>
{
public:
static bool parse(Parser<ParserPolicy> &parser);
static bool testAndReturn(Parser<ParserPolicy> &parser, const bool &value);
static bool testAndSkip(Parser<ParserPolicy> &parser, const bool &value);
static void expect(Parser<ParserPolicy> &parser, const bool &expectedValue);
static bool test(Parser<ParserPolicy> &parser, const bool &value);
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser, typename Type>
bool ParserTraits<Parser, Type>::testAndReturn(Parser &parser, const Type &value)
{
const auto position = parser.position();
const auto result = test(parser, value);
parser.seek(position);
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser, typename Type>
bool ParserTraits<Parser, Type>::testAndSkip(Parser &parser, const Type &value)
{
const auto position = parser.position();
const auto result = test(parser, value);
if (result == false)
parser.seek(position);
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class ParserPolicy>
void Parser<ParserPolicy>::expect(const Type &expectedValue)
{
if (testAndSkip(parser, expectedValue))
return;
std::stringstream message;
message << "unexpected value, expected “" << expectedValue << "";
throw ParserException(parser.coordinate(), message.str());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
std::string ParserTraits<Parser, std::string>::parse(Parser &parser)
{
parser.skipWhiteSpace();
const auto startPosition = parser.position();
while (!parser.isWhiteSpace(parser.currentCharacter()))
parser.advance();
const auto endPosition = parser.position();
const auto length = static_cast<size_t>(endPosition - startPosition);
std::string value;
value.reserve(length);
parser.seek(startPosition);
for (size_t i = 0; i < length; i++)
{
value.push_back(parser.currentCharacter());
parser.advance();
}
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
char ParserTraits<Parser, char>::parse(Parser &parser)
{
const auto value = parser.currentCharacter();
parser.advance();
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
uint64_t parseIntegerBody(Parser &parser)
{
parser.checkStream();
if (!std::isdigit(parser.currentCharacter()))
throw ParserException(parser.coordinate(), "could not parse integer value");
uint64_t value = 0;
while (!parser.atEndOfStream())
{
const auto character = parser.currentCharacter();
if (!std::isdigit(character))
break;
value *= 10;
value += character - '0';
parser.advance();
}
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
int64_t ParserTraits<Parser, int64_t>::parse(Parser &parser)
{
parser.skipWhiteSpace();
bool positive = parser.template testAndSkip<char>('+') || !parser.template testAndSkip<char>('-');
const auto value = parseIntegerBody(parser);
return (positive ? value : -value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
uint64_t ParserTraits<Parser, uint64_t>::parse(Parser &parser)
{
parser.skipWhiteSpace();
if (parser.currentCharacter() == '-')
throw ParserException(parser.coordinate(), "expected unsigned integer, got signed one");
return parseIntegerBody(parser);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
int32_t ParserTraits<Parser, int32_t>::parse(Parser &parser)
{
return static_cast<int32_t>(ParserTraits<Parser, int64_t>::parse(parser));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
uint32_t ParserTraits<Parser, uint32_t>::parse(Parser &parser)
{
return static_cast<uint32_t>(ParserTraits<Parser, uint64_t>::parse(parser));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
bool ParserTraits<Parser, bool>::parse(Parser &parser)
{
parser.skipWhiteSpace();
if (parser.template testAndSkip<char>('0'))
return false;
if (parser.template testAndSkip<char>('1'))
return true;
throw ParserException(parser.coordinate(), "could not parse Boolean value");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
bool ParserTraits<Parser, std::string>::test(Parser &parser, const std::string &expectedValue)
{
if (!parser.isWhiteSpace(expectedValue.front()))
parser.skipWhiteSpace();
const auto match = std::find_if(expectedValue.cbegin(), expectedValue.cend(),
[&parser](const auto &expectedCharacter)
{
const auto character = static_cast<char>(parser.currentCharacter());
if (character != expectedCharacter)
return true;
parser.advance();
return false;
});
return (match == expectedValue.cend());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
bool ParserTraits<Parser, char>::test(Parser &parser, const char &expectedValue)
{
const auto result = (parser.currentCharacter() == expectedValue);
parser.advance();
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
bool ParserTraits<Parser, int64_t>::test(Parser &parser, const int64_t &expectedValue)
{
const auto value = parse(parser);
return (value == expectedValue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
bool ParserTraits<Parser, uint64_t>::test(Parser &parser, const uint64_t &expectedValue)
{
const auto value = parse(parser);
return (value == expectedValue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
bool ParserTraits<Parser, int32_t>::test(Parser &parser, const int32_t &expectedValue)
{
return ParserTraits<Parser, int64_t>::test(parser, static_cast<int64_t>(expectedValue));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class Parser>
bool ParserTraits<Parser, uint32_t>::test(Parser &parser, const uint32_t &expectedValue)
{
return ParserTraits<Parser, uint64_t>::test(parser, static_cast<uint64_t>(expectedValue));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
}
}
#endif

View File

@ -0,0 +1,85 @@
#ifndef __PLASP__UTILS__STREAM_H
#define __PLASP__UTILS__STREAM_H
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
#include <boost/filesystem.hpp>
#include <plasp/utils/ParserException.h>
#include <plasp/utils/StreamCoordinate.h>
namespace plasp
{
namespace utils
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Stream
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class Stream
{
public:
using Position = std::stringstream::pos_type;
struct Delimiter
{
Position position;
std::string sectionName;
};
public:
explicit Stream();
explicit Stream(std::string streamName, std::istream &istream);
Stream(const Stream &other) = delete;
Stream &operator=(const Stream &other) = delete;
Stream(Stream &&other)
: m_stream{std::move(other.m_stream)},
m_delimiters{std::move(other.m_delimiters)}
{
}
Stream &operator=(Stream &&other)
{
m_stream = std::move(other.m_stream);
m_delimiters = std::move(other.m_delimiters);
return *this;
}
~Stream() = default;
void read(std::string streamName, std::istream &istream);
void read(const boost::filesystem::path &path);
void reset();
void seek(Position position);
Position position() const;
StreamCoordinate coordinate() const;
char currentCharacter() const;
void advance();
bool atEnd() const;
void check() const;
// TODO: make protected again
//protected:
mutable std::stringstream m_stream;
std::vector<Delimiter> m_delimiters;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -1,27 +1,24 @@
#ifndef __PLASP__PDDL__IDENTIFIER_H #ifndef __PLASP__UTILS__STREAM_COORDINATE_H
#define __PLASP__PDDL__IDENTIFIER_H #define __PLASP__UTILS__STREAM_COORDINATE_H
#include <cctype> #include <string>
namespace plasp namespace plasp
{ {
namespace pddl namespace utils
{ {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Identifier // StreamCoordinate
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
const auto isIdentifier = struct StreamCoordinate
[](const auto character)
{ {
return character != '?' std::string sectionName;
&& character != '(' size_t row;
&& character != ')' size_t column;
&& character != ';'
&& std::isgraph(character);
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -5,10 +5,8 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Type.h> #include <plasp/pddl/expressions/Type.h>
#include <plasp/utils/IO.h> #include <plasp/utils/IO.h>
#include <plasp/utils/ParserException.h>
namespace plasp namespace plasp
{ {
@ -23,31 +21,33 @@ namespace pddl
void Action::parseDeclaration(Context &context, Domain &domain) void Action::parseDeclaration(Context &context, Domain &domain)
{ {
auto &parser = context.parser;
auto action = std::make_unique<Action>(Action()); auto action = std::make_unique<Action>(Action());
action->m_name = context.parser.parseIdentifier(isIdentifier); action->m_name = parser.parseIdentifier();
context.parser.expect<std::string>(":parameters"); parser.expect<std::string>(":parameters");
context.parser.expect<std::string>("("); parser.expect<std::string>("(");
ExpressionContext expressionContext(domain, action->m_parameters); ExpressionContext expressionContext(domain, action->m_parameters);
// Read parameters // Read parameters
expressions::Variable::parseTypedDeclarations(context, expressionContext); expressions::Variable::parseTypedDeclarations(context, expressionContext);
context.parser.expect<std::string>(")"); parser.expect<std::string>(")");
// Parse preconditions and effects // Parse preconditions and effects
while (context.parser.currentCharacter() != ')') while (!parser.testAndReturn(')'))
{ {
context.parser.expect<std::string>(":"); parser.expect<std::string>(":");
if (context.parser.probeIdentifier("precondition", isIdentifier)) if (parser.testIdentifierAndSkip("precondition"))
action->m_precondition = parsePreconditionExpression(context, expressionContext); action->m_precondition = parsePreconditionExpression(context, expressionContext);
else if (context.parser.probeIdentifier("effect", isIdentifier)) else if (parser.testIdentifierAndSkip("effect"))
action->m_effect = parseEffectExpression(context, expressionContext); action->m_effect = parseEffectExpression(context, expressionContext);
context.parser.skipWhiteSpace(); parser.skipWhiteSpace();
} }
// Store new action // Store new action

View File

@ -44,7 +44,7 @@ Description Description::fromStream(std::istream &istream)
{ {
Description description; Description description;
description.m_context.parser.readStream("std::cin", istream); description.m_context.parser.read("std::cin", istream);
description.parse(); description.parse();
return description; return description;
@ -56,7 +56,7 @@ Description Description::fromFile(const std::string &path)
{ {
Description description; Description description;
description.m_context.parser.readFile(path); description.m_context.parser.read(path);
description.parse(); description.parse();
return description; return description;
@ -73,7 +73,7 @@ Description Description::fromFiles(const std::vector<std::string> &paths)
std::for_each(paths.cbegin(), paths.cend(), std::for_each(paths.cbegin(), paths.cend(),
[&](const auto &path) [&](const auto &path)
{ {
description.m_context.parser.readFile(path); description.m_context.parser.read(path);
}); });
description.parse(); description.parse();
@ -126,7 +126,6 @@ void Description::parse()
{ {
auto &parser = m_context.parser; auto &parser = m_context.parser;
parser.setCaseSensitive(false);
parser.removeComments(";", "\n", false); parser.removeComments(";", "\n", false);
// First, determine the locations of domain and problem // First, determine the locations of domain and problem
@ -155,7 +154,7 @@ void Description::findSections()
parser.skipWhiteSpace(); parser.skipWhiteSpace();
while (!parser.atEndOfStream()) while (!parser.atEnd())
{ {
const auto position = parser.position(); const auto position = parser.position();
@ -163,20 +162,20 @@ void Description::findSections()
parser.expect<std::string>("define"); parser.expect<std::string>("define");
parser.expect<std::string>("("); parser.expect<std::string>("(");
if (parser.probe<std::string>("domain")) if (parser.testAndSkip<std::string>("domain"))
{ {
if (m_domainPosition != -1) if (m_domainPosition != -1)
throw utils::ParserException(parser, "PDDL description may not contain two domains"); throw utils::ParserException(parser.coordinate(), "PDDL description may not contain two domains");
m_domainPosition = position; m_domainPosition = position;
parser.seek(position); parser.seek(position);
m_domain->findSections(); m_domain->findSections();
} }
else if (m_context.parser.probe<std::string>("problem")) else if (m_context.parser.testAndSkip<std::string>("problem"))
{ {
if (m_problemPosition != -1) if (m_problemPosition != -1)
throw utils::ParserException(parser, "PDDL description may currently not contain two problems"); throw utils::ParserException(parser.coordinate(), "PDDL description may currently not contain two problems");
m_problem = std::make_unique<Problem>(Problem(m_context, *m_domain)); m_problem = std::make_unique<Problem>(Problem(m_context, *m_domain));
@ -188,7 +187,7 @@ void Description::findSections()
else else
{ {
const auto sectionIdentifier = parser.parse<std::string>(); const auto sectionIdentifier = parser.parse<std::string>();
throw utils::ParserException(parser, "unknown PDDL section “" + sectionIdentifier + ""); throw utils::ParserException(parser.coordinate(), "unknown PDDL section “" + sectionIdentifier + "");
} }
m_context.parser.skipWhiteSpace(); m_context.parser.skipWhiteSpace();

View File

@ -3,7 +3,6 @@
#include <algorithm> #include <algorithm>
#include <plasp/pddl/ConsistencyException.h> #include <plasp/pddl/ConsistencyException.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/pddl/expressions/PredicateDeclaration.h> #include <plasp/pddl/expressions/PredicateDeclaration.h>
@ -43,7 +42,7 @@ void Domain::findSections()
parser.expect<std::string>("("); parser.expect<std::string>("(");
parser.expect<std::string>("domain"); parser.expect<std::string>("domain");
m_name = m_context.parser.parseIdentifier(isIdentifier); m_name = m_context.parser.parseIdentifier();
parser.expect<std::string>(")"); parser.expect<std::string>(")");
@ -53,7 +52,7 @@ void Domain::findSections()
if (unique && sectionPosition != -1) if (unique && sectionPosition != -1)
{ {
parser.seek(value); parser.seek(value);
throw utils::ParserException(parser, "only one “:" + sectionName + "” section allowed"); throw utils::ParserException(parser.coordinate(), "only one “:" + sectionName + "” section allowed");
} }
sectionPosition = value; sectionPosition = value;
@ -72,38 +71,38 @@ void Domain::findSections()
const auto sectionIdentifierPosition = parser.position(); const auto sectionIdentifierPosition = parser.position();
// Save the parser position of the individual sections for later parsing // Save the parser position of the individual sections for later parsing
if (parser.probeIdentifier("requirements", isIdentifier)) if (parser.testIdentifierAndSkip("requirements"))
setSectionPosition("requirements", m_requirementsPosition, position, true); setSectionPosition("requirements", m_requirementsPosition, position, true);
else if (parser.probeIdentifier("types", isIdentifier)) else if (parser.testIdentifierAndSkip("types"))
setSectionPosition("types", m_typesPosition, position, true); setSectionPosition("types", m_typesPosition, position, true);
else if (parser.probeIdentifier("constants", isIdentifier)) else if (parser.testIdentifierAndSkip("constants"))
setSectionPosition("constants", m_constantsPosition, position, true); setSectionPosition("constants", m_constantsPosition, position, true);
else if (parser.probeIdentifier("predicates", isIdentifier)) else if (parser.testIdentifierAndSkip("predicates"))
setSectionPosition("predicates", m_predicatesPosition, position, true); setSectionPosition("predicates", m_predicatesPosition, position, true);
else if (parser.probeIdentifier("action", isIdentifier)) else if (parser.testIdentifierAndSkip("action"))
{ {
m_actionPositions.emplace_back(-1); m_actionPositions.emplace_back(-1);
setSectionPosition("action", m_actionPositions.back(), position); setSectionPosition("action", m_actionPositions.back(), position);
} }
else if (parser.probeIdentifier("functions", isIdentifier) else if (parser.testIdentifierAndSkip("functions")
|| parser.probeIdentifier("constraints", isIdentifier) || parser.testIdentifierAndSkip("constraints")
|| parser.probeIdentifier("durative-action", isIdentifier) || parser.testIdentifierAndSkip("durative-action")
|| parser.probeIdentifier("derived", isIdentifier)) || parser.testIdentifierAndSkip("derived"))
{ {
parser.seek(sectionIdentifierPosition); parser.seek(sectionIdentifierPosition);
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); const auto sectionIdentifier = parser.parseIdentifier();
m_context.logger.logWarning(parser, "section type “" + sectionIdentifier + "” currently unsupported"); m_context.logger.logWarning(parser.coordinate(), "section type “" + sectionIdentifier + "” currently unsupported");
parser.seek(sectionIdentifierPosition); parser.seek(sectionIdentifierPosition);
} }
else else
{ {
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); const auto sectionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
throw utils::ParserException(m_context.parser, "unknown domain section “" + sectionIdentifier + ""); throw utils::ParserException(parser.coordinate(), "unknown domain section “" + sectionIdentifier + "");
} }
// Skip section for now and parse it later // Skip section for now and parse it later
@ -340,7 +339,7 @@ void Domain::parseTypeSection()
while (parser.currentCharacter() != ')') while (parser.currentCharacter() != ')')
{ {
if (parser.currentCharacter() == '(') if (parser.currentCharacter() == '(')
throw utils::ParserException(parser, "only primitive types are allowed in type section"); throw utils::ParserException(parser.coordinate(), "only primitive types are allowed in type section");
expressions::PrimitiveType::parseTypedDeclaration(m_context, *this); expressions::PrimitiveType::parseTypedDeclaration(m_context, *this);

View File

@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
#include <plasp/pddl/expressions/And.h> #include <plasp/pddl/expressions/And.h>
#include <plasp/pddl/expressions/Imply.h> #include <plasp/pddl/expressions/Imply.h>
@ -49,12 +48,12 @@ ExpressionPointer parsePreconditionExpression(Context &context,
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("forall", isIdentifier) if (parser.testIdentifierAndSkip("forall")
|| parser.probeIdentifier("preference", isIdentifier)) || parser.testIdentifierAndSkip("preference"))
{ {
// TODO: refactor // TODO: refactor
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
@ -89,32 +88,32 @@ ExpressionPointer parseExpression(Context &context, ExpressionContext &expressio
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("exists", isIdentifier) if (parser.testIdentifierAndSkip("exists")
|| parser.probeIdentifier("forall", isIdentifier) || parser.testIdentifierAndSkip("forall")
|| parser.probeIdentifier("-", isIdentifier) || parser.testIdentifierAndSkip("-")
|| parser.probeIdentifier("=", isIdentifier) || parser.testIdentifierAndSkip("=")
|| parser.probeIdentifier("*", isIdentifier) || parser.testIdentifierAndSkip("*")
|| parser.probeIdentifier("+", isIdentifier) || parser.testIdentifierAndSkip("+")
|| parser.probeIdentifier("-", isIdentifier) || parser.testIdentifierAndSkip("-")
|| parser.probeIdentifier("/", isIdentifier) || parser.testIdentifierAndSkip("/")
|| parser.probeIdentifier(">", isIdentifier) || parser.testIdentifierAndSkip(">")
|| parser.probeIdentifier("<", isIdentifier) || parser.testIdentifierAndSkip("<")
|| parser.probeIdentifier("=", isIdentifier) || parser.testIdentifierAndSkip("=")
|| parser.probeIdentifier(">=", isIdentifier) || parser.testIdentifierAndSkip(">=")
|| parser.probeIdentifier("<=", isIdentifier)) || parser.testIdentifierAndSkip("<="))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
} }
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
throw utils::ParserException(context.parser, "expression type “" + expressionIdentifier + "” unknown or not allowed in this context"); throw utils::ParserException(parser.coordinate(), "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -134,11 +133,11 @@ ExpressionPointer parseEffectExpression(Context &context, ExpressionContext &exp
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("forall", isIdentifier) if (parser.testIdentifierAndSkip("forall")
|| parser.probeIdentifier("when", isIdentifier)) || parser.testIdentifierAndSkip("when"))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
@ -168,37 +167,39 @@ ExpressionPointer parseEffectBodyExpression(Context &context, ExpressionContext
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("=", isIdentifier) if (parser.testIdentifierAndSkip("=")
|| parser.probeIdentifier("assign", isIdentifier) || parser.testIdentifierAndSkip("assign")
|| parser.probeIdentifier("scale-up", isIdentifier) || parser.testIdentifierAndSkip("scale-up")
|| parser.probeIdentifier("scale-down", isIdentifier) || parser.testIdentifierAndSkip("scale-down")
|| parser.probeIdentifier("increase", isIdentifier) || parser.testIdentifierAndSkip("increase")
|| parser.probeIdentifier("decrease", isIdentifier)) || parser.testIdentifierAndSkip("decrease"))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
} }
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
throw utils::ParserException(context.parser, "expression type “" + expressionIdentifier + "” unknown or not allowed in this context"); throw utils::ParserException(parser.coordinate(), "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
ExpressionPointer parsePredicate(Context &context, ExpressionContext &expressionContext) ExpressionPointer parsePredicate(Context &context, ExpressionContext &expressionContext)
{ {
auto &parser = context.parser;
ExpressionPointer expression; ExpressionPointer expression;
if ((expression = expressions::Predicate::parse(context, expressionContext))) if ((expression = expressions::Predicate::parse(context, expressionContext)))
return expression; return expression;
throw utils::ParserException(context.parser, "expected predicate"); throw utils::ParserException(parser.coordinate(), "expected predicate");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -229,15 +230,15 @@ ExpressionPointer parseAtomicFormula(Context &context, ExpressionContext &expres
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(")) if (!parser.testAndSkip<std::string>("("))
return nullptr; return nullptr;
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("=", isIdentifier)) if (parser.testIdentifierAndSkip("="))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);

View File

@ -2,7 +2,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
#include <plasp/pddl/Problem.h> #include <plasp/pddl/Problem.h>
#include <plasp/pddl/expressions/At.h> #include <plasp/pddl/expressions/At.h>
@ -46,20 +45,20 @@ std::unique_ptr<InitialState> InitialState::parseDeclaration(Context &context,
const auto expressionIdentifierPosition = parser.position(); const auto expressionIdentifierPosition = parser.position();
if (parser.probeIdentifier("=", isIdentifier)) if (parser.testIdentifierAndSkip("="))
{ {
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
return expressions::Unsupported::parse(context); return expressions::Unsupported::parse(context);
} }
parser.seek(expressionIdentifierPosition); parser.seek(expressionIdentifierPosition);
const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); const auto expressionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
throw utils::ParserException(parser, "expression type “" + expressionIdentifier + "” unknown or not allowed in this context"); throw utils::ParserException(parser.coordinate(), "expression type “" + expressionIdentifier + "” unknown or not allowed in this context");
}; };
parser.skipWhiteSpace(); parser.skipWhiteSpace();

View File

@ -4,7 +4,6 @@
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/utils/IO.h> #include <plasp/utils/IO.h>
@ -43,7 +42,7 @@ void Problem::findSections()
parser.expect<std::string>("("); parser.expect<std::string>("(");
parser.expect<std::string>("problem"); parser.expect<std::string>("problem");
m_name = parser.parseIdentifier(isIdentifier); m_name = parser.parseIdentifier();
parser.expect<std::string>(")"); parser.expect<std::string>(")");
@ -53,7 +52,7 @@ void Problem::findSections()
if (unique && sectionPosition != -1) if (unique && sectionPosition != -1)
{ {
parser.seek(value); parser.seek(value);
throw utils::ParserException(parser, "only one “:" + sectionName + "” section allowed"); throw utils::ParserException(parser.coordinate(), "only one “:" + sectionName + "” section allowed");
} }
sectionPosition = value; sectionPosition = value;
@ -71,34 +70,34 @@ void Problem::findSections()
const auto sectionIdentifierPosition = parser.position(); const auto sectionIdentifierPosition = parser.position();
// TODO: check order of the sections // TODO: check order of the sections
if (parser.probeIdentifier("domain", isIdentifier)) if (parser.testIdentifierAndSkip("domain"))
setSectionPosition("domain", m_domainPosition, position, true); setSectionPosition("domain", m_domainPosition, position, true);
else if (parser.probeIdentifier("requirements", isIdentifier)) else if (parser.testIdentifierAndSkip("requirements"))
setSectionPosition("requirements", m_requirementsPosition, position, true); setSectionPosition("requirements", m_requirementsPosition, position, true);
else if (parser.probeIdentifier("objects", isIdentifier)) else if (parser.testIdentifierAndSkip("objects"))
setSectionPosition("objects", m_objectsPosition, position, true); setSectionPosition("objects", m_objectsPosition, position, true);
else if (parser.probeIdentifier("init", isIdentifier)) else if (parser.testIdentifierAndSkip("init"))
setSectionPosition("init", m_initialStatePosition, position, true); setSectionPosition("init", m_initialStatePosition, position, true);
else if (parser.probeIdentifier("goal", isIdentifier)) else if (parser.testIdentifierAndSkip("goal"))
setSectionPosition("goal", m_goalPosition, position, true); setSectionPosition("goal", m_goalPosition, position, true);
else if (parser.probeIdentifier("constraints", isIdentifier) else if (parser.testIdentifierAndSkip("constraints")
|| parser.probeIdentifier("metric", isIdentifier) || parser.testIdentifierAndSkip("metric")
|| parser.probeIdentifier("length", isIdentifier)) || parser.testIdentifierAndSkip("length"))
{ {
parser.seek(sectionIdentifierPosition); parser.seek(sectionIdentifierPosition);
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); const auto sectionIdentifier = parser.parseIdentifier();
m_context.logger.logWarning(parser, "section type “" + sectionIdentifier + "” currently unsupported"); m_context.logger.logWarning(parser.coordinate(), "section type “" + sectionIdentifier + "” currently unsupported");
parser.seek(sectionIdentifierPosition); parser.seek(sectionIdentifierPosition);
} }
else else
{ {
const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); const auto sectionIdentifier = parser.parseIdentifier();
parser.seek(position); parser.seek(position);
throw utils::ParserException(m_context.parser, "unknown problem section “" + sectionIdentifier + ""); throw utils::ParserException(parser.coordinate(), "unknown problem section “" + sectionIdentifier + "");
} }
// Skip section for now and parse it later // Skip section for now and parse it later
@ -201,10 +200,10 @@ void Problem::parseDomainSection()
parser.skipWhiteSpace(); parser.skipWhiteSpace();
const auto domainName = parser.parseIdentifier(isIdentifier); const auto domainName = parser.parseIdentifier();
if (m_domain.name() != domainName) if (m_domain.name() != domainName)
throw utils::ParserException(parser, "domains do not match (“" + m_domain.name() + "” and “" + domainName + "”)"); throw utils::ParserException(parser.coordinate(), "domains do not match (“" + m_domain.name() + "” and “" + domainName + "”)");
parser.expect<std::string>(")"); parser.expect<std::string>(")");
} }

View File

@ -4,7 +4,6 @@
#include <boost/assign.hpp> #include <boost/assign.hpp>
#include <boost/bimap.hpp> #include <boost/bimap.hpp>
#include <plasp/pddl/Identifier.h>
#include <plasp/utils/IO.h> #include <plasp/utils/IO.h>
#include <plasp/utils/ParserException.h> #include <plasp/utils/ParserException.h>
@ -84,17 +83,19 @@ Requirement::Requirement(Requirement::Type type)
Requirement Requirement::parse(Context &context) Requirement Requirement::parse(Context &context)
{ {
const auto requirementName = context.parser.parseIdentifier(isIdentifier); auto &parser = context.parser;
const auto requirementName = parser.parseIdentifier();
const auto match = requirementTypesToPDDL.right.find(requirementName); const auto match = requirementTypesToPDDL.right.find(requirementName);
if (match == requirementTypesToPDDL.right.end()) if (match == requirementTypesToPDDL.right.end())
throw utils::ParserException(context.parser, "unknown PDDL requirement “" + requirementName + ""); throw utils::ParserException(parser.coordinate(), "unknown PDDL requirement “" + requirementName + "");
const auto requirementType = match->second; const auto requirementType = match->second;
if (requirementType == Requirement::Type::GoalUtilities) if (requirementType == Requirement::Type::GoalUtilities)
context.logger.logWarning(context.parser, "requirement “goal-utilities” is not part of the PDDL 3.1 specification"); context.logger.logWarning(parser.coordinate(), "requirement “goal-utilities” is not part of the PDDL 3.1 specification");
return Requirement(match->second); return Requirement(match->second);
} }

View File

@ -37,7 +37,7 @@ ConstantPointer Constant::parseDeclaration(Context &context)
auto constant = std::make_unique<Constant>(Constant()); auto constant = std::make_unique<Constant>(Constant());
constant->m_name = context.parser.parseIdentifier(isIdentifier); constant->m_name = context.parser.parseIdentifier();
BOOST_ASSERT(constant->m_name != "-"); BOOST_ASSERT(constant->m_name != "-");
@ -71,7 +71,7 @@ void Constant::parseTypedDeclaration(Context &context, Domain &domain, Constants
context.parser.skipWhiteSpace(); context.parser.skipWhiteSpace();
// Check for typing information // Check for typing information
if (!context.parser.probe('-')) if (!context.parser.testAndSkip<char>('-'))
return; return;
// If existing, parse and store parent type // If existing, parse and store parent type
@ -113,7 +113,7 @@ void Constant::parseTypedDeclarations(Context &context, Domain &domain)
domain.checkRequirement(Requirement::Type::Typing); domain.checkRequirement(Requirement::Type::Typing);
// If no types are given, check that typing is not a requirement // If no types are given, check that typing is not a requirement
else if (domain.hasRequirement(Requirement::Type::Typing)) else if (domain.hasRequirement(Requirement::Type::Typing))
throw utils::ParserException(parser, "constant has undeclared type"); throw utils::ParserException(parser.coordinate(), "constant has undeclared type");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -140,32 +140,36 @@ void Constant::parseTypedDeclarations(Context &context, Problem &problem)
problem.checkRequirement(Requirement::Type::Typing); problem.checkRequirement(Requirement::Type::Typing);
// If no types are given, check that typing is not a requirement // If no types are given, check that typing is not a requirement
else if (problem.hasRequirement(Requirement::Type::Typing)) else if (problem.hasRequirement(Requirement::Type::Typing))
throw utils::ParserException(context.parser, "constant has undeclared type"); throw utils::ParserException(parser.coordinate(), "constant has undeclared type");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Constant *Constant::parseAndFind(Context &context, const Domain &domain) Constant *Constant::parseAndFind(Context &context, const Domain &domain)
{ {
context.parser.skipWhiteSpace(); auto &parser = context.parser;
const auto constantName = context.parser.parseIdentifier(isIdentifier); parser.skipWhiteSpace();
const auto constantName = parser.parseIdentifier();
auto *constant = parseAndFind(constantName, domain.constants()); auto *constant = parseAndFind(constantName, domain.constants());
if (constant != nullptr) if (constant != nullptr)
return constant; return constant;
throw utils::ParserException(context.parser, "constant “" + constantName + "” used but never declared"); throw utils::ParserException(parser.coordinate(), "constant “" + constantName + "” used but never declared");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Constant *Constant::parseAndFind(Context &context, const Problem &problem) Constant *Constant::parseAndFind(Context &context, const Problem &problem)
{ {
context.parser.skipWhiteSpace(); auto &parser = context.parser;
const auto constantName = context.parser.parseIdentifier(isIdentifier); parser.skipWhiteSpace();
const auto constantName = parser.parseIdentifier();
auto *constant = parseAndFind(constantName, problem.domain().constants()); auto *constant = parseAndFind(constantName, problem.domain().constants());
@ -177,7 +181,7 @@ Constant *Constant::parseAndFind(Context &context, const Problem &problem)
if (constant) if (constant)
return constant; return constant;
throw utils::ParserException(context.parser, "constant “" + constantName + "” used but never declared"); throw utils::ParserException(parser.coordinate(), "constant “" + constantName + "” used but never declared");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -13,6 +13,7 @@ namespace expressions
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: make static character string literal
const std::string Imply::Identifier = "imply"; const std::string Imply::Identifier = "imply";
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/Problem.h> #include <plasp/pddl/Problem.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/pddl/expressions/Variable.h> #include <plasp/pddl/expressions/Variable.h>
@ -34,13 +33,13 @@ PredicatePointer Predicate::parse(Context &context, ExpressionContext &expressio
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(")) if (!parser.testAndSkip<std::string>("("))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;
} }
const auto predicateName = parser.parseIdentifier(isIdentifier); const auto predicateName = parser.parseIdentifier();
const auto &predicates = expressionContext.domain.predicates(); const auto &predicates = expressionContext.domain.predicates();
const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(), const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(),
@ -97,13 +96,13 @@ PredicatePointer Predicate::parse(Context &context, const Problem &problem)
const auto position = parser.position(); const auto position = parser.position();
if (!parser.probe<std::string>("(")) if (!parser.testAndSkip<std::string>("("))
{ {
parser.seek(position); parser.seek(position);
return nullptr; return nullptr;
} }
const auto predicateName = parser.parseIdentifier(isIdentifier); const auto predicateName = parser.parseIdentifier();
const auto &predicates = problem.domain().predicates(); const auto &predicates = problem.domain().predicates();
const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(), const auto matchingPredicate = std::find_if(predicates.cbegin(), predicates.cend(),
@ -122,12 +121,12 @@ PredicatePointer Predicate::parse(Context &context, const Problem &problem)
predicate->m_name = predicateName; predicate->m_name = predicateName;
context.parser.skipWhiteSpace(); parser.skipWhiteSpace();
while (context.parser.currentCharacter() != ')') while (parser.currentCharacter() != ')')
{ {
if (context.parser.currentCharacter() == '?') if (parser.currentCharacter() == '?')
throw utils::ParserException(context.parser, "variables not allowed in this context"); throw utils::ParserException(parser.coordinate(), "variables not allowed in this context");
// Parse objects and constants // Parse objects and constants
const auto *constant = Constant::parseAndFind(context, problem); const auto *constant = Constant::parseAndFind(context, problem);

View File

@ -3,7 +3,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Constant.h> #include <plasp/pddl/expressions/Constant.h>
#include <plasp/pddl/expressions/Variable.h> #include <plasp/pddl/expressions/Variable.h>
@ -33,7 +32,7 @@ void PredicateDeclaration::parse(Context &context, Domain &domain)
auto predicate = std::make_unique<PredicateDeclaration>(PredicateDeclaration()); auto predicate = std::make_unique<PredicateDeclaration>(PredicateDeclaration());
predicate->m_name = context.parser.parseIdentifier(isIdentifier); predicate->m_name = context.parser.parseIdentifier();
// Flag predicate as correctly declared in the types section // Flag predicate as correctly declared in the types section
predicate->setDeclared(); predicate->setDeclared();

View File

@ -43,7 +43,7 @@ void PrimitiveType::parseDeclaration(Context &context, Domain &domain)
context.parser.skipWhiteSpace(); context.parser.skipWhiteSpace();
const auto typeName = context.parser.parseIdentifier(isIdentifier); const auto typeName = context.parser.parseIdentifier();
const auto match = std::find_if(types.cbegin(), types.cend(), const auto match = std::find_if(types.cbegin(), types.cend(),
[&](const auto &primitiveType) [&](const auto &primitiveType)
@ -76,7 +76,7 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
context.parser.skipWhiteSpace(); context.parser.skipWhiteSpace();
// Check for type inheritance // Check for type inheritance
if (!context.parser.probe('-')) if (!context.parser.testAndSkip<char>('-'))
return; return;
domain.checkRequirement(Requirement::Type::Typing); domain.checkRequirement(Requirement::Type::Typing);
@ -102,14 +102,16 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain)
PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain) PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain)
{ {
auto &parser = context.parser;
auto &types = domain.types(); auto &types = domain.types();
context.parser.skipWhiteSpace(); parser.skipWhiteSpace();
const auto typeName = context.parser.parseIdentifier(isIdentifier); const auto typeName = parser.parseIdentifier();
if (typeName.empty()) if (typeName.empty())
throw utils::ParserException(context.parser, "no type supplied"); throw utils::ParserException(parser.coordinate(), "no type supplied");
const auto match = std::find_if(types.cbegin(), types.cend(), const auto match = std::find_if(types.cbegin(), types.cend(),
[&](const auto &primitiveType) [&](const auto &primitiveType)
@ -122,11 +124,11 @@ PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain)
// Only "object" is allowed as an implicit type // Only "object" is allowed as an implicit type
if (typeName == "object" || typeName == "objects") if (typeName == "object" || typeName == "objects")
{ {
context.logger.logWarning(context.parser, "primitive type “" + typeName + "” should be declared"); context.logger.logWarning(parser.coordinate(), "primitive type “" + typeName + "” should be declared");
types.emplace_back(std::make_unique<expressions::PrimitiveType>(typeName)); types.emplace_back(std::make_unique<expressions::PrimitiveType>(typeName));
} }
else else
throw utils::ParserException(context.parser, "type “" + typeName + "” used but never declared"); throw utils::ParserException(parser.coordinate(), "type “" + typeName + "” used but never declared");
return types.back().get(); return types.back().get();
} }

View File

@ -1,6 +1,5 @@
#include <plasp/pddl/expressions/Unsupported.h> #include <plasp/pddl/expressions/Unsupported.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/IO.h> #include <plasp/pddl/IO.h>
namespace plasp namespace plasp
@ -24,9 +23,9 @@ UnsupportedPointer Unsupported::parse(Context &context)
parser.expect<std::string>("("); parser.expect<std::string>("(");
expression->m_type = parser.parseIdentifier(isIdentifier); expression->m_type = parser.parseIdentifier();
context.logger.logWarning(context.parser, "expression type “" + expression->m_type + "” currently unsupported in this context"); context.logger.logWarning(parser.coordinate(), "expression type “" + expression->m_type + "” currently unsupported in this context");
skipSection(parser); skipSection(parser);

View File

@ -7,7 +7,6 @@
#include <plasp/pddl/Context.h> #include <plasp/pddl/Context.h>
#include <plasp/pddl/Domain.h> #include <plasp/pddl/Domain.h>
#include <plasp/pddl/ExpressionContext.h> #include <plasp/pddl/ExpressionContext.h>
#include <plasp/pddl/Identifier.h>
#include <plasp/pddl/expressions/Either.h> #include <plasp/pddl/expressions/Either.h>
#include <plasp/pddl/expressions/PrimitiveType.h> #include <plasp/pddl/expressions/PrimitiveType.h>
#include <plasp/pddl/expressions/Type.h> #include <plasp/pddl/expressions/Type.h>
@ -36,13 +35,15 @@ Variable::Variable()
void Variable::parseDeclaration(Context &context, Variables &parameters) void Variable::parseDeclaration(Context &context, Variables &parameters)
{ {
context.parser.skipWhiteSpace(); auto &parser = context.parser;
context.parser.expect<std::string>("?"); parser.skipWhiteSpace();
parser.expect<std::string>("?");
auto variable = std::make_unique<Variable>(Variable()); auto variable = std::make_unique<Variable>(Variable());
variable->m_name = context.parser.parseIdentifier(isIdentifier); variable->m_name = parser.parseIdentifier();
// Check if variable of that name already exists in the current scope // Check if variable of that name already exists in the current scope
const auto match = std::find_if(parameters.cbegin(), parameters.cend(), const auto match = std::find_if(parameters.cbegin(), parameters.cend(),
@ -52,7 +53,7 @@ void Variable::parseDeclaration(Context &context, Variables &parameters)
}); });
if (match != parameters.cend()) if (match != parameters.cend())
throw utils::ParserException(context.parser, "variable “" + variable->m_name + "” already declared in this scope"); throw utils::ParserException(parser.coordinate(), "variable “" + variable->m_name + "” already declared in this scope");
// Flag variable for potentially upcoming type declaration // Flag variable for potentially upcoming type declaration
variable->setDirty(); variable->setDirty();
@ -75,7 +76,7 @@ void Variable::parseTypedDeclaration(Context &context, ExpressionContext &expres
parser.skipWhiteSpace(); parser.skipWhiteSpace();
// Check if the variable has a type declaration // Check if the variable has a type declaration
if (!parser.probe('-')) if (!parser.testAndSkip<char>('-'))
return; return;
const auto setType = const auto setType =
@ -132,18 +133,20 @@ void Variable::parseTypedDeclarations(Context &context, ExpressionContext &expre
expressionContext.checkRequirement(Requirement::Type::Typing); expressionContext.checkRequirement(Requirement::Type::Typing);
// If no types are given, check that typing is not a requirement // If no types are given, check that typing is not a requirement
else if (expressionContext.hasRequirement(Requirement::Type::Typing)) else if (expressionContext.hasRequirement(Requirement::Type::Typing))
throw utils::ParserException(parser, "variable has undeclared type"); throw utils::ParserException(parser.coordinate(), "variable has undeclared type");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
const Variable *Variable::parseAndFind(Context &context, const ExpressionContext &expressionContext) const Variable *Variable::parseAndFind(Context &context, const ExpressionContext &expressionContext)
{ {
context.parser.skipWhiteSpace(); auto &parser = context.parser;
context.parser.expect<std::string>("?"); parser.skipWhiteSpace();
const auto variableName = context.parser.parseIdentifier(isIdentifier); parser.expect<std::string>("?");
const auto variableName = parser.parseIdentifier();
const auto &variables = expressionContext.parameters; const auto &variables = expressionContext.parameters;
@ -154,7 +157,7 @@ const Variable *Variable::parseAndFind(Context &context, const ExpressionContext
}); });
if (match == variables.cend()) if (match == variables.cend())
throw utils::ParserException(context.parser, "parameter “" + variableName + "” used but never declared"); throw utils::ParserException(parser.coordinate(), "parameter “" + variableName + "” used but never declared");
return match->get(); return match->get();
} }

View File

@ -31,7 +31,7 @@ AssignedVariable::AssignedVariable(const Variable &variable, const Value &value)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
AssignedVariable AssignedVariable::fromSAS(utils::Parser &parser, const Variables &variables) AssignedVariable AssignedVariable::fromSAS(utils::Parser<> &parser, const Variables &variables)
{ {
AssignedVariable assignedVariable; AssignedVariable assignedVariable;
@ -43,7 +43,7 @@ AssignedVariable AssignedVariable::fromSAS(utils::Parser &parser, const Variable
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
AssignedVariable AssignedVariable::fromSAS(utils::Parser &parser, const Variable &variable) AssignedVariable AssignedVariable::fromSAS(utils::Parser<> &parser, const Variable &variable)
{ {
AssignedVariable assignedVariable; AssignedVariable assignedVariable;

View File

@ -23,7 +23,7 @@ AxiomRule::AxiomRule(AxiomRule::Conditions conditions, AxiomRule::Condition post
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
AxiomRule AxiomRule::fromSAS(utils::Parser &parser, const Variables &variables) AxiomRule AxiomRule::fromSAS(utils::Parser<> &parser, const Variables &variables)
{ {
parser.expect<std::string>("begin_rule"); parser.expect<std::string>("begin_rule");

View File

@ -28,10 +28,8 @@ Description::Description()
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Description Description::fromParser(utils::Parser &&parser) Description Description::fromParser(utils::Parser<> &&parser)
{ {
parser.setCaseSensitive(true);
Description description; Description description;
description.parseContent(parser); description.parseContent(parser);
@ -42,8 +40,8 @@ Description Description::fromParser(utils::Parser &&parser)
Description Description::fromStream(std::istream &istream) Description Description::fromStream(std::istream &istream)
{ {
utils::Parser parser; utils::Parser<> parser;
parser.readStream("std::cin", istream); parser.read("std::cin", istream);
Description description; Description description;
description.parseContent(parser); description.parseContent(parser);
@ -58,8 +56,8 @@ Description Description::fromFile(const boost::filesystem::path &path)
if (!boost::filesystem::is_regular_file(path)) if (!boost::filesystem::is_regular_file(path))
throw std::runtime_error("File does not exist: “" + path.string() + ""); throw std::runtime_error("File does not exist: “" + path.string() + "");
utils::Parser parser; utils::Parser<> parser;
parser.readFile(path); parser.read(path);
Description description; Description description;
description.parseContent(parser); description.parseContent(parser);
@ -155,7 +153,7 @@ bool Description::usesConditionalEffects() const
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseContent(utils::Parser &parser) void Description::parseContent(utils::Parser<> &parser)
{ {
parseVersionSection(parser); parseVersionSection(parser);
parseMetricSection(parser); parseMetricSection(parser);
@ -168,27 +166,27 @@ void Description::parseContent(utils::Parser &parser)
parser.skipWhiteSpace(); parser.skipWhiteSpace();
if (!parser.atEndOfStream()) if (!parser.atEnd())
throw utils::ParserException(parser, "expected end of SAS description (perhaps, input contains two SAS descriptions?)"); throw utils::ParserException(parser.coordinate(), "expected end of SAS description (perhaps, input contains two SAS descriptions?)");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseVersionSection(utils::Parser &parser) const void Description::parseVersionSection(utils::Parser<> &parser) const
{ {
parser.expect<std::string>("begin_version"); parser.expect<std::string>("begin_version");
const auto formatVersion = parser.parse<size_t>(); const auto formatVersion = parser.parse<size_t>();
if (formatVersion != 3) if (formatVersion != 3)
throw utils::ParserException(parser, "unsupported SAS format version (" + std::to_string(formatVersion) + ")"); throw utils::ParserException(parser.coordinate(), "unsupported SAS format version (" + std::to_string(formatVersion) + ")");
parser.expect<std::string>("end_version"); parser.expect<std::string>("end_version");
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseMetricSection(utils::Parser &parser) void Description::parseMetricSection(utils::Parser<> &parser)
{ {
parser.expect<std::string>("begin_metric"); parser.expect<std::string>("begin_metric");
@ -199,7 +197,7 @@ void Description::parseMetricSection(utils::Parser &parser)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseVariablesSection(utils::Parser &parser) void Description::parseVariablesSection(utils::Parser<> &parser)
{ {
const auto numberOfVariables = parser.parse<size_t>(); const auto numberOfVariables = parser.parse<size_t>();
m_variables.reserve(numberOfVariables); m_variables.reserve(numberOfVariables);
@ -210,7 +208,7 @@ void Description::parseVariablesSection(utils::Parser &parser)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseMutexSection(utils::Parser &parser) void Description::parseMutexSection(utils::Parser<> &parser)
{ {
const auto numberOfMutexGroups = parser.parse<size_t>(); const auto numberOfMutexGroups = parser.parse<size_t>();
m_mutexGroups.reserve(numberOfMutexGroups); m_mutexGroups.reserve(numberOfMutexGroups);
@ -221,21 +219,21 @@ void Description::parseMutexSection(utils::Parser &parser)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseInitialStateSection(utils::Parser &parser) void Description::parseInitialStateSection(utils::Parser<> &parser)
{ {
m_initialState = std::make_unique<InitialState>(InitialState::fromSAS(parser, m_variables)); m_initialState = std::make_unique<InitialState>(InitialState::fromSAS(parser, m_variables));
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseGoalSection(utils::Parser &parser) void Description::parseGoalSection(utils::Parser<> &parser)
{ {
m_goal = std::make_unique<Goal>(Goal::fromSAS(parser, m_variables)); m_goal = std::make_unique<Goal>(Goal::fromSAS(parser, m_variables));
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseOperatorSection(utils::Parser &parser) void Description::parseOperatorSection(utils::Parser<> &parser)
{ {
const auto numberOfOperators = parser.parse<size_t>(); const auto numberOfOperators = parser.parse<size_t>();
m_operators.reserve(numberOfOperators); m_operators.reserve(numberOfOperators);
@ -246,7 +244,7 @@ void Description::parseOperatorSection(utils::Parser &parser)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Description::parseAxiomSection(utils::Parser &parser) void Description::parseAxiomSection(utils::Parser<> &parser)
{ {
const auto numberOfAxiomRules = parser.parse<size_t>(); const auto numberOfAxiomRules = parser.parse<size_t>();
m_axiomRules.reserve(numberOfAxiomRules); m_axiomRules.reserve(numberOfAxiomRules);

View File

@ -23,7 +23,7 @@ Effect::Effect(Conditions conditions, Condition postcondition)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Effect Effect::fromSAS(utils::Parser &parser, const Variables &variables, Conditions &preconditions) Effect Effect::fromSAS(utils::Parser<> &parser, const Variables &variables, Conditions &preconditions)
{ {
Effect::Conditions conditions; Effect::Conditions conditions;

View File

@ -13,7 +13,7 @@ namespace sas
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Goal Goal::fromSAS(utils::Parser &parser, const Variables &variables) Goal Goal::fromSAS(utils::Parser<> &parser, const Variables &variables)
{ {
Goal goal; Goal goal;

View File

@ -11,7 +11,7 @@ namespace sas
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
InitialState InitialState::fromSAS(utils::Parser &parser, const Variables &variables) InitialState InitialState::fromSAS(utils::Parser<> &parser, const Variables &variables)
{ {
InitialState initialState; InitialState initialState;

View File

@ -15,7 +15,7 @@ namespace sas
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MutexGroup MutexGroup::fromSAS(utils::Parser &parser, const Variables &variables) MutexGroup MutexGroup::fromSAS(utils::Parser<> &parser, const Variables &variables)
{ {
MutexGroup mutexGroup; MutexGroup mutexGroup;
@ -29,7 +29,7 @@ MutexGroup MutexGroup::fromSAS(utils::Parser &parser, const Variables &variables
mutexGroup.m_facts.emplace_back(Fact::fromSAS(parser, variables)); mutexGroup.m_facts.emplace_back(Fact::fromSAS(parser, variables));
if (mutexGroup.m_facts[j].value() == Value::None) if (mutexGroup.m_facts[j].value() == Value::None)
throw utils::ParserException(parser, "mutex groups must not contain <none of those> values"); throw utils::ParserException(parser.coordinate(), "mutex groups must not contain <none of those> values");
} }
parser.expect<std::string>("end_mutex_group"); parser.expect<std::string>("end_mutex_group");

View File

@ -17,7 +17,7 @@ namespace sas
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Operator Operator::fromSAS(utils::Parser &parser, const Variables &variables) Operator Operator::fromSAS(utils::Parser<> &parser, const Variables &variables)
{ {
Operator operator_; Operator operator_;

View File

@ -18,7 +18,7 @@ namespace sas
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Predicate Predicate::fromSAS(utils::Parser &parser) Predicate Predicate::fromSAS(utils::Parser<> &parser)
{ {
Predicate predicate; Predicate predicate;
@ -31,11 +31,12 @@ Predicate Predicate::fromSAS(utils::Parser &parser)
while (true) while (true)
{ {
// Parse arguments until reaching newline // Parse arguments until reaching newline
parser.skipWhiteSpace( // TODO: reimplement
/*parser.skipWhiteSpace(
[&](const auto character) [&](const auto character)
{ {
return character != '\n' && std::isspace(character); return character != '\n' && std::isspace(character);
}); });*/
if (parser.currentCharacter() == '\n') if (parser.currentCharacter() == '\n')
break; break;
@ -46,7 +47,7 @@ Predicate Predicate::fromSAS(utils::Parser &parser)
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
throw utils::ParserException(parser, "could not parse operator predicate"); throw utils::ParserException(parser.coordinate(), "could not parse operator predicate");
} }
return predicate; return predicate;

View File

@ -55,7 +55,7 @@ Value Value::negated() const
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Value Value::fromSAS(utils::Parser &parser) Value Value::fromSAS(utils::Parser<> &parser)
{ {
const auto sasSign = parser.parse<std::string>(); const auto sasSign = parser.parse<std::string>();
@ -75,12 +75,12 @@ Value Value::fromSAS(utils::Parser &parser)
else if (sasSign == "NegatedAtom") else if (sasSign == "NegatedAtom")
value.m_sign = Value::Sign::Negative; value.m_sign = Value::Sign::Negative;
else else
throw utils::ParserException(parser, "invalid value sign “" + sasSign + ""); throw utils::ParserException(parser.coordinate(), "invalid value sign “" + sasSign + "");
try try
{ {
parser.skipWhiteSpace(); parser.skipWhiteSpace();
value.m_name = parser.getLine(); value.m_name = parser.parseLine();
// Remove trailing () // Remove trailing ()
if (value.m_name.find("()") != std::string::npos) if (value.m_name.find("()") != std::string::npos)
@ -91,7 +91,7 @@ Value Value::fromSAS(utils::Parser &parser)
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
throw utils::ParserException(parser, std::string("could not parse variable value (") + e.what() + ")"); throw utils::ParserException(parser.coordinate(), std::string("could not parse variable value (") + e.what() + ")");
} }
return value; return value;
@ -99,7 +99,7 @@ Value Value::fromSAS(utils::Parser &parser)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
const Value &Value::referenceFromSAS(utils::Parser &parser, const Variable &variable) const Value &Value::referenceFromSAS(utils::Parser<> &parser, const Variable &variable)
{ {
const auto valueID = parser.parse<int>(); const auto valueID = parser.parse<int>();
@ -107,7 +107,7 @@ const Value &Value::referenceFromSAS(utils::Parser &parser, const Variable &vari
return Value::Any; return Value::Any;
if (valueID < 0 || static_cast<size_t>(valueID) >= variable.values().size()) if (valueID < 0 || static_cast<size_t>(valueID) >= variable.values().size())
throw utils::ParserException(parser, "value index out of range (variable " + variable.name() + ", index " + std::to_string(valueID) + ")"); throw utils::ParserException(parser.coordinate(), "value index out of range (variable " + variable.name() + ", index " + std::to_string(valueID) + ")");
return variable.values()[valueID]; return variable.values()[valueID];
} }

View File

@ -24,7 +24,7 @@ Variable::Variable()
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Variable Variable::fromSAS(utils::Parser &parser) Variable Variable::fromSAS(utils::Parser<> &parser)
{ {
Variable variable; Variable variable;
@ -42,7 +42,7 @@ Variable Variable::fromSAS(utils::Parser &parser)
// <none of those> values are only allowed at the end // <none of those> values are only allowed at the end
if (j < numberOfValues - 1 && variable.m_values[j] == Value::None) if (j < numberOfValues - 1 && variable.m_values[j] == Value::None)
throw utils::ParserException(parser, "<none of those> value must be the last value of a variable"); throw utils::ParserException(parser.coordinate(), "<none of those> value must be the last value of a variable");
} }
parser.expect<std::string>("end_variable"); parser.expect<std::string>("end_variable");
@ -59,12 +59,12 @@ void Variable::printNameAsASPPredicate(utils::LogStream &outputStream) const
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
const Variable &Variable::referenceFromSAS(utils::Parser &parser, const Variables &variables) const Variable &Variable::referenceFromSAS(utils::Parser<> &parser, const Variables &variables)
{ {
const auto variableID = parser.parse<size_t>(); const auto variableID = parser.parse<size_t>();
if (variableID >= variables.size()) if (variableID >= variables.size())
throw utils::ParserException(parser, "variable index out of range (index " + std::to_string(variableID) + ")"); throw utils::ParserException(parser.coordinate(), "variable index out of range (index " + std::to_string(variableID) + ")");
return variables[variableID]; return variables[variableID];
} }

View File

@ -24,7 +24,7 @@ VariableTransition::VariableTransition()
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
VariableTransition VariableTransition::fromSAS(utils::Parser &parser, const Variables &variables) VariableTransition VariableTransition::fromSAS(utils::Parser<> &parser, const Variables &variables)
{ {
VariableTransition variableTransition; VariableTransition variableTransition;

View File

@ -105,7 +105,7 @@ void Logger::logError(const std::string &message)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::logError(const Parser::Coordinate &coordinate, const std::string &message) void Logger::logError(const StreamCoordinate &coordinate, const std::string &message)
{ {
m_errorStream m_errorStream
<< Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":" << Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":"
@ -119,15 +119,13 @@ void Logger::logError(const Parser::Coordinate &coordinate, const std::string &m
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::logWarning(const Parser &parser, const std::string &message) void Logger::logWarning(const StreamCoordinate &coordinate, const std::string &message)
{ {
if (m_warningLevel == WarningLevel::Ignore) if (m_warningLevel == WarningLevel::Ignore)
return; return;
if (m_warningLevel == WarningLevel::Error) if (m_warningLevel == WarningLevel::Error)
throw ParserException(parser, message); throw ParserException(coordinate, message);
const auto coordinate = parser.coordinate();
m_errorStream m_errorStream
<< Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":" << Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":"

View File

@ -1,628 +0,0 @@
#include <plasp/utils/Parser.h>
#include <algorithm>
#include <fstream>
#include <boost/assert.hpp>
#include <plasp/utils/ParserException.h>
namespace plasp
{
namespace utils
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Parser
//
////////////////////////////////////////////////////////////////////////////////////////////////////
const std::istreambuf_iterator<char> Parser::EndOfFile = std::istreambuf_iterator<char>();
////////////////////////////////////////////////////////////////////////////////////////////////////
Parser::Parser()
: m_isCaseSensitive{true}
{
std::setlocale(LC_NUMERIC, "C");
// Dont skip whitespace
m_stream.exceptions(std::istream::badbit);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Parser::Parser(std::string streamName, std::istream &istream)
: Parser()
{
readStream(streamName, istream);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Parser::Parser(Parser &&other)
: m_stream{std::move(other.m_stream)},
m_streamDelimiters{std::move(other.m_streamDelimiters)},
m_isCaseSensitive{other.m_isCaseSensitive}
{
other.m_isCaseSensitive = true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Parser &Parser::operator=(Parser &&other)
{
m_stream = std::move(other.m_stream);
m_streamDelimiters = std::move(other.m_streamDelimiters);
m_isCaseSensitive = other.m_isCaseSensitive;
other.m_isCaseSensitive = true;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::readStream(std::string streamName, std::istream &istream)
{
// Store position of new section
const auto position = m_stream.tellp();
m_streamDelimiters.push_back({position, streamName});
m_stream << istream.rdbuf();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::readFile(const boost::filesystem::path &path)
{
if (!boost::filesystem::is_regular_file(path))
throw std::runtime_error("File does not exist: “" + path.string() + "");
std::ifstream fileStream(path.string(), std::ios::in);
readStream(path.string(), fileStream);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::reset()
{
m_stream.clear();
seek(0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::seek(Position position)
{
m_stream.clear();
m_stream.seekg(position);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Parser::Position Parser::position() const
{
return m_stream.tellg();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Parser::Coordinate Parser::coordinate() const
{
const auto currentPosition = position();
// Find current section
auto currentFile = std::find_if(m_streamDelimiters.crbegin(), m_streamDelimiters.crend(),
[&](const auto &fileDelimiter)
{
return currentPosition >= fileDelimiter.position;
});
// If the parser is at the end of the stream, still count from the beginning of the last section
if (currentFile == m_streamDelimiters.crend())
currentFile = m_streamDelimiters.crbegin();
// Go back to beginning of section
m_stream.clear();
m_stream.seekg(currentFile->position);
size_t row = 1;
size_t column = 1;
// Compute the coordinate character by character
while (true)
{
if (currentPosition == -1 && atEndOfStream())
break;
else if (currentPosition >= 0 && position() >= currentPosition)
break;
const auto character = currentCharacter();
if (character == '\n')
{
row++;
column = 1;
}
else if (std::isblank(character) || std::isprint(character))
column++;
m_stream.ignore(1);
}
return {currentFile->sectionName, row, column};
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::setCaseSensitive(bool isCaseSensitive)
{
m_isCaseSensitive = isCaseSensitive;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool Parser::isCaseSensitive() const noexcept
{
return m_isCaseSensitive;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
char Parser::currentCharacter() const
{
if (m_isCaseSensitive)
return m_stream.peek();
return std::tolower(m_stream.peek());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool Parser::atEndOfStream() const
{
return position() == -1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::checkStream() const
{
if (atEndOfStream())
throw ParserException(*this, "reading past end of file");
if (m_stream.fail())
throw ParserException(*this);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::advance()
{
checkStream();
m_stream.ignore(1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::skipWhiteSpace()
{
return skipWhiteSpace(
[](const auto character)
{
return std::isspace(character);
});
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::skipLine()
{
checkStream();
while (currentCharacter() != '\n')
advance();
advance();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
std::string Parser::getLine()
{
checkStream();
std::string value;
while (true)
{
const auto character = currentCharacter();
advance();
if (character == '\n')
break;
else if (character == '\r')
continue;
value.push_back(character);
}
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
std::string Parser::parse<std::string>()
{
skipWhiteSpace();
std::string value;
while (true)
{
const auto character = currentCharacter();
if (std::isspace(character))
break;
value.push_back(character);
advance();
}
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
bool Parser::probe<std::string>(const std::string &expectedValue)
{
const auto previousPosition = position();
if (!std::iswspace(expectedValue.front()))
skipWhiteSpace();
const auto match = std::find_if(expectedValue.cbegin(), expectedValue.cend(),
[&](const auto &expectedCharacter)
{
const auto character = static_cast<char>(this->currentCharacter());
if (character != expectedCharacter)
return true;
this->advance();
return false;
});
const auto differs = (match != expectedValue.cend());
if (!differs)
return true;
seek(previousPosition);
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
void Parser::expect<std::string>(const std::string &expectedValue)
{
if (!probe<std::string>(expectedValue))
throw ParserException(*this, "expected “" + expectedValue + "");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
char Parser::parse<char>()
{
const auto value = currentCharacter();
advance();
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
bool Parser::probe<char>(const char &expectedValue)
{
if (currentCharacter() != expectedValue)
return false;
advance();
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
void Parser::expect<char>(const char &expectedValue)
{
if (!probe<char>(expectedValue))
throw ParserException(*this, std::string("expected “") + expectedValue + "");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
uint64_t Parser::parseIntegerBody()
{
checkStream();
if (!std::isdigit(currentCharacter()))
throw ParserException(*this, "could not parse integer value");
uint64_t value = 0;
while (!atEndOfStream())
{
const auto character = currentCharacter();
if (!std::isdigit(character))
break;
value *= 10;
value += character - '0';
advance();
}
return value;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
int64_t Parser::parse<int64_t>()
{
skipWhiteSpace();
bool positive = probe('+') || !probe('-');
const auto value = parseIntegerBody();
return (positive ? value : -value);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
uint64_t Parser::parse<uint64_t>()
{
skipWhiteSpace();
if (currentCharacter() == '-')
throw ParserException(*this, "expected unsigned integer, got signed one");
return parseIntegerBody();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
bool Parser::probe<int64_t>(const int64_t &expectedValue)
{
const auto previousPosition = position();
const auto value = parse<int64_t>();
if (value == expectedValue)
return true;
seek(previousPosition);
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
bool Parser::probe<uint64_t>(const uint64_t &expectedValue)
{
const auto previousPosition = position();
const auto value = parse<uint64_t>();
if (value == expectedValue)
return true;
seek(previousPosition);
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
void Parser::expect<int64_t>(const int64_t &expectedValue)
{
if (!probe<int64_t>(expectedValue))
throw ParserException(*this, "expected “" + std::to_string(expectedValue) + "");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
void Parser::expect<uint64_t>(const uint64_t &expectedValue)
{
if (!probe<uint64_t>(expectedValue))
throw ParserException(*this, "expected “" + std::to_string(expectedValue) + "");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
int32_t Parser::parse<int32_t>()
{
return static_cast<int32_t>(parse<int64_t>());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
uint32_t Parser::parse<uint32_t>()
{
return static_cast<uint32_t>(parse<uint64_t>());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
bool Parser::probe<int32_t>(const int32_t &expectedValue)
{
return probe<int64_t>(static_cast<int64_t>(expectedValue));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
bool Parser::probe<uint32_t>(const uint32_t &expectedValue)
{
return probe<uint64_t>(static_cast<uint64_t>(expectedValue));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
void Parser::expect<int32_t>(const int32_t &expectedValue)
{
expect<int64_t>(static_cast<int64_t>(expectedValue));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
void Parser::expect<uint32_t>(const uint32_t &expectedValue)
{
expect<uint64_t>(static_cast<uint64_t>(expectedValue));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
bool Parser::parse<bool>()
{
skipWhiteSpace();
if (probe('0'))
return false;
if (probe('1'))
return true;
throw ParserException(*this, "could not parse Boolean value");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<>
void Parser::expect<bool>(const bool &expectedValue)
{
const auto value = parse<bool>();
if (value != expectedValue)
throw ParserException(*this, "expected “" + std::to_string(expectedValue) + "");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool Parser::probeNumber()
{
const auto previousPosition = position();
skipWhiteSpace();
while (!std::iswspace(currentCharacter()))
if (!std::isdigit(currentCharacter()))
{
seek(previousPosition);
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Parser::removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd)
{
const auto inPosition = m_stream.tellg();
const auto outPosition = m_stream.tellp();
m_stream.seekg(0);
const auto removeRange =
[&](const auto &start, const auto &end)
{
BOOST_ASSERT(start != -1);
m_stream.clear();
m_stream.seekp(start);
m_stream.seekg(start);
auto position = start;
while (end == -1 || position < end)
{
m_stream.ignore(1);
if (atEndOfStream())
return;
m_stream.put(' ');
position += static_cast<std::streamoff>(1);
}
};
while (!atEndOfStream())
{
Position startPosition = m_stream.tellg();
while (!atEndOfStream())
{
startPosition = m_stream.tellg();
if (probe(startSequence))
break;
advance();
}
Position endPosition = m_stream.tellg();
while (!atEndOfStream())
{
endPosition = m_stream.tellg();
if (probe(endSequence))
break;
advance();
}
if (removeEnd)
endPosition = m_stream.tellg();
removeRange(startPosition, endPosition);
}
m_stream.clear();
m_stream.seekg(inPosition);
m_stream.seekp(outPosition);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

162
src/plasp/utils/Stream.cpp Normal file
View File

@ -0,0 +1,162 @@
#include <plasp/utils/Stream.h>
#include <fstream>
namespace plasp
{
namespace utils
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Stream
//
////////////////////////////////////////////////////////////////////////////////////////////////////
Stream::Stream()
{
std::setlocale(LC_NUMERIC, "C");
// Dont skip whitespace
m_stream.exceptions(std::istream::badbit);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Stream::Stream(std::string streamName, std::istream &istream)
{
read(streamName, istream);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Stream::read(std::string streamName, std::istream &istream)
{
// Store position of new section
const auto position = m_stream.tellp();
m_delimiters.push_back({position, streamName});
m_stream << istream.rdbuf();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Stream::read(const boost::filesystem::path &path)
{
if (!boost::filesystem::is_regular_file(path))
throw std::runtime_error("File does not exist: “" + path.string() + "");
std::ifstream fileStream(path.string(), std::ios::in);
read(path.string(), fileStream);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Stream::reset()
{
m_stream.clear();
seek(0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Stream::seek(Position position)
{
m_stream.clear();
m_stream.seekg(position);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
typename Stream::Position Stream::position() const
{
return m_stream.tellg();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
StreamCoordinate Stream::coordinate() const
{
const auto currentPosition = position();
// Find current section
auto currentFile = std::find_if(m_delimiters.crbegin(), m_delimiters.crend(),
[&](const auto &fileDelimiter)
{
return currentPosition >= fileDelimiter.position;
});
// If the parser is at the end of the stream, still count from the beginning of the last section
if (currentFile == m_delimiters.crend())
currentFile = m_delimiters.crbegin();
// Go back to beginning of section
m_stream.clear();
m_stream.seekg(currentFile->position);
size_t row = 1;
size_t column = 1;
// Compute the coordinate character by character
while (true)
{
if (currentPosition == -1 && atEnd())
break;
else if (currentPosition >= 0 && position() >= currentPosition)
break;
const auto character = currentCharacter();
if (character == '\n')
{
row++;
column = 1;
}
else if (std::isblank(character) || std::isprint(character))
column++;
m_stream.ignore(1);
}
return {currentFile->sectionName, row, column};
}
////////////////////////////////////////////////////////////////////////////////////////////////////
char Stream::currentCharacter() const
{
return m_stream.peek();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool Stream::atEnd() const
{
return position() == -1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Stream::check() const
{
if (atEnd())
throw ParserException(coordinate(), "reading past end of file");
if (m_stream.fail())
throw ParserException(coordinate());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Stream::advance()
{
check();
m_stream.ignore(1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}

View File

@ -9,9 +9,10 @@
TEST(UtilsTests, ParseSimple) TEST(UtilsTests, ParseSimple)
{ {
std::stringstream s("identifier 5 \n-51\t 0 1 expected unexpected"); std::stringstream s("identifier 5 \n-51\t 0 1 expected unexpected");
plasp::utils::Parser p("input", s); plasp::utils::Parser<> p("input", s);
ASSERT_TRUE(p.isCaseSensitive()); // TODO: reimplement
//ASSERT_TRUE(p.isCaseSensitive());
ASSERT_EQ(p.parse<std::string>(), "identifier"); ASSERT_EQ(p.parse<std::string>(), "identifier");
ASSERT_EQ(p.parse<size_t>(), 5u); ASSERT_EQ(p.parse<size_t>(), 5u);
@ -31,7 +32,7 @@ TEST(UtilsTests, ParseSimple)
TEST(UtilsTests, ParseUnsignedNumbers) TEST(UtilsTests, ParseUnsignedNumbers)
{ {
std::stringstream s("100 200 -300 -400"); std::stringstream s("100 200 -300 -400");
plasp::utils::Parser p("input", s); plasp::utils::Parser<> p("input", s);
ASSERT_EQ(p.parse<int>(), 100); ASSERT_EQ(p.parse<int>(), 100);
ASSERT_EQ(p.parse<size_t>(), 200u); ASSERT_EQ(p.parse<size_t>(), 200u);
@ -44,13 +45,13 @@ TEST(UtilsTests, ParseUnsignedNumbers)
TEST(UtilsTests, ParseEndOfFile) TEST(UtilsTests, ParseEndOfFile)
{ {
std::stringstream s1("test"); std::stringstream s1("test");
plasp::utils::Parser p1("input", s1); plasp::utils::Parser<> p1("input", s1);
ASSERT_NO_THROW(p1.expect<std::string>("test")); ASSERT_NO_THROW(p1.expect<std::string>("test"));
ASSERT_THROW(p1.parse<std::string>(), plasp::utils::ParserException); ASSERT_THROW(p1.parse<std::string>(), plasp::utils::ParserException);
std::stringstream s2("test1 test2 test3"); std::stringstream s2("test1 test2 test3");
plasp::utils::Parser p2("input", s2); plasp::utils::Parser<> p2("input", s2);
ASSERT_NO_THROW(p2.expect<std::string>("test1")); ASSERT_NO_THROW(p2.expect<std::string>("test1"));
ASSERT_NO_THROW(p2.expect<std::string>("test2")); ASSERT_NO_THROW(p2.expect<std::string>("test2"));
@ -58,13 +59,13 @@ TEST(UtilsTests, ParseEndOfFile)
ASSERT_THROW(p2.parse<std::string>(), plasp::utils::ParserException); ASSERT_THROW(p2.parse<std::string>(), plasp::utils::ParserException);
std::stringstream s3("-127"); std::stringstream s3("-127");
plasp::utils::Parser p3("input", s3); plasp::utils::Parser<> p3("input", s3);
p3.expect<int>(-127); p3.expect<int>(-127);
ASSERT_THROW(p3.parse<int>(), plasp::utils::ParserException); ASSERT_THROW(p3.parse<int>(), plasp::utils::ParserException);
std::stringstream s4("128 -1023 -4095"); std::stringstream s4("128 -1023 -4095");
plasp::utils::Parser p4("input", s4); plasp::utils::Parser<> p4("input", s4);
ASSERT_NO_THROW(p4.expect<size_t>(128)); ASSERT_NO_THROW(p4.expect<size_t>(128));
ASSERT_NO_THROW(p4.expect<int>(-1023)); ASSERT_NO_THROW(p4.expect<int>(-1023));
@ -72,13 +73,13 @@ TEST(UtilsTests, ParseEndOfFile)
ASSERT_THROW(p4.parse<int>(), plasp::utils::ParserException); ASSERT_THROW(p4.parse<int>(), plasp::utils::ParserException);
std::stringstream s5("0"); std::stringstream s5("0");
plasp::utils::Parser p5("input", s5); plasp::utils::Parser<> p5("input", s5);
p5.expect<bool>(false); p5.expect<bool>(false);
ASSERT_THROW(p5.parse<bool>(), plasp::utils::ParserException); ASSERT_THROW(p5.parse<bool>(), plasp::utils::ParserException);
std::stringstream s6("0 1 0"); std::stringstream s6("0 1 0");
plasp::utils::Parser p6("input", s6); plasp::utils::Parser<> p6("input", s6);
ASSERT_NO_THROW(p6.expect<bool>(false)); ASSERT_NO_THROW(p6.expect<bool>(false));
ASSERT_NO_THROW(p6.expect<bool>(true)); ASSERT_NO_THROW(p6.expect<bool>(true));
@ -91,11 +92,11 @@ TEST(UtilsTests, ParseEndOfFile)
TEST(UtilsTests, ParserPosition) TEST(UtilsTests, ParserPosition)
{ {
std::stringstream s("123 \n4\ntest1\n test2\ntest3 \ntest4\n\n\n\n"); std::stringstream s("123 \n4\ntest1\n test2\ntest3 \ntest4\n\n\n\n");
plasp::utils::Parser p("input", s); plasp::utils::Parser<> p("input", s);
const auto startPosition = p.position(); const auto startPosition = p.position();
plasp::utils::Parser::Coordinate c; plasp::utils::StreamCoordinate c;
c = p.coordinate(); c = p.coordinate();
ASSERT_EQ(c.row, 1u); ASSERT_EQ(c.row, 1u);
@ -174,11 +175,11 @@ TEST(UtilsTests, ParserPosition)
c = p.coordinate(); c = p.coordinate();
ASSERT_EQ(c.row, 10u); ASSERT_EQ(c.row, 10u);
ASSERT_EQ(c.column, 1u); ASSERT_EQ(c.column, 1u);
ASSERT_TRUE(p.atEndOfStream()); ASSERT_TRUE(p.atEnd());
p.reset(); p.reset();
ASSERT_EQ(p.position(), startPosition); ASSERT_EQ(p.position(), startPosition);
ASSERT_FALSE(p.atEndOfStream()); ASSERT_FALSE(p.atEnd());
for (size_t i = 0; i < 5; i++) for (size_t i = 0; i < 5; i++)
p.advance(); p.advance();
@ -199,11 +200,11 @@ TEST(UtilsTests, ParserPosition)
TEST(UtilsTests, ParserRemoveComments) TEST(UtilsTests, ParserRemoveComments)
{ {
std::stringstream s1("; comment at beginning\ntest1; comment in between\ntest2; comment at end"); std::stringstream s1("; comment at beginning\ntest1; comment in between\ntest2; comment at end");
plasp::utils::Parser p1("input", s1); plasp::utils::Parser<> p1("input", s1);
p1.removeComments(";", "\n", false); p1.removeComments(";", "\n", false);
plasp::utils::Parser::Coordinate c; plasp::utils::StreamCoordinate c;
ASSERT_NO_THROW(p1.expect<std::string>("test1")); ASSERT_NO_THROW(p1.expect<std::string>("test1"));
@ -219,10 +220,10 @@ TEST(UtilsTests, ParserRemoveComments)
p1.skipWhiteSpace(); p1.skipWhiteSpace();
ASSERT_TRUE(p1.atEndOfStream()); ASSERT_TRUE(p1.atEnd());
std::stringstream s2("test;"); std::stringstream s2("test;");
plasp::utils::Parser p2("input", s2); plasp::utils::Parser<> p2("input", s2);
p2.removeComments(";", "\n", false); p2.removeComments(";", "\n", false);
@ -230,10 +231,10 @@ TEST(UtilsTests, ParserRemoveComments)
p2.skipWhiteSpace(); p2.skipWhiteSpace();
ASSERT_TRUE(p2.atEndOfStream()); ASSERT_TRUE(p2.atEnd());
std::stringstream s3("/* comment at start */ test1 /* comment in between */ test2 /*"); std::stringstream s3("/* comment at start */ test1 /* comment in between */ test2 /*");
plasp::utils::Parser p3("input", s3); plasp::utils::Parser<> p3("input", s3);
p3.removeComments("/*", "*/", true); p3.removeComments("/*", "*/", true);
@ -242,7 +243,7 @@ TEST(UtilsTests, ParserRemoveComments)
p3.skipWhiteSpace(); p3.skipWhiteSpace();
ASSERT_TRUE(p3.atEndOfStream()); ASSERT_TRUE(p3.atEnd());
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////