From 6191d4f88d04a935c9ddec4d581d21ec23cae968 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sun, 8 Feb 2015 21:14:01 +0100 Subject: Added support for parsing commands --- src/plugins/plain/PlainFormatStreamReader.cpp | 73 +++++++++++++++++++++++++-- src/plugins/plain/PlainFormatStreamReader.hpp | 42 ++++++++++++++- 2 files changed, 110 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/plugins/plain/PlainFormatStreamReader.cpp b/src/plugins/plain/PlainFormatStreamReader.cpp index 498cd43..4469536 100644 --- a/src/plugins/plain/PlainFormatStreamReader.cpp +++ b/src/plugins/plain/PlainFormatStreamReader.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "PlainFormatStreamReader.hpp" @@ -47,7 +48,6 @@ private: SourceOffset end; public: - /** * Default constructor, initializes start and end with zeros. */ @@ -123,6 +123,72 @@ PlainFormatStreamReader::PlainFormatStreamReader(CharReader &reader, tokenBlockCommentEnd = tokenizer.registerToken("}%"); } +Variant PlainFormatStreamReader::parseIdentifier(size_t start) +{ + bool first = true; + std::vector identifier; + size_t end = reader.getPeekOffset(); + char c; + while (reader.peek(c)) { + // Abort if this character is not a valid identifer character + if ((first && Utils::isIdentifierStartCharacter(c)) || + (!first && Utils::isIdentifierCharacter(c))) { + identifier.push_back(c); + } else { + reader.resetPeek(); + break; + } + + // This is no longer the first character + first = false; + end = reader.getPeekOffset(); + reader.consumePeek(); + } + + // Return the identifier at its location + Variant res = + Variant::fromString(std::string(identifier.data(), identifier.size())); + res.setLocation({reader.getSourceId(), start, end}); + return res; +} + +void PlainFormatStreamReader::parseCommand(size_t start) +{ + // Parse the commandName as a first identifier + commandName = parseIdentifier(start); + + // Check whether the next character is a '#', indicating the start of the + // command name + Variant commandArgName; + start = reader.getOffset(); + if (reader.expect('#')) { + commandArgName = parseIdentifier(start); + if (commandArgName.asString().empty()) { + logger.error("Expected identifier after '#'", commandArgName); + } + } + + // Read the arguments (if they are available), otherwise reset them + if (reader.expect('[')) { + auto res = VariantReader::parseObject(reader, logger, ']'); + commandArguments = res.second; + } else { + commandArguments = Variant::mapType{}; + } + + // Insert the parsed name, make sure "name" was not specified in the + // arguments + if (commandArgName.isString()) { + auto res = commandArguments.asMap().emplace("name", commandArgName); + if (!res.second) { + logger.error("Name argument specified multiple times", + SourceLocation{}, MessageMode::NO_CONTEXT); + logger.note("First occurance is here: ", commandArgName); + logger.note("Second occurance is here: ", res.first->second); + } + } +} + void PlainFormatStreamReader::parseBlockComment() { DynamicToken token; @@ -184,9 +250,10 @@ PlainFormatStreamReader::State PlainFormatStreamReader::parse() char c; reader.consumePeek(); reader.peek(c); - if (Utils::isIdentifierStart(c)) { + if (Utils::isIdentifierStartCharacter(c)) { CHECK_ISSUE_DATA(); - // TODO: Parse a command + reader.resetPeek(); + parseCommand(token.location.getStart()); return State::COMMAND; } diff --git a/src/plugins/plain/PlainFormatStreamReader.hpp b/src/plugins/plain/PlainFormatStreamReader.hpp index b2ea378..737bbe8 100644 --- a/src/plugins/plain/PlainFormatStreamReader.hpp +++ b/src/plugins/plain/PlainFormatStreamReader.hpp @@ -177,6 +177,22 @@ private: */ size_t fieldIdx; + /** + * Function used internall to parse an identifier. + * + * @param start is the start byte offset of the identifier (including the + * backslash). + */ + Variant parseIdentifier(size_t start); + + /** + * Function used internally to parse a command. + * + * @param start is the start byte offset of the command (including the + * backslash). + */ + void parseCommand(size_t start); + /** * Function used internally to parse a block comment. */ @@ -208,10 +224,32 @@ public: */ State parse(); - /** - * Returns a reference at the internally stored data. + /** + * Returns a reference at the internally stored data. Only valid if + * State::DATA was returned by the "parse" function. + * + * @return a reference at a variant containing the data parsed by the + * "parse" function. */ const Variant& getData() {return data;} + + /** + * Returns a reference at the internally stored command name. Only valid if + * State::COMMAND was returned by the "parse" function. + * + * @return a reference at a variant containing name and location of the + * parsed command. + */ + const Variant& getCommandName() {return commandName;} + + /** + * Returns a reference at the internally stored command name. Only valid if + * State::COMMAND was returned by the "parse" function. + * + * @return a reference at a variant containing arguments given to the + * command. + */ + const Variant& getCommandArguments() {return commandArguments;} }; } -- cgit v1.2.3