diff --git a/apps/plasp-app/main.cpp b/apps/plasp-app/main.cpp index 626ad83..a996833 100644 --- a/apps/plasp-app/main.cpp +++ b/apps/plasp-app/main.cpp @@ -104,9 +104,7 @@ int main(int argc, char **argv) try { - plasp::utils::Parser parser; - - parser.setCaseSensitive(false); + plasp::utils::Parser parser; if (variablesMap.count("input")) { @@ -115,11 +113,11 @@ int main(int argc, char **argv) std::for_each(inputFiles.cbegin(), inputFiles.cend(), [&](const auto &inputFile) { - parser.readFile(inputFile); + parser.read(inputFile); }); } else - parser.readStream("std::cin", std::cin); + parser.read("std::cin", std::cin); const auto detectLanguage = [&]() diff --git a/include/plasp/LanguageDetection.h b/include/plasp/LanguageDetection.h index 39c9df5..dc7ccb2 100644 --- a/include/plasp/LanguageDetection.h +++ b/include/plasp/LanguageDetection.h @@ -13,13 +13,12 @@ namespace plasp // //////////////////////////////////////////////////////////////////////////////////////////////////// -Language::Type detectLanguage(utils::Parser &parser) +Language::Type detectLanguage(utils::Parser &parser) { - parser.setCaseSensitive(false); parser.skipWhiteSpace(); // SAS begins with "begin_version" - if (parser.probe("begin")) + if (parser.testAndSkip("begin")) { parser.seek(0); return Language::Type::SAS; @@ -33,7 +32,7 @@ Language::Type detectLanguage(utils::Parser &parser) } // PDDL contains sections starting with "(define" - if (parser.probe("(") && parser.probe("define")) + if (parser.testAndSkip("(") && parser.testAndSkip("define")) { parser.seek(std::ios::beg); return Language::Type::PDDL; diff --git a/include/plasp/pddl/Context.h b/include/plasp/pddl/Context.h index 76d5ca2..931c60f 100644 --- a/include/plasp/pddl/Context.h +++ b/include/plasp/pddl/Context.h @@ -5,6 +5,7 @@ #include #include +#include #include namespace plasp @@ -22,20 +23,21 @@ class Context { public: Context() = default; + ~Context() = default; - explicit Context(utils::Parser &&parser) - : parser{std::move(parser)} + explicit Context(Parser &&otherParser) + : parser{std::move(otherParser)} { } - explicit Context(utils::Logger &&logger) - : logger{std::move(logger)} + explicit Context(utils::Logger &&otherLogger) + : logger{std::move(otherLogger)} { } - explicit Context(utils::Parser &&parser, utils::Logger &&logger) - : parser{std::move(parser)}, - logger{std::move(logger)} + explicit Context(Parser &&otherParser, utils::Logger &&otherLogger) + : parser{std::move(otherParser)}, + logger{std::move(otherLogger)} { } @@ -56,7 +58,7 @@ class Context return *this; } - utils::Parser parser; + Parser parser; utils::Logger logger; }; diff --git a/include/plasp/pddl/Description.h b/include/plasp/pddl/Description.h index 50a1687..fb22c5d 100644 --- a/include/plasp/pddl/Description.h +++ b/include/plasp/pddl/Description.h @@ -45,9 +45,9 @@ class Description Context m_context; - utils::Parser::Position m_domainPosition; + utils::Stream::Position m_domainPosition; std::unique_ptr m_domain; - utils::Parser::Position m_problemPosition; + utils::Stream::Position m_problemPosition; std::unique_ptr m_problem; }; diff --git a/include/plasp/pddl/Domain.h b/include/plasp/pddl/Domain.h index 42bcc56..7d8b75b 100644 --- a/include/plasp/pddl/Domain.h +++ b/include/plasp/pddl/Domain.h @@ -4,10 +4,11 @@ #include #include #include +#include +#include #include #include #include -#include namespace plasp { @@ -68,19 +69,19 @@ class Domain std::string m_name; - utils::Parser::Position m_requirementsPosition; + utils::Stream::Position m_requirementsPosition; Requirements m_requirements; - utils::Parser::Position m_typesPosition; + utils::Stream::Position m_typesPosition; expressions::PrimitiveTypes m_types; - utils::Parser::Position m_constantsPosition; + utils::Stream::Position m_constantsPosition; expressions::Constants m_constants; - utils::Parser::Position m_predicatesPosition; + utils::Stream::Position m_predicatesPosition; expressions::PredicateDeclarations m_predicates; - std::vector m_actionPositions; + std::vector m_actionPositions; std::vector> m_actions; }; diff --git a/include/plasp/pddl/IO.h b/include/plasp/pddl/IO.h index be392eb..1c46eb7 100644 --- a/include/plasp/pddl/IO.h +++ b/include/plasp/pddl/IO.h @@ -3,7 +3,7 @@ #include -#include +#include namespace plasp { @@ -16,7 +16,7 @@ namespace pddl // //////////////////////////////////////////////////////////////////////////////////////////////////// -inline void skipSection(utils::Parser &parser) +inline void skipSection(Parser &parser) { size_t openParentheses = 1; diff --git a/include/plasp/pddl/Parser.h b/include/plasp/pddl/Parser.h new file mode 100644 index 0000000..aceb877 --- /dev/null +++ b/include/plasp/pddl/Parser.h @@ -0,0 +1,49 @@ +#ifndef __PLASP__PDDL__PARSER_H +#define __PLASP__PDDL__PARSER_H + +#include + +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; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/include/plasp/pddl/Problem.h b/include/plasp/pddl/Problem.h index e761b86..5b6dc4f 100644 --- a/include/plasp/pddl/Problem.h +++ b/include/plasp/pddl/Problem.h @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace plasp @@ -61,18 +62,18 @@ class Problem 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; - utils::Parser::Position m_objectsPosition; + utils::Stream::Position m_objectsPosition; expressions::Constants m_objects; - utils::Parser::Position m_initialStatePosition; + utils::Stream::Position m_initialStatePosition; std::unique_ptr m_initialState; - utils::Parser::Position m_goalPosition; + utils::Stream::Position m_goalPosition; ExpressionPointer m_goal; }; diff --git a/include/plasp/pddl/expressions/At.h b/include/plasp/pddl/expressions/At.h index bfc9c8d..166d9ad 100644 --- a/include/plasp/pddl/expressions/At.h +++ b/include/plasp/pddl/expressions/At.h @@ -3,7 +3,6 @@ #include #include -#include namespace plasp { @@ -57,8 +56,8 @@ AtPointer At::parse(Context &context, ExpressionContext &expressionContext, const auto position = parser.position(); - if (!parser.probe("(") - || !parser.probeIdentifier("at", isIdentifier)) + if (!parser.testAndSkip("(") + || !parser.testIdentifierAndSkip("at")) { parser.seek(position); return nullptr; @@ -68,9 +67,9 @@ AtPointer At::parse(Context &context, ExpressionContext &expressionContext, const auto timePointPosition = parser.position(); - if (parser.probeIdentifier("start", isIdentifier)) + if (parser.testIdentifierAndSkip("start")) timePoint = TimePointStart; - else if (parser.probeIdentifier("end", isIdentifier)) + else if (parser.testIdentifierAndSkip("end")) timePoint = TimePointEnd; else if (parser.probeNumber()) { diff --git a/include/plasp/pddl/expressions/Binary.h b/include/plasp/pddl/expressions/Binary.h index 23d625c..1561ceb 100644 --- a/include/plasp/pddl/expressions/Binary.h +++ b/include/plasp/pddl/expressions/Binary.h @@ -4,7 +4,6 @@ #include #include #include -#include #include namespace plasp @@ -52,8 +51,8 @@ std::unique_ptr Binary::parse(Context &context, const auto position = parser.position(); - if (!parser.probe("(") - || !parser.probeIdentifier(Derived::Identifier, isIdentifier)) + if (!parser.testAndSkip("(") + || !parser.testIdentifierAndSkip(Derived::Identifier)) { parser.seek(position); return nullptr; diff --git a/include/plasp/pddl/expressions/Constant.h b/include/plasp/pddl/expressions/Constant.h index d45ac0b..0aed166 100644 --- a/include/plasp/pddl/expressions/Constant.h +++ b/include/plasp/pddl/expressions/Constant.h @@ -2,7 +2,6 @@ #define __PLASP__PDDL__EXPRESSIONS__CONSTANT_H #include -#include #include #include diff --git a/include/plasp/pddl/expressions/NAry.h b/include/plasp/pddl/expressions/NAry.h index 74470e8..7f6789b 100644 --- a/include/plasp/pddl/expressions/NAry.h +++ b/include/plasp/pddl/expressions/NAry.h @@ -4,7 +4,6 @@ #include #include #include -#include #include namespace plasp @@ -50,8 +49,8 @@ std::unique_ptr NAry::parse(Context &context, const auto position = parser.position(); - if (!parser.probe("(") - || !parser.probeIdentifier(Derived::Identifier, isIdentifier)) + if (!parser.testAndSkip("(") + || !parser.testIdentifierAndSkip(Derived::Identifier)) { parser.seek(position); return nullptr; @@ -71,7 +70,7 @@ std::unique_ptr NAry::parse(Context &context, } 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(")"); diff --git a/include/plasp/pddl/expressions/Not.h b/include/plasp/pddl/expressions/Not.h index f8a6beb..641ec7e 100644 --- a/include/plasp/pddl/expressions/Not.h +++ b/include/plasp/pddl/expressions/Not.h @@ -3,7 +3,6 @@ #include #include -#include namespace plasp { @@ -50,8 +49,8 @@ NotPointer Not::parse(Context &context, ExpressionContext &expressionContext, const auto position = parser.position(); - if (!parser.probe("(") - || !parser.probeIdentifier("not", isIdentifier)) + if (!parser.testAndSkip("(") + || !parser.testIdentifierAndSkip("not")) { parser.seek(position); return nullptr; diff --git a/include/plasp/pddl/expressions/PrimitiveType.h b/include/plasp/pddl/expressions/PrimitiveType.h index 5bd1de1..12b3819 100644 --- a/include/plasp/pddl/expressions/PrimitiveType.h +++ b/include/plasp/pddl/expressions/PrimitiveType.h @@ -3,7 +3,6 @@ #include #include -#include #include namespace plasp diff --git a/include/plasp/sas/AssignedVariable.h b/include/plasp/sas/AssignedVariable.h index 92c9523..7dc438b 100644 --- a/include/plasp/sas/AssignedVariable.h +++ b/include/plasp/sas/AssignedVariable.h @@ -27,8 +27,8 @@ using AssignedVariables = std::vector; class AssignedVariable { public: - 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 Variables &variables); + static AssignedVariable fromSAS(utils::Parser<> &parser, const Variable &variable); public: explicit AssignedVariable(const Variable &variable, const Value &value); diff --git a/include/plasp/sas/AxiomRule.h b/include/plasp/sas/AxiomRule.h index b59d1a1..88fa1db 100644 --- a/include/plasp/sas/AxiomRule.h +++ b/include/plasp/sas/AxiomRule.h @@ -29,7 +29,7 @@ class AxiomRule using Condition = AssignedVariable; using Conditions = AssignedVariables; - static AxiomRule fromSAS(utils::Parser &parser, const Variables &variables); + static AxiomRule fromSAS(utils::Parser<> &parser, const Variables &variables); public: const Conditions &conditions() const; diff --git a/include/plasp/sas/Description.h b/include/plasp/sas/Description.h index ca97d74..80ba09d 100644 --- a/include/plasp/sas/Description.h +++ b/include/plasp/sas/Description.h @@ -29,7 +29,7 @@ namespace sas class Description { public: - static Description fromParser(utils::Parser &&parser); + static Description fromParser(utils::Parser<> &&parser); static Description fromStream(std::istream &istream); static Description fromFile(const boost::filesystem::path &path); @@ -48,16 +48,16 @@ class Description private: Description(); - void parseContent(utils::Parser &parser); + void parseContent(utils::Parser<> &parser); - void parseVersionSection(utils::Parser &parser) const; - void parseMetricSection(utils::Parser &parser); - void parseVariablesSection(utils::Parser &parser); - void parseMutexSection(utils::Parser &parser); - void parseInitialStateSection(utils::Parser &parser); - void parseGoalSection(utils::Parser &parser); - void parseOperatorSection(utils::Parser &parser); - void parseAxiomSection(utils::Parser &parser); + void parseVersionSection(utils::Parser<> &parser) const; + void parseMetricSection(utils::Parser<> &parser); + void parseVariablesSection(utils::Parser<> &parser); + void parseMutexSection(utils::Parser<> &parser); + void parseInitialStateSection(utils::Parser<> &parser); + void parseGoalSection(utils::Parser<> &parser); + void parseOperatorSection(utils::Parser<> &parser); + void parseAxiomSection(utils::Parser<> &parser); bool m_usesActionCosts; diff --git a/include/plasp/sas/Effect.h b/include/plasp/sas/Effect.h index 947bf09..5a02bae 100644 --- a/include/plasp/sas/Effect.h +++ b/include/plasp/sas/Effect.h @@ -29,7 +29,7 @@ class Effect using Condition = AssignedVariable; 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: const Conditions &conditions() const; diff --git a/include/plasp/sas/Goal.h b/include/plasp/sas/Goal.h index ad0ee82..ebdca5d 100644 --- a/include/plasp/sas/Goal.h +++ b/include/plasp/sas/Goal.h @@ -21,7 +21,7 @@ class Goal using Fact = AssignedVariable; using Facts = AssignedVariables; - static Goal fromSAS(utils::Parser &parser, const Variables &variables); + static Goal fromSAS(utils::Parser<> &parser, const Variables &variables); public: const Facts &facts() const; diff --git a/include/plasp/sas/InitialState.h b/include/plasp/sas/InitialState.h index 59c0ae8..92d1576 100644 --- a/include/plasp/sas/InitialState.h +++ b/include/plasp/sas/InitialState.h @@ -21,7 +21,7 @@ class InitialState using Fact = AssignedVariable; using Facts = AssignedVariables; - static InitialState fromSAS(utils::Parser &parser, const Variables &variables); + static InitialState fromSAS(utils::Parser<> &parser, const Variables &variables); public: const Facts &facts() const; diff --git a/include/plasp/sas/MutexGroup.h b/include/plasp/sas/MutexGroup.h index 0965772..f16e5e0 100644 --- a/include/plasp/sas/MutexGroup.h +++ b/include/plasp/sas/MutexGroup.h @@ -28,7 +28,7 @@ class MutexGroup using Fact = AssignedVariable; using Facts = AssignedVariables; - static MutexGroup fromSAS(utils::Parser &parser, const Variables &variables); + static MutexGroup fromSAS(utils::Parser<> &parser, const Variables &variables); public: const Facts &facts() const; diff --git a/include/plasp/sas/Operator.h b/include/plasp/sas/Operator.h index 96d6a58..9db777a 100644 --- a/include/plasp/sas/Operator.h +++ b/include/plasp/sas/Operator.h @@ -33,7 +33,7 @@ class Operator using Condition = AssignedVariable; using Conditions = AssignedVariables; - static Operator fromSAS(utils::Parser &parser, const Variables &variables); + static Operator fromSAS(utils::Parser<> &parser, const Variables &variables); public: void printPredicateAsASP(utils::LogStream &ostream) const; diff --git a/include/plasp/sas/Predicate.h b/include/plasp/sas/Predicate.h index 46ab5ea..a768b05 100644 --- a/include/plasp/sas/Predicate.h +++ b/include/plasp/sas/Predicate.h @@ -22,7 +22,7 @@ namespace sas class Predicate { public: - static Predicate fromSAS(utils::Parser &parser); + static Predicate fromSAS(utils::Parser<> &parser); using Arguments = std::vector; diff --git a/include/plasp/sas/Value.h b/include/plasp/sas/Value.h index 8de7423..cd92e64 100644 --- a/include/plasp/sas/Value.h +++ b/include/plasp/sas/Value.h @@ -39,8 +39,8 @@ struct Value static const Value Any; static const Value None; - static Value fromSAS(utils::Parser &parser); - static const Value &referenceFromSAS(utils::Parser &parser, const Variable &variable); + static Value fromSAS(utils::Parser<> &parser); + static const Value &referenceFromSAS(utils::Parser<> &parser, const Variable &variable); public: Value negated() const; diff --git a/include/plasp/sas/Variable.h b/include/plasp/sas/Variable.h index 085df10..ce80363 100644 --- a/include/plasp/sas/Variable.h +++ b/include/plasp/sas/Variable.h @@ -28,8 +28,8 @@ using Variables = std::vector; class Variable { public: - static Variable fromSAS(utils::Parser &parser); - static const Variable &referenceFromSAS(utils::Parser &parser, const Variables &variables); + static Variable fromSAS(utils::Parser<> &parser); + static const Variable &referenceFromSAS(utils::Parser<> &parser, const Variables &variables); public: void printNameAsASPPredicate(utils::LogStream &outputStream) const; diff --git a/include/plasp/sas/VariableTransition.h b/include/plasp/sas/VariableTransition.h index b38659f..8fd2868 100644 --- a/include/plasp/sas/VariableTransition.h +++ b/include/plasp/sas/VariableTransition.h @@ -26,7 +26,7 @@ using VariableTransitions = std::vector; class VariableTransition { public: - static VariableTransition fromSAS(utils::Parser &parser, const Variables &variables); + static VariableTransition fromSAS(utils::Parser<> &parser, const Variables &variables); public: const Variable &variable() const; diff --git a/include/plasp/utils/Logger.h b/include/plasp/utils/Logger.h index 263fc6f..3fed423 100644 --- a/include/plasp/utils/Logger.h +++ b/include/plasp/utils/Logger.h @@ -4,8 +4,8 @@ #include #include -#include #include +#include namespace plasp { @@ -44,8 +44,8 @@ class Logger void setColorPolicy(LogStream::ColorPolicy colorPolicy); void logError(const std::string &message); - void logError(const Parser::Coordinate &coordinate, const std::string &message); - void logWarning(const Parser &parser, const std::string &message); + void logError(const StreamCoordinate &coordinate, const std::string &message); + void logWarning(const StreamCoordinate &parserCoordinate, const std::string &message); private: LogStream m_outputStream; diff --git a/include/plasp/utils/Parser.h b/include/plasp/utils/Parser.h index d6678cf..67f6761 100644 --- a/include/plasp/utils/Parser.h +++ b/include/plasp/utils/Parser.h @@ -8,112 +8,192 @@ #include +#include +#include +#include +#include +#include + namespace plasp { namespace utils { +template +struct Tag +{ +}; + //////////////////////////////////////////////////////////////////////////////////////////////////// // // Parser // //////////////////////////////////////////////////////////////////////////////////////////////////// -class Parser +template +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: explicit Parser(); explicit Parser(std::string streamName, std::istream &istream); - // Forbid copy construction/assignment - Parser(const Parser &other) = delete; - Parser &operator=(const Parser &other) = delete; - - Parser(Parser &&other); - 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; + template + Parser(OtherParser &&otherParser) + { + m_stream = std::move(otherParser.m_stream); + m_delimiters = std::move(otherParser.m_delimiters); + } void removeComments(const std::string &startSequence, const std::string &endSequence, bool removeEnd); + char currentCharacter() const; + template Type parse(); - template - std::string parseIdentifier(CharacterPredicate characterPredicate, WhiteSpacePredicate whiteSpacePredicate); - - template - std::string parseIdentifier(CharacterPredicate characterPredicate); + template + bool testAndReturn(const Type &expectedValue); template - bool probe(const Type &expectedValue); - - template - bool probeIdentifier(const std::string &identifier, CharacterPredicate characterPredicate); - - bool probeNumber(); + bool testAndSkip(const Type &expectedValue); template void expect(const Type &expectedValue); - template - void skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate); + std::string parseIdentifier(); + bool testIdentifierAndReturn(const std::string &identifier); + bool testIdentifierAndSkip(const std::string &identifier); + + // TODO: remove + bool probeNumber(); + + std::string parseLine(); void skipWhiteSpace(); void skipLine(); - std::string getLine(); - private: - static const std::istreambuf_iterator EndOfFile; + std::string parseImpl(Tag); + char parseImpl(Tag); + uint64_t parseImpl(Tag); + int64_t parseImpl(Tag); + uint32_t parseImpl(Tag); + int32_t parseImpl(Tag); + bool parseImpl(Tag); - private: - void checkStream() const; + bool testImpl(const std::string &expectedValue); + 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(); - - mutable std::stringstream m_stream; - - std::vector m_streamDelimiters; - - bool m_isCaseSensitive; }; //////////////////////////////////////////////////////////////////////////////////////////////////// -template -std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, WhiteSpacePredicate whiteSpacePredicate) +template +Parser::Parser() +: Stream() { - skipWhiteSpace(whiteSpacePredicate); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +Parser::Parser(std::string streamName, std::istream &istream) +: Stream(streamName, istream) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +void Parser::skipWhiteSpace() +{ + check(); + + while (!atEnd() && ParserPolicy::isWhiteSpace(currentCharacter())) + advance(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +void Parser::skipLine() +{ + check(); + + while (currentCharacter() != '\n') + advance(); + + advance(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +template +Type Parser::parse() +{ + return parseImpl(Tag()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +template +bool Parser::testAndReturn(const Type &expectedValue) +{ + const auto previousPosition = position(); + + const auto result = testImpl(expectedValue); + + seek(previousPosition); + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +template +bool Parser::testAndSkip(const Type &expectedValue) +{ + const auto previousPosition = position(); + + const auto result = testImpl(expectedValue); + + if (result == false) + seek(previousPosition); + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +template +void Parser::expect(const Type &expectedValue) +{ + if (testAndSkip(expectedValue)) + return; + + std::stringstream message; + message << "unexpected value, expected “" << expectedValue << "”"; + + throw ParserException(coordinate(), message.str()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +std::string Parser::parseIdentifier() +{ + skipWhiteSpace(); std::string value; @@ -121,7 +201,7 @@ std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, White { const auto character = currentCharacter(); - if (!characterPredicate(character)) + if (!ParserPolicy::isIdentifierCharacter(character)) return value; value.push_back(character); @@ -131,33 +211,342 @@ std::string Parser::parseIdentifier(CharacterPredicate characterPredicate, White //////////////////////////////////////////////////////////////////////////////////////////////////// -template -std::string Parser::parseIdentifier(CharacterPredicate characterPredicate) +template +bool Parser::testIdentifierAndSkip(const std::string &expectedValue) { - return parseIdentifier(characterPredicate, - [&](const auto character) + return testAndSkip(expectedValue) && !ParserPolicy::isIdentifierCharacter(currentCharacter()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::probeNumber() +{ + const auto previousPosition = position(); + + skipWhiteSpace(); + + while (!ParserPolicy::isWhiteSpace(currentCharacter())) + if (!std::isdigit(currentCharacter())) { - return std::isspace(character); - }); + seek(previousPosition); + + return false; + } + + return true; } //////////////////////////////////////////////////////////////////////////////////////////////////// -template -bool Parser::probeIdentifier(const std::string &expectedValue, CharacterPredicate characterPredicate) +template +std::string Parser::parseLine() { - return probe(expectedValue) && !characterPredicate(currentCharacter()); -} + std::string value; -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template -void Parser::skipWhiteSpace(WhiteSpacePredicate whiteSpacePredicate) -{ - checkStream(); - - while (!atEndOfStream() && whiteSpacePredicate(currentCharacter())) + while (true) + { + const auto character = currentCharacter(); advance(); + + if (character == '\n') + break; + else if (character == '\r') + continue; + + value.push_back(character); + } + + return value; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +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 (atEnd()) + return; + + m_stream.put(' '); + position += static_cast(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 +char Parser::currentCharacter() const +{ + return ParserPolicy::transformCharacter(Stream::currentCharacter()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +std::string Parser::parseImpl(Tag) +{ + skipWhiteSpace(); + + const auto startPosition = position(); + + while (!ParserPolicy::isWhiteSpace(currentCharacter())) + advance(); + + const auto endPosition = position(); + const auto length = static_cast(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 +char Parser::parseImpl(Tag) +{ + const auto value = currentCharacter(); + + advance(); + + return value; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +uint64_t Parser::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 +int64_t Parser::parseImpl(Tag) +{ + skipWhiteSpace(); + + bool positive = testAndSkip('+') || !testAndSkip('-'); + + const auto value = parseIntegerBody(); + + return (positive ? value : -value); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +uint64_t Parser::parseImpl(Tag) +{ + skipWhiteSpace(); + + if (currentCharacter() == '-') + throw ParserException(coordinate(), "expected unsigned integer, got signed one"); + + return parseIntegerBody(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +int32_t Parser::parseImpl(Tag) +{ + return static_cast(parseImpl(Tag())); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +uint32_t Parser::parseImpl(Tag) +{ + return static_cast(parseImpl(Tag())); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::parseImpl(Tag) +{ + skipWhiteSpace(); + + if (testAndSkip('0')) + return false; + + if (testAndSkip('1')) + return true; + + throw ParserException(coordinate(), "could not parse Boolean value"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::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(this->currentCharacter()); + + if (character != expectedCharacter) + return true; + + this->advance(); + + return false; + }); + + return (match == expectedValue.cend()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::testImpl(char expectedValue) +{ + const auto result = (currentCharacter() == expectedValue); + + advance(); + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::testImpl(int64_t expectedValue) +{ + const auto value = parseImpl(Tag()); + + return (value == expectedValue); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::testImpl(uint64_t expectedValue) +{ + const auto value = parseImpl(Tag()); + + return (value == expectedValue); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::testImpl(int32_t expectedValue) +{ + return testImpl(static_cast(expectedValue)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::testImpl(uint32_t expectedValue) +{ + return testImpl(static_cast(expectedValue)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool Parser::testImpl(bool expectedValue) +{ + const auto value = parseImpl(Tag()); + + return (value == expectedValue); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/plasp/utils/ParserException.h b/include/plasp/utils/ParserException.h index 2bc5e4e..fb7123c 100644 --- a/include/plasp/utils/ParserException.h +++ b/include/plasp/utils/ParserException.h @@ -4,7 +4,7 @@ #include #include -#include +#include namespace plasp { @@ -20,18 +20,18 @@ namespace utils class ParserException: public std::exception { public: - explicit ParserException(const utils::Parser &parser) - : ParserException(parser, "unspecified parser error") + explicit ParserException(const StreamCoordinate &coordinate) + : ParserException(coordinate, "unspecified parser error") { } - explicit ParserException(const utils::Parser &parser, const char *message) - : ParserException(parser, static_cast(message)) + explicit ParserException(const StreamCoordinate &coordinate, const char *message) + : ParserException(coordinate, static_cast(message)) { } - explicit ParserException(const utils::Parser &parser, const std::string &message) - : m_coordinate{parser.coordinate()}, + explicit ParserException(const StreamCoordinate &coordinate, const std::string &message) + : m_coordinate{coordinate}, m_message{message}, m_plainMessage{m_coordinate.sectionName + ":" + std::to_string(m_coordinate.row) + ":" + std::to_string(m_coordinate.column) + " " + m_message} @@ -47,7 +47,7 @@ class ParserException: public std::exception return m_plainMessage.c_str(); } - const Parser::Coordinate &coordinate() const + const StreamCoordinate &coordinate() const { return m_coordinate; } @@ -58,7 +58,7 @@ class ParserException: public std::exception } private: - Parser::Coordinate m_coordinate; + StreamCoordinate m_coordinate; std::string m_message; std::string m_plainMessage; }; diff --git a/include/plasp/utils/ParserPolicy.h b/include/plasp/utils/ParserPolicy.h new file mode 100644 index 0000000..8532747 --- /dev/null +++ b/include/plasp/utils/ParserPolicy.h @@ -0,0 +1,62 @@ +#ifndef __PLASP__UTILS__PARSER_POLICY_H +#define __PLASP__UTILS__PARSER_POLICY_H + +#include + +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 diff --git a/include/plasp/utils/ParserTraits.h b/include/plasp/utils/ParserTraits.h new file mode 100644 index 0000000..e6c7afb --- /dev/null +++ b/include/plasp/utils/ParserTraits.h @@ -0,0 +1,363 @@ +#ifndef __PLASP__UTILS__PARSER_TRAITS_H +#define __PLASP__UTILS__PARSER_TRAITS_H + +#include +#include +#include + +namespace plasp +{ +namespace utils +{ +/* +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// ParserTraits +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ParserTraits +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ParserTraits +{ + public: + static std::string parse(Parser &parser); + static bool testAndReturn(Parser &parser, const std::string &value); + static bool testAndSkip(Parser &parser, const std::string &value); + static void expect(Parser &parser, const std::string &expectedValue); + static bool test(Parser &parser, const std::string &value); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ParserTraits +{ + public: + static char parse(Parser &parser); + static bool testAndReturn(Parser &parser, const char &value); + static bool testAndSkip(Parser &parser, const char &value); + static void expect(Parser &parser, const char &expectedValue); + static bool test(Parser &parser, const char &value); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ParserTraits +{ + public: + static uint64_t parse(Parser &parser); + static bool testAndReturn(Parser &parser, const uint64_t &value); + static bool testAndSkip(Parser &parser, const uint64_t &value); + static void expect(Parser &parser, const uint64_t &expectedValue); + static bool test(Parser &parser, const uint64_t &value); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ParserTraits +{ + public: + static int64_t parse(Parser &parser); + static bool testAndReturn(Parser &parser, const int64_t &value); + static bool testAndSkip(Parser &parser, const int64_t &value); + static void expect(Parser &parser, const int64_t &expectedValue); + static bool test(Parser &parser, const int64_t &value); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ParserTraits +{ + public: + static uint32_t parse(Parser &parser); + static bool testAndReturn(Parser &parser, const uint32_t &value); + static bool testAndSkip(Parser &parser, const uint32_t &value); + static void expect(Parser &parser, const uint32_t &expectedValue); + static bool test(Parser &parser, const uint32_t &value); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ParserTraits +{ + public: + static int32_t parse(Parser &parser); + static bool testAndReturn(Parser &parser, const int32_t &value); + static bool testAndSkip(Parser &parser, const int32_t &value); + static void expect(Parser &parser, const int32_t &expectedValue); + static bool test(Parser &parser, const int32_t &value); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ParserTraits +{ + public: + static bool parse(Parser &parser); + static bool testAndReturn(Parser &parser, const bool &value); + static bool testAndSkip(Parser &parser, const bool &value); + static void expect(Parser &parser, const bool &expectedValue); + static bool test(Parser &parser, const bool &value); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::testAndReturn(Parser &parser, const Type &value) +{ + const auto position = parser.position(); + + const auto result = test(parser, value); + + parser.seek(position); + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::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 +void Parser::expect(const Type &expectedValue) +{ + if (testAndSkip(parser, expectedValue)) + return; + + std::stringstream message; + message << "unexpected value, expected “" << expectedValue << "”"; + + throw ParserException(parser.coordinate(), message.str()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +std::string ParserTraits::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(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 +char ParserTraits::parse(Parser &parser) +{ + const auto value = parser.currentCharacter(); + + parser.advance(); + + return value; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +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 +int64_t ParserTraits::parse(Parser &parser) +{ + parser.skipWhiteSpace(); + + bool positive = parser.template testAndSkip('+') || !parser.template testAndSkip('-'); + + const auto value = parseIntegerBody(parser); + + return (positive ? value : -value); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +uint64_t ParserTraits::parse(Parser &parser) +{ + parser.skipWhiteSpace(); + + if (parser.currentCharacter() == '-') + throw ParserException(parser.coordinate(), "expected unsigned integer, got signed one"); + + return parseIntegerBody(parser); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +int32_t ParserTraits::parse(Parser &parser) +{ + return static_cast(ParserTraits::parse(parser)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +uint32_t ParserTraits::parse(Parser &parser) +{ + return static_cast(ParserTraits::parse(parser)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::parse(Parser &parser) +{ + parser.skipWhiteSpace(); + + if (parser.template testAndSkip('0')) + return false; + + if (parser.template testAndSkip('1')) + return true; + + throw ParserException(parser.coordinate(), "could not parse Boolean value"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::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(parser.currentCharacter()); + + if (character != expectedCharacter) + return true; + + parser.advance(); + + return false; + }); + + return (match == expectedValue.cend()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::test(Parser &parser, const char &expectedValue) +{ + const auto result = (parser.currentCharacter() == expectedValue); + + parser.advance(); + + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::test(Parser &parser, const int64_t &expectedValue) +{ + const auto value = parse(parser); + + return (value == expectedValue); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::test(Parser &parser, const uint64_t &expectedValue) +{ + const auto value = parse(parser); + + return (value == expectedValue); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::test(Parser &parser, const int32_t &expectedValue) +{ + return ParserTraits::test(parser, static_cast(expectedValue)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +bool ParserTraits::test(Parser &parser, const uint32_t &expectedValue) +{ + return ParserTraits::test(parser, static_cast(expectedValue)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +*/ +} +} + +#endif diff --git a/include/plasp/utils/Stream.h b/include/plasp/utils/Stream.h new file mode 100644 index 0000000..262783b --- /dev/null +++ b/include/plasp/utils/Stream.h @@ -0,0 +1,85 @@ +#ifndef __PLASP__UTILS__STREAM_H +#define __PLASP__UTILS__STREAM_H + +#include +#include +#include +#include + +#include + +#include +#include + +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 m_delimiters; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/include/plasp/pddl/Identifier.h b/include/plasp/utils/StreamCoordinate.h similarity index 53% rename from include/plasp/pddl/Identifier.h rename to include/plasp/utils/StreamCoordinate.h index e1abc92..341063a 100644 --- a/include/plasp/pddl/Identifier.h +++ b/include/plasp/utils/StreamCoordinate.h @@ -1,28 +1,25 @@ -#ifndef __PLASP__PDDL__IDENTIFIER_H -#define __PLASP__PDDL__IDENTIFIER_H +#ifndef __PLASP__UTILS__STREAM_COORDINATE_H +#define __PLASP__UTILS__STREAM_COORDINATE_H -#include +#include namespace plasp { -namespace pddl +namespace utils { //////////////////////////////////////////////////////////////////////////////////////////////////// // -// Identifier +// StreamCoordinate // //////////////////////////////////////////////////////////////////////////////////////////////////// -const auto isIdentifier = - [](const auto character) - { - return character != '?' - && character != '(' - && character != ')' - && character != ';' - && std::isgraph(character); - }; +struct StreamCoordinate +{ + std::string sectionName; + size_t row; + size_t column; +}; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/plasp/pddl/Action.cpp b/src/plasp/pddl/Action.cpp index 52af78d..2be27d2 100644 --- a/src/plasp/pddl/Action.cpp +++ b/src/plasp/pddl/Action.cpp @@ -5,10 +5,8 @@ #include #include #include -#include #include #include -#include namespace plasp { @@ -23,31 +21,33 @@ namespace pddl void Action::parseDeclaration(Context &context, Domain &domain) { + auto &parser = context.parser; + auto action = std::make_unique(Action()); - action->m_name = context.parser.parseIdentifier(isIdentifier); + action->m_name = parser.parseIdentifier(); - context.parser.expect(":parameters"); - context.parser.expect("("); + parser.expect(":parameters"); + parser.expect("("); ExpressionContext expressionContext(domain, action->m_parameters); // Read parameters expressions::Variable::parseTypedDeclarations(context, expressionContext); - context.parser.expect(")"); + parser.expect(")"); // Parse preconditions and effects - while (context.parser.currentCharacter() != ')') + while (!parser.testAndReturn(')')) { - context.parser.expect(":"); + parser.expect(":"); - if (context.parser.probeIdentifier("precondition", isIdentifier)) + if (parser.testIdentifierAndSkip("precondition")) action->m_precondition = parsePreconditionExpression(context, expressionContext); - else if (context.parser.probeIdentifier("effect", isIdentifier)) + else if (parser.testIdentifierAndSkip("effect")) action->m_effect = parseEffectExpression(context, expressionContext); - context.parser.skipWhiteSpace(); + parser.skipWhiteSpace(); } // Store new action diff --git a/src/plasp/pddl/Description.cpp b/src/plasp/pddl/Description.cpp index 3ba5578..8d2cd1e 100644 --- a/src/plasp/pddl/Description.cpp +++ b/src/plasp/pddl/Description.cpp @@ -44,7 +44,7 @@ Description Description::fromStream(std::istream &istream) { Description description; - description.m_context.parser.readStream("std::cin", istream); + description.m_context.parser.read("std::cin", istream); description.parse(); return description; @@ -56,7 +56,7 @@ Description Description::fromFile(const std::string &path) { Description description; - description.m_context.parser.readFile(path); + description.m_context.parser.read(path); description.parse(); return description; @@ -73,7 +73,7 @@ Description Description::fromFiles(const std::vector &paths) std::for_each(paths.cbegin(), paths.cend(), [&](const auto &path) { - description.m_context.parser.readFile(path); + description.m_context.parser.read(path); }); description.parse(); @@ -126,7 +126,6 @@ void Description::parse() { auto &parser = m_context.parser; - parser.setCaseSensitive(false); parser.removeComments(";", "\n", false); // First, determine the locations of domain and problem @@ -155,7 +154,7 @@ void Description::findSections() parser.skipWhiteSpace(); - while (!parser.atEndOfStream()) + while (!parser.atEnd()) { const auto position = parser.position(); @@ -163,20 +162,20 @@ void Description::findSections() parser.expect("define"); parser.expect("("); - if (parser.probe("domain")) + if (parser.testAndSkip("domain")) { 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; parser.seek(position); m_domain->findSections(); } - else if (m_context.parser.probe("problem")) + else if (m_context.parser.testAndSkip("problem")) { 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(m_context, *m_domain)); @@ -188,7 +187,7 @@ void Description::findSections() else { const auto sectionIdentifier = parser.parse(); - throw utils::ParserException(parser, "unknown PDDL section “" + sectionIdentifier + "”"); + throw utils::ParserException(parser.coordinate(), "unknown PDDL section “" + sectionIdentifier + "”"); } m_context.parser.skipWhiteSpace(); diff --git a/src/plasp/pddl/Domain.cpp b/src/plasp/pddl/Domain.cpp index b8e9ec9..f8e8513 100644 --- a/src/plasp/pddl/Domain.cpp +++ b/src/plasp/pddl/Domain.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -43,7 +42,7 @@ void Domain::findSections() parser.expect("("); parser.expect("domain"); - m_name = m_context.parser.parseIdentifier(isIdentifier); + m_name = m_context.parser.parseIdentifier(); parser.expect(")"); @@ -53,7 +52,7 @@ void Domain::findSections() if (unique && sectionPosition != -1) { parser.seek(value); - throw utils::ParserException(parser, "only one “:" + sectionName + "” section allowed"); + throw utils::ParserException(parser.coordinate(), "only one “:" + sectionName + "” section allowed"); } sectionPosition = value; @@ -72,38 +71,38 @@ void Domain::findSections() const auto sectionIdentifierPosition = parser.position(); // 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); - else if (parser.probeIdentifier("types", isIdentifier)) + else if (parser.testIdentifierAndSkip("types")) setSectionPosition("types", m_typesPosition, position, true); - else if (parser.probeIdentifier("constants", isIdentifier)) + else if (parser.testIdentifierAndSkip("constants")) setSectionPosition("constants", m_constantsPosition, position, true); - else if (parser.probeIdentifier("predicates", isIdentifier)) + else if (parser.testIdentifierAndSkip("predicates")) setSectionPosition("predicates", m_predicatesPosition, position, true); - else if (parser.probeIdentifier("action", isIdentifier)) + else if (parser.testIdentifierAndSkip("action")) { m_actionPositions.emplace_back(-1); setSectionPosition("action", m_actionPositions.back(), position); } - else if (parser.probeIdentifier("functions", isIdentifier) - || parser.probeIdentifier("constraints", isIdentifier) - || parser.probeIdentifier("durative-action", isIdentifier) - || parser.probeIdentifier("derived", isIdentifier)) + else if (parser.testIdentifierAndSkip("functions") + || parser.testIdentifierAndSkip("constraints") + || parser.testIdentifierAndSkip("durative-action") + || parser.testIdentifierAndSkip("derived")) { 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); } else { - const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); + const auto sectionIdentifier = parser.parseIdentifier(); 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 @@ -340,7 +339,7 @@ void Domain::parseTypeSection() while (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); diff --git a/src/plasp/pddl/Expression.cpp b/src/plasp/pddl/Expression.cpp index b3a3d04..af9b59b 100644 --- a/src/plasp/pddl/Expression.cpp +++ b/src/plasp/pddl/Expression.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -49,12 +48,12 @@ ExpressionPointer parsePreconditionExpression(Context &context, const auto expressionIdentifierPosition = parser.position(); - if (parser.probeIdentifier("forall", isIdentifier) - || parser.probeIdentifier("preference", isIdentifier)) + if (parser.testIdentifierAndSkip("forall") + || parser.testIdentifierAndSkip("preference")) { // TODO: refactor parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); parser.seek(position); return expressions::Unsupported::parse(context); @@ -89,32 +88,32 @@ ExpressionPointer parseExpression(Context &context, ExpressionContext &expressio const auto expressionIdentifierPosition = parser.position(); - if (parser.probeIdentifier("exists", isIdentifier) - || parser.probeIdentifier("forall", isIdentifier) - || parser.probeIdentifier("-", isIdentifier) - || parser.probeIdentifier("=", isIdentifier) - || parser.probeIdentifier("*", isIdentifier) - || parser.probeIdentifier("+", isIdentifier) - || parser.probeIdentifier("-", isIdentifier) - || parser.probeIdentifier("/", isIdentifier) - || parser.probeIdentifier(">", isIdentifier) - || parser.probeIdentifier("<", isIdentifier) - || parser.probeIdentifier("=", isIdentifier) - || parser.probeIdentifier(">=", isIdentifier) - || parser.probeIdentifier("<=", isIdentifier)) + if (parser.testIdentifierAndSkip("exists") + || parser.testIdentifierAndSkip("forall") + || parser.testIdentifierAndSkip("-") + || parser.testIdentifierAndSkip("=") + || parser.testIdentifierAndSkip("*") + || parser.testIdentifierAndSkip("+") + || parser.testIdentifierAndSkip("-") + || parser.testIdentifierAndSkip("/") + || parser.testIdentifierAndSkip(">") + || parser.testIdentifierAndSkip("<") + || parser.testIdentifierAndSkip("=") + || parser.testIdentifierAndSkip(">=") + || parser.testIdentifierAndSkip("<=")) { parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); parser.seek(position); return expressions::Unsupported::parse(context); } parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); 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(); - if (parser.probeIdentifier("forall", isIdentifier) - || parser.probeIdentifier("when", isIdentifier)) + if (parser.testIdentifierAndSkip("forall") + || parser.testIdentifierAndSkip("when")) { parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); parser.seek(position); return expressions::Unsupported::parse(context); @@ -168,37 +167,39 @@ ExpressionPointer parseEffectBodyExpression(Context &context, ExpressionContext const auto expressionIdentifierPosition = parser.position(); - if (parser.probeIdentifier("=", isIdentifier) - || parser.probeIdentifier("assign", isIdentifier) - || parser.probeIdentifier("scale-up", isIdentifier) - || parser.probeIdentifier("scale-down", isIdentifier) - || parser.probeIdentifier("increase", isIdentifier) - || parser.probeIdentifier("decrease", isIdentifier)) + if (parser.testIdentifierAndSkip("=") + || parser.testIdentifierAndSkip("assign") + || parser.testIdentifierAndSkip("scale-up") + || parser.testIdentifierAndSkip("scale-down") + || parser.testIdentifierAndSkip("increase") + || parser.testIdentifierAndSkip("decrease")) { parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); parser.seek(position); return expressions::Unsupported::parse(context); } parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); 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) { + auto &parser = context.parser; + ExpressionPointer expression; if ((expression = expressions::Predicate::parse(context, expressionContext))) 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(); - if (!parser.probe("(")) + if (!parser.testAndSkip("(")) return nullptr; const auto expressionIdentifierPosition = parser.position(); - if (parser.probeIdentifier("=", isIdentifier)) + if (parser.testIdentifierAndSkip("=")) { parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); parser.seek(position); return expressions::Unsupported::parse(context); diff --git a/src/plasp/pddl/InitialState.cpp b/src/plasp/pddl/InitialState.cpp index e767249..cab3750 100644 --- a/src/plasp/pddl/InitialState.cpp +++ b/src/plasp/pddl/InitialState.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -46,20 +45,20 @@ std::unique_ptr InitialState::parseDeclaration(Context &context, const auto expressionIdentifierPosition = parser.position(); - if (parser.probeIdentifier("=", isIdentifier)) + if (parser.testIdentifierAndSkip("=")) { parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); parser.seek(position); return expressions::Unsupported::parse(context); } parser.seek(expressionIdentifierPosition); - const auto expressionIdentifier = parser.parseIdentifier(isIdentifier); + const auto expressionIdentifier = parser.parseIdentifier(); 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(); diff --git a/src/plasp/pddl/Problem.cpp b/src/plasp/pddl/Problem.cpp index 0b58e1c..90b87e2 100644 --- a/src/plasp/pddl/Problem.cpp +++ b/src/plasp/pddl/Problem.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -43,7 +42,7 @@ void Problem::findSections() parser.expect("("); parser.expect("problem"); - m_name = parser.parseIdentifier(isIdentifier); + m_name = parser.parseIdentifier(); parser.expect(")"); @@ -53,7 +52,7 @@ void Problem::findSections() if (unique && sectionPosition != -1) { parser.seek(value); - throw utils::ParserException(parser, "only one “:" + sectionName + "” section allowed"); + throw utils::ParserException(parser.coordinate(), "only one “:" + sectionName + "” section allowed"); } sectionPosition = value; @@ -71,34 +70,34 @@ void Problem::findSections() const auto sectionIdentifierPosition = parser.position(); // TODO: check order of the sections - if (parser.probeIdentifier("domain", isIdentifier)) + if (parser.testIdentifierAndSkip("domain")) setSectionPosition("domain", m_domainPosition, position, true); - else if (parser.probeIdentifier("requirements", isIdentifier)) + else if (parser.testIdentifierAndSkip("requirements")) setSectionPosition("requirements", m_requirementsPosition, position, true); - else if (parser.probeIdentifier("objects", isIdentifier)) + else if (parser.testIdentifierAndSkip("objects")) setSectionPosition("objects", m_objectsPosition, position, true); - else if (parser.probeIdentifier("init", isIdentifier)) + else if (parser.testIdentifierAndSkip("init")) setSectionPosition("init", m_initialStatePosition, position, true); - else if (parser.probeIdentifier("goal", isIdentifier)) + else if (parser.testIdentifierAndSkip("goal")) setSectionPosition("goal", m_goalPosition, position, true); - else if (parser.probeIdentifier("constraints", isIdentifier) - || parser.probeIdentifier("metric", isIdentifier) - || parser.probeIdentifier("length", isIdentifier)) + else if (parser.testIdentifierAndSkip("constraints") + || parser.testIdentifierAndSkip("metric") + || parser.testIdentifierAndSkip("length")) { 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); } else { - const auto sectionIdentifier = parser.parseIdentifier(isIdentifier); + const auto sectionIdentifier = parser.parseIdentifier(); 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 @@ -201,10 +200,10 @@ void Problem::parseDomainSection() parser.skipWhiteSpace(); - const auto domainName = parser.parseIdentifier(isIdentifier); + const auto domainName = parser.parseIdentifier(); 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(")"); } diff --git a/src/plasp/pddl/Requirement.cpp b/src/plasp/pddl/Requirement.cpp index 774d70e..74a7994 100644 --- a/src/plasp/pddl/Requirement.cpp +++ b/src/plasp/pddl/Requirement.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -84,17 +83,19 @@ Requirement::Requirement(Requirement::Type type) 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); 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; 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); } diff --git a/src/plasp/pddl/expressions/Constant.cpp b/src/plasp/pddl/expressions/Constant.cpp index 8ae4d8d..d092907 100644 --- a/src/plasp/pddl/expressions/Constant.cpp +++ b/src/plasp/pddl/expressions/Constant.cpp @@ -37,7 +37,7 @@ ConstantPointer Constant::parseDeclaration(Context &context) auto constant = std::make_unique(Constant()); - constant->m_name = context.parser.parseIdentifier(isIdentifier); + constant->m_name = context.parser.parseIdentifier(); BOOST_ASSERT(constant->m_name != "-"); @@ -71,7 +71,7 @@ void Constant::parseTypedDeclaration(Context &context, Domain &domain, Constants context.parser.skipWhiteSpace(); // Check for typing information - if (!context.parser.probe('-')) + if (!context.parser.testAndSkip('-')) return; // If existing, parse and store parent type @@ -113,7 +113,7 @@ void Constant::parseTypedDeclarations(Context &context, Domain &domain) domain.checkRequirement(Requirement::Type::Typing); // If no types are given, check that typing is not a requirement 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); // If no types are given, check that typing is not a requirement 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) { - 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()); if (constant != nullptr) 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) { - 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()); @@ -177,7 +181,7 @@ Constant *Constant::parseAndFind(Context &context, const Problem &problem) if (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"); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/plasp/pddl/expressions/Imply.cpp b/src/plasp/pddl/expressions/Imply.cpp index b425c0c..c9d86ca 100644 --- a/src/plasp/pddl/expressions/Imply.cpp +++ b/src/plasp/pddl/expressions/Imply.cpp @@ -13,6 +13,7 @@ namespace expressions // //////////////////////////////////////////////////////////////////////////////////////////////////// +// TODO: make static character string literal const std::string Imply::Identifier = "imply"; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/plasp/pddl/expressions/Predicate.cpp b/src/plasp/pddl/expressions/Predicate.cpp index 6438992..ed1dbe2 100644 --- a/src/plasp/pddl/expressions/Predicate.cpp +++ b/src/plasp/pddl/expressions/Predicate.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -34,13 +33,13 @@ PredicatePointer Predicate::parse(Context &context, ExpressionContext &expressio const auto position = parser.position(); - if (!parser.probe("(")) + if (!parser.testAndSkip("(")) { parser.seek(position); return nullptr; } - const auto predicateName = parser.parseIdentifier(isIdentifier); + const auto predicateName = parser.parseIdentifier(); const auto &predicates = expressionContext.domain.predicates(); 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(); - if (!parser.probe("(")) + if (!parser.testAndSkip("(")) { parser.seek(position); return nullptr; } - const auto predicateName = parser.parseIdentifier(isIdentifier); + const auto predicateName = parser.parseIdentifier(); const auto &predicates = problem.domain().predicates(); 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; - context.parser.skipWhiteSpace(); + parser.skipWhiteSpace(); - while (context.parser.currentCharacter() != ')') + while (parser.currentCharacter() != ')') { - if (context.parser.currentCharacter() == '?') - throw utils::ParserException(context.parser, "variables not allowed in this context"); + if (parser.currentCharacter() == '?') + throw utils::ParserException(parser.coordinate(), "variables not allowed in this context"); // Parse objects and constants const auto *constant = Constant::parseAndFind(context, problem); diff --git a/src/plasp/pddl/expressions/PredicateDeclaration.cpp b/src/plasp/pddl/expressions/PredicateDeclaration.cpp index 643026f..f87873c 100644 --- a/src/plasp/pddl/expressions/PredicateDeclaration.cpp +++ b/src/plasp/pddl/expressions/PredicateDeclaration.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -33,7 +32,7 @@ void PredicateDeclaration::parse(Context &context, Domain &domain) auto predicate = std::make_unique(PredicateDeclaration()); - predicate->m_name = context.parser.parseIdentifier(isIdentifier); + predicate->m_name = context.parser.parseIdentifier(); // Flag predicate as correctly declared in the types section predicate->setDeclared(); diff --git a/src/plasp/pddl/expressions/PrimitiveType.cpp b/src/plasp/pddl/expressions/PrimitiveType.cpp index 850300a..0486978 100644 --- a/src/plasp/pddl/expressions/PrimitiveType.cpp +++ b/src/plasp/pddl/expressions/PrimitiveType.cpp @@ -43,7 +43,7 @@ void PrimitiveType::parseDeclaration(Context &context, Domain &domain) 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 &primitiveType) @@ -76,7 +76,7 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain) context.parser.skipWhiteSpace(); // Check for type inheritance - if (!context.parser.probe('-')) + if (!context.parser.testAndSkip('-')) return; domain.checkRequirement(Requirement::Type::Typing); @@ -102,14 +102,16 @@ void PrimitiveType::parseTypedDeclaration(Context &context, Domain &domain) PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain) { + auto &parser = context.parser; + auto &types = domain.types(); - context.parser.skipWhiteSpace(); + parser.skipWhiteSpace(); - const auto typeName = context.parser.parseIdentifier(isIdentifier); + const auto typeName = parser.parseIdentifier(); 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 &primitiveType) @@ -122,11 +124,11 @@ PrimitiveType *PrimitiveType::parseAndFind(Context &context, Domain &domain) // Only "object" is allowed as an implicit type 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(typeName)); } 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(); } diff --git a/src/plasp/pddl/expressions/Unsupported.cpp b/src/plasp/pddl/expressions/Unsupported.cpp index 19181bc..ef00a0d 100644 --- a/src/plasp/pddl/expressions/Unsupported.cpp +++ b/src/plasp/pddl/expressions/Unsupported.cpp @@ -1,6 +1,5 @@ #include -#include #include namespace plasp @@ -24,9 +23,9 @@ UnsupportedPointer Unsupported::parse(Context &context) parser.expect("("); - 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); diff --git a/src/plasp/pddl/expressions/Variable.cpp b/src/plasp/pddl/expressions/Variable.cpp index 7a7ed28..115e08d 100644 --- a/src/plasp/pddl/expressions/Variable.cpp +++ b/src/plasp/pddl/expressions/Variable.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -36,13 +35,15 @@ Variable::Variable() void Variable::parseDeclaration(Context &context, Variables ¶meters) { - context.parser.skipWhiteSpace(); + auto &parser = context.parser; - context.parser.expect("?"); + parser.skipWhiteSpace(); + + parser.expect("?"); auto variable = std::make_unique(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 const auto match = std::find_if(parameters.cbegin(), parameters.cend(), @@ -52,7 +53,7 @@ void Variable::parseDeclaration(Context &context, Variables ¶meters) }); 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 variable->setDirty(); @@ -75,7 +76,7 @@ void Variable::parseTypedDeclaration(Context &context, ExpressionContext &expres parser.skipWhiteSpace(); // Check if the variable has a type declaration - if (!parser.probe('-')) + if (!parser.testAndSkip('-')) return; const auto setType = @@ -132,18 +133,20 @@ void Variable::parseTypedDeclarations(Context &context, ExpressionContext &expre expressionContext.checkRequirement(Requirement::Type::Typing); // If no types are given, check that typing is not a requirement 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) { - context.parser.skipWhiteSpace(); + auto &parser = context.parser; - context.parser.expect("?"); + parser.skipWhiteSpace(); - const auto variableName = context.parser.parseIdentifier(isIdentifier); + parser.expect("?"); + + const auto variableName = parser.parseIdentifier(); const auto &variables = expressionContext.parameters; @@ -154,7 +157,7 @@ const Variable *Variable::parseAndFind(Context &context, const ExpressionContext }); 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(); } diff --git a/src/plasp/sas/AssignedVariable.cpp b/src/plasp/sas/AssignedVariable.cpp index 801b00c..8a93e59 100644 --- a/src/plasp/sas/AssignedVariable.cpp +++ b/src/plasp/sas/AssignedVariable.cpp @@ -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; @@ -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; diff --git a/src/plasp/sas/AxiomRule.cpp b/src/plasp/sas/AxiomRule.cpp index d18c2eb..f015706 100644 --- a/src/plasp/sas/AxiomRule.cpp +++ b/src/plasp/sas/AxiomRule.cpp @@ -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("begin_rule"); diff --git a/src/plasp/sas/Description.cpp b/src/plasp/sas/Description.cpp index 615c645..f1523fa 100644 --- a/src/plasp/sas/Description.cpp +++ b/src/plasp/sas/Description.cpp @@ -28,10 +28,8 @@ Description::Description() //////////////////////////////////////////////////////////////////////////////////////////////////// -Description Description::fromParser(utils::Parser &&parser) +Description Description::fromParser(utils::Parser<> &&parser) { - parser.setCaseSensitive(true); - Description description; description.parseContent(parser); @@ -42,8 +40,8 @@ Description Description::fromParser(utils::Parser &&parser) Description Description::fromStream(std::istream &istream) { - utils::Parser parser; - parser.readStream("std::cin", istream); + utils::Parser<> parser; + parser.read("std::cin", istream); Description description; description.parseContent(parser); @@ -58,8 +56,8 @@ Description Description::fromFile(const boost::filesystem::path &path) if (!boost::filesystem::is_regular_file(path)) throw std::runtime_error("File does not exist: “" + path.string() + "”"); - utils::Parser parser; - parser.readFile(path); + utils::Parser<> parser; + parser.read(path); Description description; 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); parseMetricSection(parser); @@ -168,27 +166,27 @@ void Description::parseContent(utils::Parser &parser) parser.skipWhiteSpace(); - if (!parser.atEndOfStream()) - throw utils::ParserException(parser, "expected end of SAS description (perhaps, input contains two SAS descriptions?)"); + if (!parser.atEnd()) + 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("begin_version"); const auto formatVersion = parser.parse(); 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("end_version"); } //////////////////////////////////////////////////////////////////////////////////////////////////// -void Description::parseMetricSection(utils::Parser &parser) +void Description::parseMetricSection(utils::Parser<> &parser) { parser.expect("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(); 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(); 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::fromSAS(parser, m_variables)); } //////////////////////////////////////////////////////////////////////////////////////////////////// -void Description::parseGoalSection(utils::Parser &parser) +void Description::parseGoalSection(utils::Parser<> &parser) { m_goal = std::make_unique(Goal::fromSAS(parser, m_variables)); } //////////////////////////////////////////////////////////////////////////////////////////////////// -void Description::parseOperatorSection(utils::Parser &parser) +void Description::parseOperatorSection(utils::Parser<> &parser) { const auto numberOfOperators = parser.parse(); 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(); m_axiomRules.reserve(numberOfAxiomRules); diff --git a/src/plasp/sas/Effect.cpp b/src/plasp/sas/Effect.cpp index 9f39e1f..0fe21e5 100644 --- a/src/plasp/sas/Effect.cpp +++ b/src/plasp/sas/Effect.cpp @@ -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; diff --git a/src/plasp/sas/Goal.cpp b/src/plasp/sas/Goal.cpp index 69ddec1..0db7a71 100644 --- a/src/plasp/sas/Goal.cpp +++ b/src/plasp/sas/Goal.cpp @@ -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; diff --git a/src/plasp/sas/InitialState.cpp b/src/plasp/sas/InitialState.cpp index 9130a07..60b8f03 100644 --- a/src/plasp/sas/InitialState.cpp +++ b/src/plasp/sas/InitialState.cpp @@ -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; diff --git a/src/plasp/sas/MutexGroup.cpp b/src/plasp/sas/MutexGroup.cpp index 69b08b9..3ee36be 100644 --- a/src/plasp/sas/MutexGroup.cpp +++ b/src/plasp/sas/MutexGroup.cpp @@ -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; @@ -29,7 +29,7 @@ MutexGroup MutexGroup::fromSAS(utils::Parser &parser, const Variables &variables mutexGroup.m_facts.emplace_back(Fact::fromSAS(parser, variables)); if (mutexGroup.m_facts[j].value() == Value::None) - throw utils::ParserException(parser, "mutex groups must not contain values"); + throw utils::ParserException(parser.coordinate(), "mutex groups must not contain values"); } parser.expect("end_mutex_group"); diff --git a/src/plasp/sas/Operator.cpp b/src/plasp/sas/Operator.cpp index 3d390d7..83bbbcc 100644 --- a/src/plasp/sas/Operator.cpp +++ b/src/plasp/sas/Operator.cpp @@ -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_; diff --git a/src/plasp/sas/Predicate.cpp b/src/plasp/sas/Predicate.cpp index 7ac6595..d4b802e 100644 --- a/src/plasp/sas/Predicate.cpp +++ b/src/plasp/sas/Predicate.cpp @@ -18,7 +18,7 @@ namespace sas // //////////////////////////////////////////////////////////////////////////////////////////////////// -Predicate Predicate::fromSAS(utils::Parser &parser) +Predicate Predicate::fromSAS(utils::Parser<> &parser) { Predicate predicate; @@ -31,11 +31,12 @@ Predicate Predicate::fromSAS(utils::Parser &parser) while (true) { // Parse arguments until reaching newline - parser.skipWhiteSpace( + // TODO: reimplement + /*parser.skipWhiteSpace( [&](const auto character) { return character != '\n' && std::isspace(character); - }); + });*/ if (parser.currentCharacter() == '\n') break; @@ -46,7 +47,7 @@ Predicate Predicate::fromSAS(utils::Parser &parser) } 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; diff --git a/src/plasp/sas/Value.cpp b/src/plasp/sas/Value.cpp index 049c64a..346e29e 100644 --- a/src/plasp/sas/Value.cpp +++ b/src/plasp/sas/Value.cpp @@ -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(); @@ -75,12 +75,12 @@ Value Value::fromSAS(utils::Parser &parser) else if (sasSign == "NegatedAtom") value.m_sign = Value::Sign::Negative; else - throw utils::ParserException(parser, "invalid value sign “" + sasSign + "”"); + throw utils::ParserException(parser.coordinate(), "invalid value sign “" + sasSign + "”"); try { parser.skipWhiteSpace(); - value.m_name = parser.getLine(); + value.m_name = parser.parseLine(); // Remove trailing () if (value.m_name.find("()") != std::string::npos) @@ -91,7 +91,7 @@ Value Value::fromSAS(utils::Parser &parser) } 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; @@ -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(); @@ -107,7 +107,7 @@ const Value &Value::referenceFromSAS(utils::Parser &parser, const Variable &vari return Value::Any; if (valueID < 0 || static_cast(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]; } diff --git a/src/plasp/sas/Variable.cpp b/src/plasp/sas/Variable.cpp index 6c1e8c9..7f90ec2 100644 --- a/src/plasp/sas/Variable.cpp +++ b/src/plasp/sas/Variable.cpp @@ -24,7 +24,7 @@ Variable::Variable() //////////////////////////////////////////////////////////////////////////////////////////////////// -Variable Variable::fromSAS(utils::Parser &parser) +Variable Variable::fromSAS(utils::Parser<> &parser) { Variable variable; @@ -42,7 +42,7 @@ Variable Variable::fromSAS(utils::Parser &parser) // values are only allowed at the end if (j < numberOfValues - 1 && variable.m_values[j] == Value::None) - throw utils::ParserException(parser, " value must be the last value of a variable"); + throw utils::ParserException(parser.coordinate(), " value must be the last value of a variable"); } parser.expect("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(); 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]; } diff --git a/src/plasp/sas/VariableTransition.cpp b/src/plasp/sas/VariableTransition.cpp index 143c753..0c9ee5d 100644 --- a/src/plasp/sas/VariableTransition.cpp +++ b/src/plasp/sas/VariableTransition.cpp @@ -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; diff --git a/src/plasp/utils/Logger.cpp b/src/plasp/utils/Logger.cpp index 8702597..ea0470f 100644 --- a/src/plasp/utils/Logger.cpp +++ b/src/plasp/utils/Logger.cpp @@ -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 << 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) return; if (m_warningLevel == WarningLevel::Error) - throw ParserException(parser, message); - - const auto coordinate = parser.coordinate(); + throw ParserException(coordinate, message); m_errorStream << Format(Color::White, FontWeight::Bold) << coordinate.sectionName << ":" diff --git a/src/plasp/utils/Parser.cpp b/src/plasp/utils/Parser.cpp deleted file mode 100644 index 607abb2..0000000 --- a/src/plasp/utils/Parser.cpp +++ /dev/null @@ -1,628 +0,0 @@ -#include - -#include -#include - -#include - -#include - -namespace plasp -{ -namespace utils -{ - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Parser -// -//////////////////////////////////////////////////////////////////////////////////////////////////// - -const std::istreambuf_iterator Parser::EndOfFile = std::istreambuf_iterator(); - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -Parser::Parser() -: m_isCaseSensitive{true} -{ - std::setlocale(LC_NUMERIC, "C"); - - // Don’t 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() -{ - 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(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(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(const std::string &expectedValue) -{ - if (!probe(expectedValue)) - throw ParserException(*this, "expected “" + expectedValue + "”"); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -char Parser::parse() -{ - const auto value = currentCharacter(); - - advance(); - - return value; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -bool Parser::probe(const char &expectedValue) -{ - if (currentCharacter() != expectedValue) - return false; - - advance(); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -void Parser::expect(const char &expectedValue) -{ - if (!probe(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() -{ - skipWhiteSpace(); - - bool positive = probe('+') || !probe('-'); - - const auto value = parseIntegerBody(); - - return (positive ? value : -value); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -uint64_t Parser::parse() -{ - skipWhiteSpace(); - - if (currentCharacter() == '-') - throw ParserException(*this, "expected unsigned integer, got signed one"); - - return parseIntegerBody(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -bool Parser::probe(const int64_t &expectedValue) -{ - const auto previousPosition = position(); - const auto value = parse(); - - if (value == expectedValue) - return true; - - seek(previousPosition); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -bool Parser::probe(const uint64_t &expectedValue) -{ - const auto previousPosition = position(); - const auto value = parse(); - - if (value == expectedValue) - return true; - - seek(previousPosition); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -void Parser::expect(const int64_t &expectedValue) -{ - if (!probe(expectedValue)) - throw ParserException(*this, "expected “" + std::to_string(expectedValue) + "”"); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -void Parser::expect(const uint64_t &expectedValue) -{ - if (!probe(expectedValue)) - throw ParserException(*this, "expected “" + std::to_string(expectedValue) + "”"); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -int32_t Parser::parse() -{ - return static_cast(parse()); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -uint32_t Parser::parse() -{ - return static_cast(parse()); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -bool Parser::probe(const int32_t &expectedValue) -{ - return probe(static_cast(expectedValue)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -bool Parser::probe(const uint32_t &expectedValue) -{ - return probe(static_cast(expectedValue)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -void Parser::expect(const int32_t &expectedValue) -{ - expect(static_cast(expectedValue)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -void Parser::expect(const uint32_t &expectedValue) -{ - expect(static_cast(expectedValue)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -bool Parser::parse() -{ - skipWhiteSpace(); - - if (probe('0')) - return false; - - if (probe('1')) - return true; - - throw ParserException(*this, "could not parse Boolean value"); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -void Parser::expect(const bool &expectedValue) -{ - const auto value = parse(); - - 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(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); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -} -} diff --git a/src/plasp/utils/Stream.cpp b/src/plasp/utils/Stream.cpp new file mode 100644 index 0000000..5c196ae --- /dev/null +++ b/src/plasp/utils/Stream.cpp @@ -0,0 +1,162 @@ +#include + +#include + +namespace plasp +{ +namespace utils +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Stream +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +Stream::Stream() +{ + std::setlocale(LC_NUMERIC, "C"); + + // Don’t 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); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/tests/TestUtils.cpp b/tests/TestUtils.cpp index 07d48dc..f0e7e37 100644 --- a/tests/TestUtils.cpp +++ b/tests/TestUtils.cpp @@ -9,9 +9,10 @@ TEST(UtilsTests, ParseSimple) { 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(), "identifier"); ASSERT_EQ(p.parse(), 5u); @@ -31,7 +32,7 @@ TEST(UtilsTests, ParseSimple) TEST(UtilsTests, ParseUnsignedNumbers) { std::stringstream s("100 200 -300 -400"); - plasp::utils::Parser p("input", s); + plasp::utils::Parser<> p("input", s); ASSERT_EQ(p.parse(), 100); ASSERT_EQ(p.parse(), 200u); @@ -44,13 +45,13 @@ TEST(UtilsTests, ParseUnsignedNumbers) TEST(UtilsTests, ParseEndOfFile) { std::stringstream s1("test"); - plasp::utils::Parser p1("input", s1); + plasp::utils::Parser<> p1("input", s1); ASSERT_NO_THROW(p1.expect("test")); ASSERT_THROW(p1.parse(), plasp::utils::ParserException); std::stringstream s2("test1 test2 test3"); - plasp::utils::Parser p2("input", s2); + plasp::utils::Parser<> p2("input", s2); ASSERT_NO_THROW(p2.expect("test1")); ASSERT_NO_THROW(p2.expect("test2")); @@ -58,13 +59,13 @@ TEST(UtilsTests, ParseEndOfFile) ASSERT_THROW(p2.parse(), plasp::utils::ParserException); std::stringstream s3("-127"); - plasp::utils::Parser p3("input", s3); + plasp::utils::Parser<> p3("input", s3); p3.expect(-127); ASSERT_THROW(p3.parse(), plasp::utils::ParserException); std::stringstream s4("128 -1023 -4095"); - plasp::utils::Parser p4("input", s4); + plasp::utils::Parser<> p4("input", s4); ASSERT_NO_THROW(p4.expect(128)); ASSERT_NO_THROW(p4.expect(-1023)); @@ -72,13 +73,13 @@ TEST(UtilsTests, ParseEndOfFile) ASSERT_THROW(p4.parse(), plasp::utils::ParserException); std::stringstream s5("0"); - plasp::utils::Parser p5("input", s5); + plasp::utils::Parser<> p5("input", s5); p5.expect(false); ASSERT_THROW(p5.parse(), plasp::utils::ParserException); std::stringstream s6("0 1 0"); - plasp::utils::Parser p6("input", s6); + plasp::utils::Parser<> p6("input", s6); ASSERT_NO_THROW(p6.expect(false)); ASSERT_NO_THROW(p6.expect(true)); @@ -91,11 +92,11 @@ TEST(UtilsTests, ParseEndOfFile) TEST(UtilsTests, ParserPosition) { 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(); - plasp::utils::Parser::Coordinate c; + plasp::utils::StreamCoordinate c; c = p.coordinate(); ASSERT_EQ(c.row, 1u); @@ -174,11 +175,11 @@ TEST(UtilsTests, ParserPosition) c = p.coordinate(); ASSERT_EQ(c.row, 10u); ASSERT_EQ(c.column, 1u); - ASSERT_TRUE(p.atEndOfStream()); + ASSERT_TRUE(p.atEnd()); p.reset(); ASSERT_EQ(p.position(), startPosition); - ASSERT_FALSE(p.atEndOfStream()); + ASSERT_FALSE(p.atEnd()); for (size_t i = 0; i < 5; i++) p.advance(); @@ -199,11 +200,11 @@ TEST(UtilsTests, ParserPosition) TEST(UtilsTests, ParserRemoveComments) { 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); - plasp::utils::Parser::Coordinate c; + plasp::utils::StreamCoordinate c; ASSERT_NO_THROW(p1.expect("test1")); @@ -219,10 +220,10 @@ TEST(UtilsTests, ParserRemoveComments) p1.skipWhiteSpace(); - ASSERT_TRUE(p1.atEndOfStream()); + ASSERT_TRUE(p1.atEnd()); std::stringstream s2("test;"); - plasp::utils::Parser p2("input", s2); + plasp::utils::Parser<> p2("input", s2); p2.removeComments(";", "\n", false); @@ -230,10 +231,10 @@ TEST(UtilsTests, ParserRemoveComments) p2.skipWhiteSpace(); - ASSERT_TRUE(p2.atEndOfStream()); + ASSERT_TRUE(p2.atEnd()); 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); @@ -242,7 +243,7 @@ TEST(UtilsTests, ParserRemoveComments) p3.skipWhiteSpace(); - ASSERT_TRUE(p3.atEndOfStream()); + ASSERT_TRUE(p3.atEnd()); } ////////////////////////////////////////////////////////////////////////////////////////////////////