summaryrefslogtreecommitdiff
path: root/src/core/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/common')
-rw-r--r--src/core/common/CharReader.cpp23
-rw-r--r--src/core/common/CharReader.hpp9
-rw-r--r--src/core/common/Exceptions.hpp2
-rw-r--r--src/core/common/Logger.hpp14
-rw-r--r--src/core/common/VariantReader.cpp132
-rw-r--r--src/core/common/VariantReader.hpp49
6 files changed, 200 insertions, 29 deletions
diff --git a/src/core/common/CharReader.cpp b/src/core/common/CharReader.cpp
index 3e95280..2a4383f 100644
--- a/src/core/common/CharReader.cpp
+++ b/src/core/common/CharReader.cpp
@@ -336,7 +336,7 @@ size_t Buffer::seekCursor(CursorId cursor, size_t offs)
const ssize_t relativeOffs = offs - currentOffs;
// Perform the actual seeking, move the peek cursor to the read cursor
- const ssize_t reachedOffs = currentOffs + moveCursor(cursor, relativeOffs);
+ const ssize_t reachedOffs = currentOffs + moveCursor(cursor, relativeOffs);
// Clamp to values larger or equal to zero
return reachedOffs < 0 ? 0 : reachedOffs;
@@ -402,6 +402,18 @@ CharReader::CharReader(std::shared_ptr<Buffer> buffer, SourceId sourceId,
{
}
+CharReader::CharReader(CharReader &&other) noexcept
+ : buffer(std::move(other.buffer)),
+ readCursor(other.readCursor),
+ peekCursor(other.peekCursor),
+ coherent(other.coherent),
+ sourceId(other.sourceId),
+ offs(other.offs)
+{
+ other.readCursor = 0;
+ other.peekCursor = 0;
+}
+
CharReader::CharReader(const std::string &str, SourceId sourceId, size_t offs)
: CharReader(std::shared_ptr<Buffer>{new Buffer{str}}, sourceId, offs)
{
@@ -468,10 +480,7 @@ bool CharReader::read(char &c)
return res;
}
-bool CharReader::fetch(char &c)
-{
- return buffer->fetch(readCursor, c);
-}
+bool CharReader::fetch(char &c) { return buffer->fetch(readCursor, c); }
bool CharReader::fetchPeek(char &c)
{
@@ -541,7 +550,7 @@ size_t CharReader::readRaw(char *buf, size_t size)
size_t CharReader::seek(size_t requestedOffset)
{
- const size_t res = buffer->seekCursor(readCursor, requestedOffset);
+ const size_t res = buffer->seekCursor(readCursor, requestedOffset);
buffer->copyCursor(readCursor, peekCursor);
coherent = true;
return res;
@@ -549,7 +558,7 @@ size_t CharReader::seek(size_t requestedOffset)
size_t CharReader::seekPeekCursor(size_t requestedOffset)
{
- const size_t res = buffer->seekCursor(peekCursor, requestedOffset);
+ const size_t res = buffer->seekCursor(peekCursor, requestedOffset);
coherent = (res == getOffset());
return res;
}
diff --git a/src/core/common/CharReader.hpp b/src/core/common/CharReader.hpp
index a90d337..0a220ee 100644
--- a/src/core/common/CharReader.hpp
+++ b/src/core/common/CharReader.hpp
@@ -462,10 +462,15 @@ public:
~CharReader();
// No copy
- CharReader(const Buffer &) = delete;
+ CharReader(const CharReader &) = delete;
// No assign
- CharReader &operator=(const Buffer &) = delete;
+ CharReader &operator=(const CharReader &) = delete;
+
+ /**
+ * Move constructor.
+ */
+ CharReader(CharReader &&) noexcept;
/**
* Peeks a single character. If called multiple times, returns the
diff --git a/src/core/common/Exceptions.hpp b/src/core/common/Exceptions.hpp
index b63c32a..337480a 100644
--- a/src/core/common/Exceptions.hpp
+++ b/src/core/common/Exceptions.hpp
@@ -109,7 +109,7 @@ public:
* @param loc is a reference to a variable with location data.
*/
template <class LocationType>
- LoggableException(std::string msg, LocationType loc)
+ LoggableException(std::string msg, const LocationType &loc)
: LoggableException(std::move(msg), SourceLocation::location(loc))
{
}
diff --git a/src/core/common/Logger.hpp b/src/core/common/Logger.hpp
index c8b324c..d2d8e80 100644
--- a/src/core/common/Logger.hpp
+++ b/src/core/common/Logger.hpp
@@ -280,7 +280,7 @@ public:
* @param mode specifies how the message should be displayed.
*/
template <class LocationType>
- void log(const LoggableException &ex, LocationType loc,
+ void log(const LoggableException &ex, const LocationType &loc,
MessageMode mode = MessageMode::DEFAULT)
{
log(ex, SourceLocation::location(loc), mode);
@@ -297,7 +297,7 @@ public:
* @param mode specifies how the message should be displayed.
*/
template <class LocationType>
- void log(Severity severity, const std::string &msg, LocationType loc,
+ void log(Severity severity, const std::string &msg, const LocationType &loc,
MessageMode mode = MessageMode::DEFAULT)
{
log(severity, msg, SourceLocation::location(loc), mode);
@@ -328,7 +328,7 @@ public:
* information.
*/
template <class LocationType>
- void debug(const std::string &msg, LocationType loc,
+ void debug(const std::string &msg, const LocationType &loc,
MessageMode mode = MessageMode::DEFAULT)
{
#ifndef NDEBUG
@@ -357,7 +357,7 @@ public:
* information.
*/
template <class LocationType>
- void note(const std::string &msg, LocationType loc,
+ void note(const std::string &msg, const LocationType &loc,
MessageMode mode = MessageMode::DEFAULT)
{
log(Severity::NOTE, msg, loc, mode);
@@ -384,7 +384,7 @@ public:
* information.
*/
template <class LocationType>
- void warning(const std::string &msg, LocationType loc,
+ void warning(const std::string &msg, const LocationType &loc,
MessageMode mode = MessageMode::DEFAULT)
{
log(Severity::WARNING, msg, SourceLocation::location(loc), mode);
@@ -411,7 +411,7 @@ public:
* information.
*/
template <class LocationType>
- void error(const std::string &msg, LocationType loc,
+ void error(const std::string &msg, const LocationType &loc,
MessageMode mode = MessageMode::DEFAULT)
{
log(Severity::ERROR, msg, SourceLocation::location(loc), mode);
@@ -438,7 +438,7 @@ public:
* information.
*/
template <class LocationType>
- void fatalError(const std::string &msg, LocationType loc,
+ void fatalError(const std::string &msg, const LocationType &loc,
MessageMode mode = MessageMode::DEFAULT)
{
log(Severity::FATAL_ERROR, msg, SourceLocation::location(loc), mode);
diff --git a/src/core/common/VariantReader.cpp b/src/core/common/VariantReader.cpp
index ef71740..3f02226 100644
--- a/src/core/common/VariantReader.cpp
+++ b/src/core/common/VariantReader.cpp
@@ -16,9 +16,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <iostream>
-
#include <cmath>
+#include <limits>
#include <sstream>
#include <utf8.h>
@@ -485,6 +484,36 @@ std::pair<bool, std::string> VariantReader::parseUnescapedString(
return std::make_pair(true, res.str());
}
+std::pair<bool, Variant::boolType> VariantReader::parseBool(CharReader &reader,
+ Logger &logger)
+{
+ // first we consume all whitespaces.
+ reader.consumePeek();
+ reader.consumeWhitespace();
+ // then we try to find the words "true" or "false".
+
+ bool val = false;
+ CharReaderFork readerFork = reader.fork();
+ LoggerFork loggerFork = logger.fork();
+ auto res = parseToken(readerFork, loggerFork, {});
+ if (res.first) {
+ bool valid = false;
+ if (res.second == "true") {
+ val = true;
+ valid = true;
+ } else if (res.second == "false") {
+ val = false;
+ valid = true;
+ }
+ if (valid) {
+ readerFork.commit();
+ loggerFork.commit();
+ return std::make_pair(true, val);
+ }
+ }
+ return std::make_pair(false, val);
+}
+
std::pair<bool, int64_t> VariantReader::parseInteger(
CharReader &reader, Logger &logger, const std::unordered_set<char> &delims)
{
@@ -715,10 +744,9 @@ std::pair<bool, Variant> VariantReader::parseGenericToken(
// Skip all whitespace characters, read a character and abort if at the end
reader.consumePeek();
reader.consumeWhitespace();
- if (!reader.peek(c) || delims.count(c)) {
+ if (!reader.fetch(c) || delims.count(c)) {
return error(reader, logger, ERR_UNEXPECTED_END, nullptr);
}
- reader.resetPeek();
// Fetch the start offset
const SourceOffset start = reader.getOffset();
@@ -738,26 +766,31 @@ std::pair<bool, Variant> VariantReader::parseGenericToken(
CharReaderFork readerFork = reader.fork();
LoggerFork loggerFork = logger.fork();
if (n.parse(readerFork, loggerFork, delims)) {
- readerFork.commit();
- loggerFork.commit();
-
Variant v;
if (n.isInt()) {
+ if (n.intValue() <
+ std::numeric_limits<Variant::intType>::min() ||
+ n.intValue() >
+ std::numeric_limits<Variant::intType>::max()) {
+ logger.error("Number exceeds type limits.", reader);
+ return std::make_pair(false, v);
+ }
v = Variant{static_cast<Variant::intType>(n.intValue())};
} else {
v = Variant{n.doubleValue()};
}
+ readerFork.commit();
+ loggerFork.commit();
v.setLocation({reader.getSourceId(), start, reader.getOffset()});
return std::make_pair(true, v);
}
- reader.resetPeek();
}
// Try to parse a cardinality
if (c == '{') {
CharReaderFork readerFork = reader.fork();
LoggerFork loggerFork = logger.fork();
- auto res = parseCardinality(readerFork, logger);
+ auto res = parseCardinality(readerFork, loggerFork);
if (res.first) {
readerFork.commit();
loggerFork.commit();
@@ -765,7 +798,6 @@ std::pair<bool, Variant> VariantReader::parseGenericToken(
v.setLocation({reader.getSourceId(), start, reader.getOffset()});
return std::make_pair(true, v);
}
- reader.resetPeek();
}
// Try to parse an object
@@ -835,5 +867,85 @@ std::pair<bool, Variant> VariantReader::parseGenericString(
v.setLocation({sourceId, offs, offs + str.size()});
return std::make_pair(true, v);
}
+
+std::pair<bool, Variant> VariantReader::parseTyped(
+ VariantType type, CharReader &reader, Logger &logger,
+ const std::unordered_set<char> &delims)
+{
+ switch (type) {
+ case VariantType::BOOL: {
+ auto res = parseBool(reader, logger);
+ return std::make_pair(res.first, Variant{res.second});
+ }
+ case VariantType::INT: {
+ auto res = parseInteger(reader, logger, delims);
+ if (res.second < std::numeric_limits<Variant::intType>::min() ||
+ res.second > std::numeric_limits<Variant::intType>::max()) {
+ logger.error("Number exceeds type limits.", reader);
+ return std::make_pair(false, Variant{});
+ }
+ return std::make_pair(
+ res.first, Variant{static_cast<Variant::intType>(res.second)});
+ }
+ case VariantType::DOUBLE: {
+ auto res = parseDouble(reader, logger, delims);
+ return std::make_pair(res.first, Variant{res.second});
+ }
+ case VariantType::STRING: {
+ auto res = parseString(reader, logger, delims);
+ return std::make_pair(res.first, Variant::fromString(res.second));
+ }
+ case VariantType::ARRAY: {
+ char delim = 0;
+ if (delims.size() == 1) {
+ delim = *delims.begin();
+ }
+ auto res = parseArray(reader, logger, delim);
+ return std::make_pair(res.first, Variant{res.second});
+ }
+
+ case VariantType::MAP:
+ case VariantType::OBJECT: {
+ char delim = 0;
+ if (delims.size() == 1) {
+ delim = *delims.begin();
+ }
+ auto res = parseObject(reader, logger, delim);
+ return std::make_pair(res.first, Variant{res.second});
+ }
+ case VariantType::CARDINALITY: {
+ auto res = parseCardinality(reader, logger);
+ return std::make_pair(res.first, Variant{res.second});
+ }
+ default:
+ break;
+ }
+
+ return std::make_pair(false, Variant{});
+}
+
+std::pair<bool, Variant> VariantReader::parseTyped(VariantType type,
+ const std::string &str,
+ Logger &logger,
+ SourceId sourceId,
+ size_t offs)
+{
+ // create a char reader and forward the method.
+ CharReader reader{str, sourceId, offs};
+ LoggerFork loggerFork = logger.fork();
+ std::pair<bool, Variant> res =
+ parseTyped(type, reader, loggerFork, std::unordered_set<char>{});
+
+ // If all content could be parsed, commit the result.
+ if (reader.atEnd()) {
+ loggerFork.commit();
+ return res;
+ }
+
+ // otherwise do not.
+ logger.error("Not all input could be processed",
+ {sourceId, offs, offs + str.size()});
+ return std::make_pair(false, Variant{});
+}
}
diff --git a/src/core/common/VariantReader.hpp b/src/core/common/VariantReader.hpp
index 6b157d8..1232f6e 100644
--- a/src/core/common/VariantReader.hpp
+++ b/src/core/common/VariantReader.hpp
@@ -133,6 +133,19 @@ public:
const std::unordered_set<char> &delims);
/**
+ * Parses a bool from the given CharReader instance (the strings "true" or
+ * "false").
+ *
+ * @param reader is a reference to the CharReader instance which is
+ * the source for the character data. The reader will be positioned after
+ * the bool.
+ * @param logger is the logger instance that should be used to log error
+ * messages and warnings.
+ */
+ static std::pair<bool, Variant::boolType> parseBool(CharReader &reader,
+ Logger &logger);
+
+ /**
* Parses an integer from the given CharReader instance until one of the
* given delimiter characters is reached.
*
@@ -169,7 +182,7 @@ public:
*
* @param reader is a reference to the CharReader instance which is
* the source for the character data. The reader will be positioned after
- * the number or at the terminating delimiting character.
+ * the array or at the terminating delimiting character.
* @param logger is the logger instance that should be used to log error
* messages and warnings.
* @param delim is the terminating character. If nonzero, the parse function
@@ -185,7 +198,7 @@ public:
*
* @param reader is a reference to the CharReader instance which is
* the source for the character data. The reader will be positioned after
- * the number or at the terminating delimiting character.
+ * the object or at the terminating delimiting character.
* @param logger is the logger instance that should be used to log error
* messages and warnings.
* @param delim is the terminating character. If nonzero, the parse function
@@ -293,6 +306,38 @@ public:
static std::pair<bool, Variant> parseGenericString(
const std::string &str, Logger &logger,
SourceId sourceId = InvalidSourceId, size_t offs = 0);
+
+ /**
+ * Tries to parse an instance of the given type from the given stream. The
+ * called method is one of the parse methods defined here and adheres to the
+ * specifications defined there.
+ *
+ * @param type is the VariantType for which an instance shall be parsed.
+ * @param reader is a reference to the CharReader instance which is
+ * the source for the character data. The reader will be positioned
+ * at the end of the type instance (or the delimiting character).
+ * @param delims is a set of characters which will terminate the typed
+ * instance if the according parser uses delimiting characters.
+ * These characters are not included in the result. May not be nullptr.
+ */
+ static std::pair<bool, Variant> parseTyped(
+ VariantType type, CharReader &reader, Logger &logger,
+ const std::unordered_set<char> &delims = {});
+ /**
+ * Tries to parse an instance of the given type from the given string. The
+ * called method is one of the parse methods defined here and adheres to the
+ * specifications defined there.
+ *
+ * @param type is the VariantType for which an instance shall be parsed.
+ * @param str is the string from which the value should be read.
+ * @param sourceId is an optional descriptor of the source file from which
+ * the element is being read.
+ * @param offs is the by offset in the source file at which the string
+ * starts.
+ */
+ static std::pair<bool, Variant> parseTyped(
+ VariantType type, const std::string &str, Logger &logger,
+ SourceId sourceId = InvalidSourceId, size_t offs = 0);
};
}