summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt24
-rw-r--r--src/core/BufferedCharReader.cpp263
-rw-r--r--src/core/BufferedCharReader.hpp288
-rw-r--r--src/core/CSS.hpp2
-rw-r--r--src/core/CodeTokenizer.hpp8
-rw-r--r--src/core/Logger.hpp609
-rw-r--r--src/core/Registry.cpp3
-rw-r--r--src/core/Tokenizer.cpp12
-rw-r--r--src/core/Tokenizer.hpp27
-rw-r--r--src/core/common/CharReader.cpp (renamed from src/core/utils/CharReader.cpp)20
-rw-r--r--src/core/common/CharReader.hpp (renamed from src/core/utils/CharReader.hpp)95
-rw-r--r--src/core/common/Exceptions.cpp (renamed from src/core/Exceptions.cpp)18
-rw-r--r--src/core/common/Exceptions.hpp (renamed from src/core/Exceptions.hpp)77
-rw-r--r--src/core/common/Logger.cpp (renamed from src/core/Logger.cpp)122
-rw-r--r--src/core/common/Logger.hpp602
-rw-r--r--src/core/common/TextCursor.hpp168
-rw-r--r--src/core/common/Utils.cpp (renamed from src/core/Utils.cpp)0
-rw-r--r--src/core/common/Utils.hpp (renamed from src/core/Utils.hpp)0
-rw-r--r--src/core/common/Variant.cpp (renamed from src/core/variant/Variant.cpp)3
-rw-r--r--src/core/common/Variant.hpp (renamed from src/core/variant/Variant.hpp)7
-rw-r--r--src/core/common/VariantReader.cpp (renamed from src/core/variant/Reader.cpp)303
-rw-r--r--src/core/common/VariantReader.hpp (renamed from src/core/variant/Reader.hpp)87
-rw-r--r--src/core/parser/Parser.hpp4
-rw-r--r--src/core/parser/ParserStack.cpp4
-rw-r--r--src/core/parser/ParserStack.hpp2
-rw-r--r--src/plugins/css/CSSParser.cpp11
-rw-r--r--src/plugins/css/CSSParser.hpp2
-rw-r--r--src/plugins/xml/XmlParser.cpp12
-rw-r--r--test/core/BufferedCharReaderTest.cpp185
-rw-r--r--test/core/CodeTokenizerTest.cpp26
-rw-r--r--test/core/LoggerTest.cpp74
-rw-r--r--test/core/RegistryTest.cpp2
-rw-r--r--test/core/TokenizerTest.cpp14
-rw-r--r--test/core/common/CharReaderTest.cpp (renamed from test/core/utils/CharReaderTest.cpp)73
-rw-r--r--test/core/common/LoggerTest.cpp102
-rw-r--r--test/core/common/UtilsTest.cpp (renamed from test/core/UtilsTest.cpp)2
-rw-r--r--test/core/common/VariantReaderTest.cpp (renamed from test/core/variant/ReaderTest.cpp)155
-rw-r--r--test/core/common/VariantTest.cpp (renamed from test/core/variant/VariantTest.cpp)2
-rw-r--r--test/plugins/css/CSSParserTest.cpp16
-rw-r--r--test/plugins/xml/XmlParserTest.cpp2
40 files changed, 1468 insertions, 1958 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6651069..39d04e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -99,18 +99,20 @@ ADD_DEFINITIONS(
)
ADD_LIBRARY(ousia_core
- src/core/BufferedCharReader
src/core/CodeTokenizer
src/core/CSS
- src/core/Exceptions
- src/core/Logger
src/core/Managed
src/core/Node
src/core/Registry
src/core/ResourceLocator
src/core/Tokenizer
# src/core/Typesystem
- src/core/Utils
+ src/core/common/CharReader
+ src/core/common/Exceptions
+ src/core/common/Logger
+ src/core/common/Utils
+ src/core/common/Variant
+ src/core/common/VariantReader
src/core/parser/Parser
src/core/parser/ParserStack
src/core/parser/Scope
@@ -118,9 +120,6 @@ ADD_LIBRARY(ousia_core
# src/core/script/Object
# src/core/script/ScriptEngine
# src/core/script/Variant
- src/core/utils/CharReader
- src/core/variant/Reader
- src/core/variant/Variant
)
ADD_LIBRARY(ousia_boost
@@ -166,10 +165,8 @@ IF(TEST)
)
ADD_EXECUTABLE(ousia_test_core
- test/core/BufferedCharReaderTest
test/core/CodeTokenizerTest
test/core/CSSTest
- test/core/LoggerTest
test/core/ManagedTest
test/core/ManagedContainersTest
test/core/NodeTest
@@ -177,14 +174,15 @@ IF(TEST)
test/core/RegistryTest
test/core/ResourceLocatorTest
test/core/TokenizerTest
- test/core/UtilsTest
+ test/core/common/CharReaderTest
+ test/core/common/LoggerTest
+ test/core/common/VariantReaderTest
+ test/core/common/VariantTest
+ test/core/common/UtilsTest
test/core/parser/ParserStackTest
# test/core/script/FunctionTest
# test/core/script/ObjectTest
# test/core/script/VariantTest
- test/core/utils/CharReaderTest
- test/core/variant/ReaderTest
- test/core/variant/VariantTest
)
TARGET_LINK_LIBRARIES(ousia_test_core
diff --git a/src/core/BufferedCharReader.cpp b/src/core/BufferedCharReader.cpp
deleted file mode 100644
index aeedf12..0000000
--- a/src/core/BufferedCharReader.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- Ousía
- Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <array>
-
-#include "Utils.hpp"
-
-#include "BufferedCharReader.hpp"
-
-namespace ousia {
-
-// Constants used within the linebreak statemachine.
-static const uint8_t LB_STATE_NONE = 0x00;
-static const uint8_t LB_STATE_ONE = 0x01;
-static const uint8_t LB_STATE_LF = 0x10;
-static const uint8_t LB_STATE_CR = 0x20;
-static const uint8_t LB_STATE_MASK_CNT = 0x0F;
-static const uint8_t LB_STATE_MASK_TYPE = 0xF0;
-
-/* Struct BufferedCharReader::ReadCursor */
-
-BufferedCharReader::ReadCursor::ReadCursor(unsigned int line,
- unsigned int column,
- bool destructive)
- : line(line),
- column(column),
- bufferElem(0),
- bufferPos(0),
- destructive(destructive),
- lbState(LB_STATE_NONE)
-{
-}
-
-void BufferedCharReader::ReadCursor::assign(const ReadCursor &cursor)
-{
- this->line = cursor.line;
- this->column = cursor.column;
- this->bufferElem = cursor.bufferElem;
- this->bufferPos = cursor.bufferPos;
- this->lbState = cursor.lbState;
-}
-
-/* Class BufferedCharReader */
-
-BufferedCharReader::BufferedCharReader(int line, int column)
- : inputStream(nullptr),
- readCursor(line, column, true),
- peekCursor(line, column, false),
- depleted(false)
-{
-}
-
-BufferedCharReader::BufferedCharReader(const std::string &str, int line,
- int column)
- : inputStream(nullptr),
- readCursor(line, column, true),
- peekCursor(line, column, false),
- depleted(true)
-{
- buffer.push_back(str);
-}
-
-BufferedCharReader::BufferedCharReader(const std::string &str)
- : inputStream(nullptr),
- readCursor(1, 1, true),
- peekCursor(1, 1, false),
- depleted(true)
-{
- buffer.push_back(str);
-}
-
-BufferedCharReader::BufferedCharReader(std::istream &inputStream, int line,
- int column)
- : inputStream(&inputStream),
- readCursor(line, column, true),
- peekCursor(line, column, false),
- depleted(false)
-{
-}
-
-void BufferedCharReader::feed(const std::string &data)
-{
- if (!depleted && !inputStream) {
- buffer.push_back(data);
- }
-}
-
-void BufferedCharReader::close()
-{
- if (!inputStream) {
- depleted = true;
- }
-}
-
-bool BufferedCharReader::substituteLinebreaks(ReadCursor &cursor, char *c)
-{
- // Handle line breaks, inserts breakes after the following character
- // combinations: \n, \r, \n\r, \r\n TODO: Change behaviour to \n, \n\r, \r\n
- if ((*c == '\n') || (*c == '\r')) {
- // Determine the type of the current linebreak character
- const uint8_t type = (*c == '\n') ? LB_STATE_LF : LB_STATE_CR;
-
- // Read the last count and the last type from the state
- const uint8_t lastCount = cursor.lbState & LB_STATE_MASK_CNT;
- const uint8_t lastType = cursor.lbState & LB_STATE_MASK_TYPE;
-
- // Set the current linebreak type and counter in the state
- cursor.lbState = ((lastCount + 1) & 1) | type;
-
- // If either this is the first instance of this character or the same
- // return character is repeated
- if (!lastCount || (lastType == type)) {
- *c = '\n';
- return true;
- }
- return false;
- }
-
- // Find the state
- cursor.lbState = LB_STATE_NONE;
- return true;
-}
-
-bool BufferedCharReader::readCharacterAtCursor(ReadCursor &cursor, char *c)
-{
- bool hasChar = false;
- while (!hasChar) {
- // Abort if the current buffer element does not point to a valid entry
- // in the buffer -- we must try to feed another data block into the
- // internal buffer
- if (cursor.bufferElem >= buffer.size()) {
- // Abort if there is no more data or no input stream is set
- if (depleted || !inputStream) {
- return false;
- }
-
- // Read a buffer of the specified size
- constexpr std::streamsize BUFFER_SIZE = 1024;
- std::array<char, BUFFER_SIZE> buf;
- const std::streamsize cnt =
- (*inputStream).read(buf.data(), BUFFER_SIZE).gcount();
-
- // If data has been read, append it to the input buffer and try
- // again
- if (cnt > 0) {
- buffer.emplace_back(std::string(buf.data(), cnt));
- continue;
- }
-
- // End of file handling
- if (inputStream->fail() || inputStream->eof()) {
- depleted = true;
- return false;
- }
- }
-
- // Fetch the current element the peek pointer points to
- const std::string &data = buffer[cursor.bufferElem];
-
- // Handle the "no data" case -- either in a destructive or
- // non-destructive manner.
- if (cursor.bufferPos >= data.length()) {
- if (cursor.destructive) {
- buffer.pop_front();
- } else {
- cursor.bufferElem++;
- }
- cursor.bufferPos = 0;
- continue;
- }
-
- // Read the character, advance the buffer position
- *c = *(data.data() + cursor.bufferPos);
- cursor.bufferPos++;
-
- // Substitute linebreaks with a single LF (0x0A)
- hasChar = substituteLinebreaks(cursor, c);
- }
-
- // Update the position counter
- if (*c == '\n') {
- cursor.line++;
- cursor.column = 1;
- } else {
- // Ignore UTF-8 continuation bytes
- if (!((*c & 0x80) && !(*c & 0x40))) {
- cursor.column++;
- }
- }
-
- return true;
-}
-
-bool BufferedCharReader::peek(char *c)
-{
- return readCharacterAtCursor(peekCursor, c);
-}
-
-bool BufferedCharReader::read(char *c)
-{
- resetPeek();
- return readCharacterAtCursor(readCursor, c);
-}
-
-void BufferedCharReader::consumePeek()
-{
- // Remove all no longer needed buffer elements
- for (unsigned int i = 0; i < peekCursor.bufferElem; i++) {
- buffer.pop_front();
- }
- peekCursor.bufferElem = 0;
-
- // Copy the peek cursor to the read cursor
- readCursor.assign(peekCursor);
-}
-
-bool BufferedCharReader::consumeWhitespace()
-{
- char c;
- while (peek(&c)) {
- if (!Utils::isWhitespace(c)) {
- resetPeek();
- return true;
- }
- consumePeek();
- }
- return false;
-}
-
-void BufferedCharReader::resetPeek()
-{
- // Reset the peek cursor to the read cursor
- peekCursor.assign(readCursor);
-}
-
-bool BufferedCharReader::atEnd() const
-{
- if (depleted || !inputStream) {
- if (buffer.size() <= 0) {
- return true;
- } else if (buffer.size() == 1) {
- return buffer[0].size() == readCursor.bufferPos;
- }
- }
- return false;
-}
-}
-
diff --git a/src/core/BufferedCharReader.hpp b/src/core/BufferedCharReader.hpp
deleted file mode 100644
index e7f3186..0000000
--- a/src/core/BufferedCharReader.hpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- Ousía
- Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file BufferedCharReader.hpp
- *
- * Contains the BufferedCharReader class which is used for reading/peeking
- * single characters from an input stream or string.
- *
- * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
- */
-
-#ifndef _OUSIA_BUFFERED_CHAR_READER_H_
-#define _OUSIA_BUFFERED_CHAR_READER_H_
-
-#include <deque>
-#include <string>
-#include <istream>
-#include <cstdint>
-
-namespace ousia {
-
-// TODO: Better split this class into multiple classes with base class
-// BufferedCharReader where each sub class represents one method of supplying
-// the input data (feeding, initial string, input stream).
-
-/**
- * The BufferedCharReader class is used for storing incomming data that
- * is fed into the pipeline as well as reading/peeking single characters
- * from that buffer. Additionally it counts the current column/row
- * (with correct handling for UTF-8) and contains an internal state
- * machine that handles the detection of linebreaks and converts these to a
- * single '\n'.
- */
-class BufferedCharReader {
-private:
- /**
- * The ReadCursor structure is responsible for representing the read
- * position within the text an all state machine states belonging to the
- * cursor. There are two types of read cursors: destructive and
- * non-destructive read cursors.
- */
- struct ReadCursor {
- /**
- * The line the cursor currently points to.
- */
- unsigned int line;
-
- /**
- * The column the cursor currently points to.
- */
- unsigned int column;
-
- /**
- * The index of the element in the data buffer we're currently reading
- * from.
- */
- unsigned int bufferElem;
-
- /**
- * The byte position within this data buffer.
- */
- unsigned int bufferPos;
-
- /**
- * Specifies whether this is a destructive cursor (bytes are discarded
- * once they were read from the buffer).
- */
- const bool destructive;
-
- /**
- * State variable used in the internal state machine of the
- * line feed detection.
- */
- uint8_t lbState;
-
- /**
- * Constructor of the ReadCursor structure.
- *
- * @param line is the start line.
- * @param column is the start column.
- * @param destructive specifies whether the ReadCursor is destructive
- * (consumes all read characters, as used in the "read cursor") or
- * non-destructive (as used in the "peek cursor").
- */
- ReadCursor(unsigned int line, unsigned int column, bool destructive);
-
- /**
- * Copys the data from another ReadCursor without overriding the
- * "destructive" flag.
- *
- * @param cursor is the cursor that should be copied.
- */
- void assign(const ReadCursor &cursor);
- };
-
- /**
- * Pointer at an (optional) input stream used for reading a chunk of data
- * whenever the input buffer depletes.
- */
- std::istream *inputStream;
-
- /**
- * The read and the peek cursor.
- */
- ReadCursor readCursor, peekCursor;
-
- /**
- * Set to true if there is no more input data.
- */
- bool depleted;
-
- /**
- * Queue containing the data that has been fed into the char reader.
- */
- std::deque<std::string> buffer;
-
- /**
- * Substitute any combination of linebreaks in the incomming code with "\n".
- * Returns true if the current character is meant as output, false
- * otherwise.
- */
- bool substituteLinebreaks(ReadCursor &cursor, char *c);
-
- /**
- * Reads a character from the input buffer and advances the given read
- * cursor.
- *
- * @param cursor is a reference to the read cursor that should be used
- * for reading.
- * @param hasChar is set to true, if a character is available, false if
- * no character is available (e.g. because line breaks are substituted or
- * the end of a buffer boundary is reached -- in this case this function
- * should be called again with the same parameters.)
- * @param c is a output parameter, which will be set to the read character.
- * @param returns true if there was enough data in the buffer, false
- * otherwise.
- */
- bool readCharacterAtCursor(ReadCursor &cursor, char *c);
-
- /**
- * Function that is called for each read character -- updates the row and
- * column count.
- */
- void updatePositionCounters(const char c);
-
-public:
-
- /**
- * Constructor of the buffered char reader class with empty buffer as input.
- * This operates the BufferedCharReader in a mode where new data has to be
- * fed using the "feed" function and explicitly closed using the "close"
- * function.
- *
- * @param line is the start line.
- * @param column is the start column.
- */
- BufferedCharReader(int line = 1, int column = 1);
-
- /**
- * Constructor of the buffered char reader class with a string as input.
- *
- * @param str is a string containing the input data.
- * @param line is the start line.
- * @param column is the start column.
- */
- BufferedCharReader(const std::string &str, int line, int column);
-
- /**
- * Constructor of the buffered char reader class with a string as input.
- *
- * @param str is a string containing the input data.
- */
- BufferedCharReader(const std::string &str);
-
- /**
- * Constructor of the buffered char reader class with a string as input.
- *
- * @param inputStream is the input stream from which incomming data should
- * be read.
- * @param line is the start line.
- * @param column is the start column.
- */
- BufferedCharReader(std::istream &inputStream, int line = 1, int column = 1);
-
- /**
- * Peeks a single character. If called multiple times, returns the
- * character after the previously peeked character.
- *
- * @param c is a reference to the character to which the result should be
- * writtern.
- * @return true if the character was successfully read, false if there are
- * no more characters to be read in the buffer.
- */
- bool peek(char *c);
-
- /**
- * Reads a character from the input data. If "peek" was called
- * beforehand resets the peek pointer.
- *
- * @param c is a reference to the character to which the result should be
- * writtern.
- * @return true if the character was successfully read, false if there are
- * no more characters to be read in the buffer.
- */
- bool read(char *c);
-
- /**
- * Advances the read pointer to the peek pointer -- so if the "peek"
- * function was called, "read" will now return the character after
- * the last peeked character.
- */
- void consumePeek();
-
- /**
- * Moves the read cursor to the next non-whitespace character. Returns
- * false, if the end of the stream was reached.
- *
- * @return false if the end of the stream was reached, false othrwise.
- */
- bool consumeWhitespace();
-
- /**
- * Resets the peek pointer to the "read" pointer.
- */
- void resetPeek();
-
- /**
- * Feeds new data into the internal buffer of the BufferedCharReader
- * class. Only applicable if the buffered char reader was constructed
- * without an input stream or string.
- *
- * @param data is a string containing the data that should be
- * appended to the internal buffer.
- */
- void feed(const std::string &data);
-
- /**
- * Tells the buffered char reader that no more data will be fed.
- * Only applicable if the buffered char reader was constructed without an
- * input stream or string.
- *
- * @param data is a string containing the data that should be
- * appended to the internal buffer.
- */
- void close();
-
- /**
- * Returns true if there are no more characters as the stream was
- * closed.
- *
- * @return true if there is no more data.
- */
- bool atEnd() const;
-
- /**
- * Returns the current line (starting with one).
- *
- * @return the current line number.
- */
- int getLine() const { return readCursor.line; }
-
- /**
- * Returns the current column (starting with one).
- *
- * @return the current column number.
- */
- int getColumn() const { return readCursor.column; }
-};
-}
-
-#endif /* _OUSIA_BUFFERED_CHAR_READER_H_ */
-
diff --git a/src/core/CSS.hpp b/src/core/CSS.hpp
index 1510f3a..a54d956 100644
--- a/src/core/CSS.hpp
+++ b/src/core/CSS.hpp
@@ -23,7 +23,7 @@
#include <vector>
#include <tuple>
-#include <core/variant/Variant.hpp>
+#include <core/common/Variant.hpp>
#include "Managed.hpp"
#include "Node.hpp"
diff --git a/src/core/CodeTokenizer.hpp b/src/core/CodeTokenizer.hpp
index 43c7abb..4190297 100644
--- a/src/core/CodeTokenizer.hpp
+++ b/src/core/CodeTokenizer.hpp
@@ -22,7 +22,7 @@
#include <map>
#include <sstream>
-#include "BufferedCharReader.hpp"
+#include <core/common/CharReader.hpp>
#include "Tokenizer.hpp"
namespace ousia {
@@ -108,8 +108,8 @@ public:
/**
*
- * @param input a BufferedCharReader containing the input for this
- * tokenizer, as with a regular tokenizer.
+ * @param input a CharReader containing the input for this tokenizer, as
+ * with a regular tokenizer.
* @param root a TokenTreeNode representing the root of the TokenTree.
* Please note that you have to specify all tokenIDs here that you use
* in the descriptors map.
@@ -120,7 +120,7 @@ public:
* and this CodeTokenizer would recognize the token "//" as starting a
* line comment.
*/
- CodeTokenizer(BufferedCharReader &input, const TokenTreeNode &root,
+ CodeTokenizer(CharReader &input, const TokenTreeNode &root,
std::map<int, CodeTokenDescriptor> descriptors)
: Tokenizer(input, root), descriptors(descriptors), state(CodeTokenizerState::NORMAL)
{
diff --git a/src/core/Logger.hpp b/src/core/Logger.hpp
deleted file mode 100644
index e6b97f4..0000000
--- a/src/core/Logger.hpp
+++ /dev/null
@@ -1,609 +0,0 @@
-/*
- Ousía
- Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file Logger.hpp
- *
- * Contains classes for logging messages in Ousía. Provides a generic Logger
- * class, and TerminalLogger, an extension of Logger which logs do an output
- * stream.
- *
- * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
- */
-
-#ifndef _OUSIA_LOGGER_HPP_
-#define _OUSIA_LOGGER_HPP_
-
-#include <ostream>
-#include <stack>
-#include <string>
-#include <vector>
-
-#include "Exceptions.hpp"
-
-namespace ousia {
-
-/**
- * Enum containing the severities used for logging errors and debug messages.
- */
-enum class Severity : int {
- /**
- * Indicates that this message was only printed for debugging. Note that
- * in release builds messages with this severity are discarded.
- */
- DEBUG = 0,
-
- /**
- * A message which might provide additional information to the user.
- */
- NOTE = 1,
-
- /**
- * A message which warns of possible mistakes by the user which might not be
- * actual errors but may lead to unintended behaviour.
- */
- WARNING = 2,
-
- /**
- * An error occurred while processing, however program execution continues,
- * trying to deal with the error situation (graceful degradation). However,
- * messages with this severity may be followed up by fatal errors.
- */
- ERROR = 3,
-
- /**
- * A fatal error occurred. Program execution cannot continue.
- */
- FATAL_ERROR = 4
-};
-
-#ifdef NDEBUG
-static constexpr Severity DEFAULT_MIN_SEVERITY = Severity::NOTE;
-#else
-static constexpr Severity DEFAULT_MIN_SEVERITY = Severity::DEBUG;
-#endif
-
-/**
- * The Logger class is the base class the individual logging systems should
- * derive from. It provides a simple interface for logging errors, warnings and
- * notes and filters these according to the set minimum severity. Additionally
- * a stack of file names is maintained in order to allow simple descent into
- * included files. Note however, that this base Logger class simply discards the
- * incomming log messages. Use one of the derived classes to actually handle the
- * log messages.
- */
-class Logger {
-public:
- /**
- * The message struct represents a single log message and all information
- * attached to it.
- */
- struct Message {
- /**
- * Severity of the log message.
- */
- Severity severity;
-
- /**
- * Actual log message.
- */
- std::string msg;
-
- /**
- * Refers to the file which provides the context for this error message.
- * May be empty.
- */
- std::string file;
-
- /**
- * Line in the above file the error message refers to. Ignored if
- * smaller than zero.
- */
- int line;
-
- /**
- * Column in the above file the error message refers to. Ignored if
- * smaller than zero.
- */
- int column;
-
- /**
- * Constructor of the Message struct.
- *
- * @param severity describes the message severity.
- * @param msg contains the actual message.
- * @param file provides the context the message refers to. May be empty.
- * @param line is the line in the above file the message refers to.
- * @param column is the column in the above file the message refers to.
- */
- Message(Severity severity, std::string msg, std::string file, int line,
- int column)
- : severity(severity),
- msg(std::move(msg)),
- file(std::move(file)),
- line(line),
- column(column){};
-
- /**
- * Returns true if the file string is set.
- *
- * @return true if the file string is set.
- */
- bool hasFile() const { return !file.empty(); }
-
- /**
- * Returns true if the line is set.
- *
- * @return true if the line number is a non-negative integer.
- */
- bool hasLine() const { return line >= 0; }
-
- /**
- * Returns true if column and line are set (since a column has no
- * significance without a line number).
- *
- * @return true if line number and column number are non-negative
- * integers.
- */
- bool hasColumn() const { return hasLine() && column >= 0; }
- };
-
-private:
- /**
- * Minimum severity a log message should have before it is discarded.
- */
- Severity minSeverity;
-
- /**
- * Maximum encountered log message severity.
- */
- Severity maxEncounteredSeverity;
-
- /**
- * Stack containing the current file names that have been processed.
- */
- std::stack<std::string> filenameStack;
-
-protected:
- /**
- * Function to be overriden by child classes to actually display or store
- * the messages. The default implementation just discards all incomming
- * messages.
- *
- * @param msg is an instance of the Message struct containing the data that
- * should be logged.
- */
- virtual void process(const Message &msg){};
-
-public:
- /**
- * Constructor of the Logger class.
- *
- * @param minSeverity is the minimum severity a log message should have.
- * Messages below this severity are discarded.
- */
- Logger(Severity minSeverity = DEFAULT_MIN_SEVERITY)
- : minSeverity(minSeverity), maxEncounteredSeverity(Severity::DEBUG)
- {
- }
-
- Logger(const Logger &) = delete;
-
- /**
- * Virtual destructor.
- */
- virtual ~Logger(){};
-
- /**
- * Logs the given message. Most generic log function.
- *
- * @param severity is the severity of the log message.
- * @param msg is the actual log message.
- * @param file is the name of the file the message refers to. May be empty.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void log(Severity severity, const std::string &msg, const std::string &file,
- int line = -1, int column = -1);
-
- /**
- * Logs the given message. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param severity is the severity of the log message.
- * @param msg is the actual log message.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void log(Severity severity, const std::string &msg, int line = -1,
- int column = -1)
- {
- log(severity, msg, currentFilename(), line, column);
- }
-
- /**
- * Logs the given message. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param severity is the severity of the log message.
- * @param msg is the actual log message.
- * @param pos is a const reference to a variable which provides position
- * information.
- * @tparam PosType is the actual type of pos and must implement a getLine
- * and getColumn function.
- */
- template <class PosType>
- void logAt(Severity severity, const std::string &msg, const PosType &pos)
- {
- log(severity, msg, pos.getLine(), pos.getColumn());
- }
-
- /**
- * Logs the given loggable exception.
- *
- * @param ex is the exception that should be logged.
- */
- void log(const LoggableException &ex)
- {
- log(Severity::ERROR, ex.msg,
- ex.file.empty() ? currentFilename() : ex.file, ex.line, ex.column);
- }
-
- /**
- * Logs a debug message. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param file is the name of the file the message refers to. May be empty.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void debug(const std::string &msg, const std::string &file, int line = -1,
- int column = -1)
- {
- log(Severity::DEBUG, msg, file, line, column);
- }
-
- /**
- * Logs a debug message. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void debug(const std::string &msg, int line = -1, int column = -1)
- {
- debug(msg, currentFilename(), line, column);
- }
-
- /**
- * Logs a debug message. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param severity is the severity of the log message.
- * @param msg is the actual log message.
- * @param pos is a const reference to a variable which provides position
- * information.
- */
- template <class PosType>
- void debugAt(const std::string &msg, const PosType &pos)
- {
- debug(msg, pos.getLine(), pos.getColumn());
- }
-
- /**
- * Logs a note. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param file is the name of the file the message refers to. May be empty.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void note(const std::string &msg, const std::string &file, int line = -1,
- int column = -1)
- {
- log(Severity::NOTE, msg, file, line, column);
- }
-
- /**
- * Logs a note. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void note(const std::string &msg, int line = -1, int column = -1)
- {
- note(msg, currentFilename(), line, column);
- }
-
- /**
- * Logs a note. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param pos is a const reference to a variable which provides position
- * information.
- */
- template <class PosType>
- void noteAt(const std::string &msg, const PosType &pos)
- {
- note(msg, pos.getLine(), pos.getColumn());
- }
-
- /**
- * Logs a warning. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param file is the name of the file the message refers to. May be empty.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void warning(const std::string &msg, const std::string &file, int line = -1,
- int column = -1)
- {
- log(Severity::WARNING, msg, file, line, column);
- }
-
- /**
- * Logs a warning. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param pos is a const reference to a variable which provides position
- * information.
- */
- template <class PosType>
- void warningAt(const std::string &msg, const PosType &pos)
- {
- warning(msg, pos.getLine(), pos.getColumn());
- }
-
- /**
- * Logs a warning. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void warning(const std::string &msg, int line = -1, int column = -1)
- {
- warning(msg, currentFilename(), line, column);
- }
-
- /**
- * Logs an error message. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param file is the name of the file the message refers to. May be empty.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void error(const std::string &msg, const std::string &file, int line = -1,
- int column = -1)
- {
- log(Severity::ERROR, msg, file, line, column);
- }
-
- /**
- * Logs an error message. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void error(const std::string &msg, int line = -1, int column = -1)
- {
- error(msg, currentFilename(), line, column);
- }
-
- /**
- * Logs an error message. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param pos is a const reference to a variable which provides position
- * information.
- */
- template <class PosType>
- void errorAt(const std::string &msg, const PosType &pos)
- {
- error(msg, pos.getLine(), pos.getColumn());
- }
-
- /**
- * Logs a fatal error. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param file is the name of the file the message refers to. May be empty.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void fatalError(const std::string &msg, const std::string &file,
- int line = -1, int column = -1)
- {
- log(Severity::FATAL_ERROR, msg, file, line, column);
- }
-
- /**
- * Logs a fatal error. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param line is the line in the above file at which the error occured.
- * Ignored if negative.
- * @param column is the column in the above file at which the error occured.
- * Ignored if negative.
- */
- void fatalError(const std::string &msg, int line = -1, int column = -1)
- {
- fatalError(msg, currentFilename(), line, column);
- }
-
- /**
- * Logs a fatal error. The file name is set to the topmost file name on
- * the file name stack.
- *
- * @param msg is the actual log message.
- * @param pos is a const reference to a variable which provides position
- * information.
- */
- template <class PosType>
- void fatalErrorAt(const std::string &msg, const PosType &pos)
- {
- fatalError(msg, pos.getLine(), pos.getColumn());
- }
-
- /**
- * Pushes a new file name onto the internal filename stack.
- *
- * @param name is the name of the file that should be added to the filename
- * stack.
- * @return the size of the filename stack. This number can be passed to the
- * "unwindFilenameStack" method in order to return the stack to state it was
- * in after this function has been called.
- */
- unsigned int pushFilename(const std::string &name);
-
- /**
- * Pops the filename from the internal filename stack.
- *
- * @return the current size of the filename stack.
- */
- unsigned int popFilename();
-
- /**
- * Pops elements from the filename stack while it has more elements than
- * the given number and the stack is non-empty.
- *
- * @param pos is the position the filename stack should be unwound to. Use
- * a number returned by pushFilename.
- */
- void unwindFilenameStack(unsigned int pos);
-
- /**
- * Returns the topmost filename from the internal filename stack.
- *
- * @return the topmost filename from the filename stack or an empty string
- * if the filename stack is empty.
- */
- std::string currentFilename()
- {
- return filenameStack.empty() ? std::string{} : filenameStack.top();
- }
-
- /**
- * Returns the maximum severity that was encountered by the Logger but at
- * least Severity::DEBUG.
- *
- * @return the severity of the most severe log message but at least
- * Severity::DEBUG.
- */
- Severity getMaxEncounteredSeverity() { return maxEncounteredSeverity; }
-
- /**
- * Returns the minimum severity. Messages with a smaller severity are
- * discarded.
- *
- * @return the minimum severity.
- */
- Severity getMinSeverity() { return minSeverity; }
-
- /**
- * Sets the minimum severity. Messages with a smaller severity will be
- * discarded. Only new messages will be filtered according to the new value.
- *
- * @param severity is the minimum severity for new log messages.
- */
- void setMinSeverity(Severity severity) { minSeverity = severity; }
-};
-
-/**
- * Class extending the Logger class and printing the log messages to the given
- * stream.
- */
-class TerminalLogger : public Logger {
-private:
- /**
- * Reference to the target output stream.
- */
- std::ostream &os;
-
- /**
- * If true, the TerminalLogger will use colors to make the log messages
- * prettier.
- */
- bool useColor;
-
-protected:
- /**
- * Implements the process function and logs the messages to the output.
- */
- void process(const Message &msg) override;
-
-public:
- /**
- * Constructor of the TerminalLogger class.
- *
- * @param os is the output stream the log messages should be logged to.
- * Should be set to std::cerr in most cases.
- * @param useColor if true, the TerminalLogger class will do its best to
- * use ANSI/VT100 control sequences for colored log messages.
- * @param minSeverity is the minimum severity below which log messages are
- * discarded.
- */
- TerminalLogger(std::ostream &os, bool useColor = false,
- Severity minSeverity = DEFAULT_MIN_SEVERITY)
- : Logger(minSeverity), os(os), useColor(useColor)
- {
- }
-};
-}
-
-#endif /* _OUSIA_LOGGER_HPP_ */
-
diff --git a/src/core/Registry.cpp b/src/core/Registry.cpp
index 6ff9594..74d1cf8 100644
--- a/src/core/Registry.cpp
+++ b/src/core/Registry.cpp
@@ -16,8 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <core/Logger.hpp>
-
+#include <core/common/Logger.hpp>
#include <core/parser/Parser.hpp>
namespace ousia {
diff --git a/src/core/Tokenizer.cpp b/src/core/Tokenizer.cpp
index b99d1ed..0af5f5a 100644
--- a/src/core/Tokenizer.cpp
+++ b/src/core/Tokenizer.cpp
@@ -72,7 +72,7 @@ TokenTreeNode::TokenTreeNode(const std::map<std::string, int> &inputs)
{
}
-Tokenizer::Tokenizer(BufferedCharReader &input, const TokenTreeNode &root)
+Tokenizer::Tokenizer(CharReader &input, const TokenTreeNode &root)
: input(input), root(root)
{
}
@@ -81,10 +81,10 @@ bool Tokenizer::prepare()
{
std::stringstream buffer;
char c;
- int startColumn = input.getColumn();
- int startLine = input.getLine();
+ uint32_t startColumn = input.getColumn();
+ uint32_t startLine = input.getLine();
bool bufEmpty = true;
- while (input.peek(&c)) {
+ while (input.peek(c)) {
if (root.children.find(c) != root.children.end()) {
// if there might be a special token, keep peeking forward
// until we find the token (or we don't).
@@ -107,7 +107,7 @@ bool Tokenizer::prepare()
input.consumePeek();
}
}
- if (!input.peek(&c)) {
+ if (!input.peek(c)) {
// if we are at the end we break off the search.
break;
}
@@ -153,7 +153,7 @@ bool Tokenizer::prepare()
}
} else{
//if we found nothing, read at least one character.
- input.peek(&c);
+ input.peek(c);
}
}
buffer << c;
diff --git a/src/core/Tokenizer.hpp b/src/core/Tokenizer.hpp
index 8f80150..33327cc 100644
--- a/src/core/Tokenizer.hpp
+++ b/src/core/Tokenizer.hpp
@@ -19,11 +19,12 @@
#ifndef _OUSIA_TOKENIZER_HPP_
#define _OUSIA_TOKENIZER_HPP_
+#include <cstdint>
+#include <deque>
#include <istream>
#include <map>
-#include <deque>
-#include "BufferedCharReader.hpp"
+#include <core/common/CharReader.hpp>
namespace ousia {
@@ -120,13 +121,13 @@ static const int TOKEN_TEXT = -2;
struct Token {
int tokenId;
std::string content;
- int startColumn;
- int startLine;
- int endColumn;
- int endLine;
+ uint32_t startColumn;
+ uint32_t startLine;
+ uint32_t endColumn;
+ uint32_t endLine;
- Token(int tokenId, std::string content, int startColumn, int startLine,
- int endColumn, int endLine)
+ Token(int tokenId, std::string content, uint32_t startColumn, uint32_t startLine,
+ uint32_t endColumn, uint32_t endLine)
: tokenId(tokenId),
content(content),
startColumn(startColumn),
@@ -160,7 +161,7 @@ struct Token {
*/
class Tokenizer {
private:
- BufferedCharReader &input;
+ CharReader &input;
const TokenTreeNode &root;
std::deque<Token> peeked;
unsigned int peekCursor = 0;
@@ -185,14 +186,14 @@ protected:
public:
/**
* @param input The input of a Tokenizer is given in the form of a
- * BufferedCharReader. Please refer to the respective documentation.
+ * CharReader. Please refer to the respective documentation.
* @param root This is meant to be the root of a TokenTree giving the
* specification of user-defined tokens this Tokenizer should recognize.
* The Tokenizer promises to not change the TokenTree such that you can
* re-use the same specification for multiple inputs.
* Please refer to the TokenTreeNode documentation for more information.
*/
- Tokenizer(BufferedCharReader &input, const TokenTreeNode &root);
+ Tokenizer(CharReader &input, const TokenTreeNode &root);
/**
* The next method consumes one Token from the input stream and gives
@@ -224,9 +225,9 @@ public:
*/
void consumePeek();
- const BufferedCharReader &getInput() const { return input; }
+ const CharReader &getInput() const { return input; }
- BufferedCharReader &getInput() { return input; }
+ CharReader &getInput() { return input; }
};
}
diff --git a/src/core/utils/CharReader.cpp b/src/core/common/CharReader.cpp
index c661b6f..4bd81ed 100644
--- a/src/core/utils/CharReader.cpp
+++ b/src/core/common/CharReader.cpp
@@ -17,15 +17,14 @@
*/
#include <algorithm>
+#include <cassert>
#include <limits>
#include <sstream>
-#include <core/Utils.hpp>
-
#include "CharReader.hpp"
+#include "Utils.hpp"
namespace ousia {
-namespace utils {
/* Helper functions */
@@ -80,6 +79,16 @@ Buffer::Buffer(const std::string &str)
startBucket = buckets.begin();
}
+#ifndef NDEBUG
+Buffer::~Buffer()
+{
+ // Make sure all cursors have been deleted
+ for (bool cursor_alive : alive) {
+ assert(!cursor_alive);
+ }
+}
+#endif
+
void Buffer::advance(BucketIterator &it)
{
it++;
@@ -507,7 +516,7 @@ CharReaderFork CharReader::fork()
return CharReaderFork(buffer, readCursor, peekCursor, coherent);
}
-CharReader::Context CharReader::getContext(ssize_t maxSize)
+TextCursor::Context CharReader::getContext(ssize_t maxSize)
{
// Clone the current read cursor
Buffer::CursorId cur = buffer->createCursor(readCursor.cursor);
@@ -603,7 +612,7 @@ CharReader::Context CharReader::getContext(ssize_t maxSize)
// Delete the newly created cursor
buffer->deleteCursor(cur);
- return CharReader::Context{ss.str(), relPos, !foundBegin || tStart != start,
+ return TextCursor::Context{ss.str(), relPos, !foundBegin || tStart != start,
!foundEnd || tEnd != end};
}
@@ -628,5 +637,4 @@ void CharReaderFork::commit()
parentPeekCursor.assign(buffer, peekCursor);
}
}
-}
diff --git a/src/core/utils/CharReader.hpp b/src/core/common/CharReader.hpp
index 5daa21d..7be5e08 100644
--- a/src/core/utils/CharReader.hpp
+++ b/src/core/common/CharReader.hpp
@@ -32,8 +32,9 @@
#include <memory>
#include <vector>
+#include "TextCursor.hpp"
+
namespace ousia {
-namespace utils {
/**
* A chunked ring buffer used in CharReader to provide access to an input stream
@@ -242,6 +243,14 @@ public:
*/
Buffer(const std::string &str);
+#ifndef NDEBUG
+ /**
+ * Destructor of the Buffer class. Makes sure that all cursors have been
+ * freed.
+ */
+ ~Buffer();
+#endif
+
// No copy
Buffer(const Buffer &) = delete;
@@ -352,52 +361,6 @@ class CharReaderFork;
* of linebreaks and converts these to a single '\n'.
*/
class CharReader {
-public:
- /**
- * The context struct is used to represent the current context the char
- * reader is in. This context can for example be used when building error
- * messages.
- */
- struct Context {
- /**
- * Set to the content of the current line.
- */
- std::string line;
-
- /**
- * Relative position (in characters) within that line.
- */
- size_t relPos;
-
- /**
- * Set to true if the beginning of the line has been truncated (because
- * the reader position is too far away from the actual position of the
- * line).
- */
- bool truncatedStart;
-
- /**
- * Set to true if the end of the line has been truncated (because the
- * reader position is too far away from the actual end position of the
- * line.
- */
- bool truncatedEnd;
-
- Context()
- : line(), relPos(0), truncatedStart(false), truncatedEnd(false)
- {
- }
-
- Context(std::string line, size_t relPos, bool truncatedStart,
- bool truncatedEnd)
- : line(std::move(line)),
- relPos(relPos),
- truncatedStart(truncatedStart),
- truncatedEnd(truncatedEnd)
- {
- }
- };
-
protected:
/**
* Internally used cursor structure for managing the read and the peek
@@ -412,19 +375,20 @@ protected:
/**
* Current line the cursor is in.
*/
- uint32_t line;
+ TextCursor::PosType line;
/**
* Current column the cursor is in.
*/
- uint32_t column;
+ TextCursor::PosType column;
/**
* Constructor of the Cursor class.
*
* @param cursor is the underlying cursor in the Buffer instance.
*/
- Cursor(Buffer::CursorId cursor, size_t line, size_t column)
+ Cursor(Buffer::CursorId cursor, TextCursor::PosType line,
+ TextCursor::PosType column)
: cursor(cursor), line(line), column(column)
{
}
@@ -584,31 +548,35 @@ public:
bool atEnd() const { return buffer->atEnd(readCursor.cursor); }
/**
- * Returns the current line (starting with one).
- *
- * @return the current line number.
+ * Returns the offset of the read cursor in bytes.
*/
- uint32_t getLine() const { return readCursor.line; }
+ size_t getOffset() const { return buffer->offset(readCursor.cursor); }
/**
- * Returns the current column (starting with one).
- *
- * @return the current column number.
+ * Returns the line number the read cursor currently is at.
*/
- uint32_t getColumn() const { return readCursor.column; }
+ TextCursor::PosType getLine() const { return readCursor.line; }
/**
- * Returns the current byte offset of the read cursor.
- *
- * @return the byte position within the stream.
+ * Returns the column the read cursor currently is at.
+ */
+ TextCursor::PosType getColumn() const { return readCursor.column; }
+
+ /**
+ * Returns the current position of the read cursor (line and column).
*/
- size_t getOffset() const { return buffer->offset(readCursor.cursor); };
+ TextCursor::Position getPosition() const
+ {
+ return TextCursor::Position(getLine(), getColumn(), getOffset());
+ }
/**
* Returns the line the read cursor currently is in, but at most the
* given number of characters in the form of a Context structure.
+ *
+ * @param maxSize is the maximum length of the extracted context
*/
- Context getContext(ssize_t maxSize);
+ TextCursor::Context getContext(ssize_t maxSize = 60);
};
/**
@@ -652,7 +620,6 @@ public:
void commit();
};
}
-}
#endif /* _OUSIA_CHAR_READER_HPP_ */
diff --git a/src/core/Exceptions.cpp b/src/core/common/Exceptions.cpp
index d064f35..30c5626 100644
--- a/src/core/Exceptions.cpp
+++ b/src/core/common/Exceptions.cpp
@@ -25,21 +25,21 @@ namespace ousia {
/* Class LoggableException */
std::string LoggableException::formatMessage(const std::string &msg,
- const std::string &file,
- int line, int column)
+ const TextCursor::Position &pos,
+ const TextCursor::Context &ctx)
{
std::stringstream ss;
ss << "error ";
- if (!file.empty()) {
- ss << "while processing \"" << file << "\" ";
- }
- if (line >= 0) {
- ss << "at line " << line << ", ";
- if (column >= 0) {
- ss << "column " << column << " ";
+ if (pos.hasLine()) {
+ ss << "at line " << pos.line << ", ";
+ if (pos.hasColumn()) {
+ ss << "column " << pos.column << " ";
}
}
ss << "with message: " << msg;
+ if (ctx.valid()) {
+ ss << " in context \"" << ctx.text << "\"";
+ }
return ss.str();
}
}
diff --git a/src/core/Exceptions.hpp b/src/core/common/Exceptions.hpp
index 00d6106..443c176 100644
--- a/src/core/Exceptions.hpp
+++ b/src/core/common/Exceptions.hpp
@@ -27,6 +27,8 @@
#ifndef _OUSIA_EXCEPTIONS_HPP_
#define _OUSIA_EXCEPTIONS_HPP_
+#include "TextCursor.hpp"
+
namespace ousia {
/**
@@ -81,80 +83,81 @@ private:
* reported to the runtime environment.
*/
static std::string formatMessage(const std::string &msg,
- const std::string &file, int line,
- int column);
+ const TextCursor::Position &pos,
+ const TextCursor::Context &ctx);
public:
/**
- * Message describing the error that occured.
+ * Reported error message.
*/
const std::string msg;
/**
- * Name of the file in which the error occured. May be empty.
+ * Position in the document at which the exception occurred.
*/
- const std::string file;
+ const TextCursor::Position pos;
/**
- * Line at which the exception occured. Negative values are ignored.
+ * Context in the document text in which the exception occurred.
*/
- const int line;
-
- /**
- * Column at which the exception occured. Negative values are ignored.
- */
- const int column;
+ const TextCursor::Context ctx;
/**
* Constructor of the LoggableException class.
*
* @param msg contains the error message.
- * @param file provides the context the message refers to. May be empty.
- * @param line is the line in the above file the message refers to.
- * @param column is the column in the above file the message refers to.
+ * @param pos is the position at which the error occured.
+ * @param ctx describes the context in which the error occured.
*/
- LoggableException(std::string msg, std::string file, int line = -1,
- int column = -1)
- : OusiaException(formatMessage(msg, file, line, column)),
+ LoggableException(std::string msg,
+ TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{})
+ : OusiaException(formatMessage(msg, pos, ctx)),
msg(std::move(msg)),
- file(std::move(file)),
- line(line),
- column(column)
+ pos(std::move(pos)),
+ ctx(std::move(ctx))
{
}
/**
- * Constructor of the LoggableException class with empty file.
+ * Constructor of the LoggableException class.
*
* @param msg contains the error message.
* @param line is the line in the above file the message refers to.
* @param column is the column in the above file the message refers to.
+ * @param offs is the byte offset.
*/
- LoggableException(std::string msg, int line = -1, int column = -1)
- : OusiaException(formatMessage(msg, "", line, column)),
- msg(std::move(msg)),
- line(line),
- column(column)
+ LoggableException(std::string msg, TextCursor::PosType line,
+ TextCursor::PosType column, size_t offs)
+ : LoggableException(msg, TextCursor::Position(line, column, offs))
{
}
/**
- * Constructor of the LoggableException class with empty file and an
- * position object.
+ * Constructor of LoggableException for arbitrary position objects.
*
* @param msg is the actual log message.
- * @param pos is a const reference to a variable which provides position
- * information.
+ * @param pos is a reference to a variable with position and context data.
*/
template <class PosType>
- LoggableException(std::string msg, const PosType &pos)
- : OusiaException(
- formatMessage(msg, "", pos.getLine(), pos.getColumn())),
- msg(std::move(msg)),
- line(pos.getLine()),
- column(pos.getColumn())
+ LoggableException(std::string msg, PosType &pos)
+ : LoggableException(std::move(msg), pos.getPosition(), pos.getContext())
{
}
+
+ /**
+ * Returns the position at which the exception occured in the text.
+ *
+ * @return the position descriptor.
+ */
+ TextCursor::Position getPosition() const { return pos; }
+
+ /**
+ * Returns the context in which the exception occured in the text.
+ *
+ * @return the context descriptor.
+ */
+ TextCursor::Context getContext() const { return ctx; }
};
}
diff --git a/src/core/Logger.cpp b/src/core/common/Logger.cpp
index 17f55a6..c1d6343 100644
--- a/src/core/Logger.cpp
+++ b/src/core/common/Logger.cpp
@@ -25,48 +25,66 @@ namespace ousia {
/* Class Logger */
-void Logger::log(Severity severity, const std::string &msg,
- const std::string &file, int line, int column)
+void Logger::log(Severity severity, std::string msg, TextCursor::Position pos,
+ TextCursor::Context ctx)
{
- // Copy the current severity level
+ // Update the maximum encountered severity level
if (static_cast<int>(severity) > static_cast<int>(maxEncounteredSeverity)) {
maxEncounteredSeverity = severity;
}
- // Call the actual log message function if the severity is larger or equal
- // to the minimum severity
+ // Only process the message if its severity is larger than the
+ // set minimum severity.
if (static_cast<int>(severity) >= static_cast<int>(minSeverity)) {
- process(Message{severity, msg, file, line, column});
+ processMessage(
+ Message{severity, std::move(msg), std::move(pos), std::move(ctx)});
}
}
-unsigned int Logger::pushFilename(const std::string &name)
+LoggerFork Logger::fork() { return LoggerFork{this, minSeverity}; }
+
+/* Class LoggerFork */
+
+void LoggerFork::processMessage(Message msg)
+{
+ calls.push_back(Call(CallType::MESSAGE, messages.size()));
+ messages.push_back(msg);
+}
+
+void LoggerFork::processPushFile(File file)
{
- filenameStack.push(name);
- return filenameStack.size();
+ calls.push_back(Call(CallType::PUSH_FILE, files.size()));
+ files.push_back(file);
}
-unsigned int Logger::popFilename()
+void LoggerFork::processPopFile()
{
- filenameStack.pop();
- return filenameStack.size();
+ calls.push_back(Call(CallType::POP_FILE, 0));
}
-void Logger::unwindFilenameStack(unsigned int pos)
+void LoggerFork::commit()
{
- while (filenameStack.size() > pos && !filenameStack.empty()) {
- filenameStack.pop();
+ for (const Call &call : calls) {
+ switch (call.type) {
+ case CallType::MESSAGE: {
+ const Message &msg = messages[call.dataIdx];
+ parent->log(msg.severity, msg.msg, msg.pos, msg.ctx);
+ break;
+ }
+ case CallType::PUSH_FILE: {
+ const File &file = files[call.dataIdx];
+ parent->pushFile(file.file, file.pos, file.ctx);
+ break;
+ }
+ case CallType::POP_FILE:
+ parent->popFile();
+ break;
+ }
}
}
-/* Class TerminalLogger */
+/* Class Terminal */
-/**
- * Small class used internally for formated terminal output using ANSI/VT100
- * escape codes on supported terminals.
- *
- * TODO: Deactivate if using windows or use the corresponding API function.
- */
class Terminal {
private:
/**
@@ -109,29 +127,47 @@ public:
}
};
-void TerminalLogger::process(const Message &msg)
+/* Class TerminalLogger */
+
+/**
+ * Small class used internally for formated terminal output using ANSI/VT100
+ * escape codes on supported terminals.
+ *
+ * TODO: Deactivate if using windows or use the corresponding API function.
+ */
+
+std::string TerminalLogger::currentFilename()
+{
+ if (!files.empty()) {
+ return files.top().file;
+ }
+ return std::string{};
+}
+
+void TerminalLogger::processMessage(Message msg)
{
Terminal t(useColor);
// Print the file name
- if (msg.hasFile()) {
- os << t.color(Terminal::WHITE, true) << msg.file << t.reset();
+ std::string filename = currentFilename();
+ bool hasFile = !filename.empty();
+ if (hasFile) {
+ os << t.color(Terminal::WHITE, true) << filename << t.reset();
}
// Print line and column number
- if (msg.hasLine()) {
- if (msg.hasFile()) {
+ if (msg.pos.hasLine()) {
+ if (hasFile) {
os << ':';
}
- os << t.color(Terminal::WHITE, true) << msg.line
- << t.reset();
- if (msg.hasColumn()) {
- os << ':' << msg.column;
+ os << t.color(Terminal::WHITE, true) << msg.pos.line << t.reset();
+ if (msg.pos.hasColumn()) {
+ os << ':' << msg.pos.column;
}
}
// Print the optional seperator
- if (msg.hasFile() || msg.hasLine()) {
+ if (hasFile || msg.pos.hasLine()) {
os << ": ";
}
@@ -156,6 +192,28 @@ void TerminalLogger::process(const Message &msg)
// Print the actual message
os << msg.msg << std::endl;
+
+ // Print the error message context if available
+ if (msg.ctx.valid()) {
+ size_t relPos = msg.ctx.relPos;
+ if (msg.ctx.truncatedStart) {
+ os << "[...] ";
+ relPos += 6;
+ }
+ os << msg.ctx.text;
+ if (msg.ctx.truncatedEnd) {
+ os << " [...]";
+ }
+ os << std::endl;
+ for (size_t i = 0; i < relPos; i++) {
+ os << ' ';
+ }
+ os << t.color(Terminal::GREEN) << '^' << t.reset() << std::endl;
+ }
}
+
+void TerminalLogger::processPushFile(File file) { files.push(file); }
+
+void TerminalLogger::processPopFile() { files.pop(); }
}
diff --git a/src/core/common/Logger.hpp b/src/core/common/Logger.hpp
new file mode 100644
index 0000000..be82ea0
--- /dev/null
+++ b/src/core/common/Logger.hpp
@@ -0,0 +1,602 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file Logger.hpp
+ *
+ * Contains classes for logging messages in Ousía. Provides a generic Logger
+ * class, and TerminalLogger, an extension of Logger which logs do an output
+ * stream.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_LOGGER_HPP_
+#define _OUSIA_LOGGER_HPP_
+
+#include <ostream>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "Exceptions.hpp"
+#include "TextCursor.hpp"
+
+namespace ousia {
+
+/**
+ * Enum containing the severities used for logging errors and debug messages.
+ */
+enum class Severity : int {
+ /**
+ * Indicates that this message was only printed for debugging. Note that
+ * in release builds messages with this severity are discarded.
+ */
+ DEBUG = 0,
+
+ /**
+ * A message which might provide additional information to the user.
+ */
+ NOTE = 1,
+
+ /**
+ * A message which warns of possible mistakes by the user which might not be
+ * actual errors but may lead to unintended behaviour.
+ */
+ WARNING = 2,
+
+ /**
+ * An error occurred while processing, however program execution continues,
+ * trying to deal with the error situation (graceful degradation). However,
+ * messages with this severity may be followed up by fatal errors.
+ */
+ ERROR = 3,
+
+ /**
+ * A fatal error occurred. Program execution cannot continue.
+ */
+ FATAL_ERROR = 4
+};
+
+#ifdef NDEBUG
+static constexpr Severity DEFAULT_MIN_SEVERITY = Severity::NOTE;
+#else
+static constexpr Severity DEFAULT_MIN_SEVERITY = Severity::DEBUG;
+#endif
+
+// Forward declaration
+class LoggerFork;
+
+/**
+ * The Logger class is the base class the individual logging systems should
+ * derive from. It provides a simple interface for logging errors, warnings and
+ * notes and filters these according to the set minimum severity. Additionally
+ * a stack of file names is maintained in order to allow simple descent into
+ * included files. Note however, that this base Logger class simply discards the
+ * incomming log messages. Use one of the derived classes to actually handle the
+ * log messages.
+ */
+class Logger {
+public:
+ /**
+ * Describes an included file.
+ */
+ struct File {
+ /**
+ * Is the name of the file.
+ */
+ std::string file;
+
+ /**
+ * Position at which the file was included.
+ */
+ TextCursor::Position pos;
+
+ /**
+ * Context in which the file was included.
+ */
+ TextCursor::Context ctx;
+
+ /**
+ * Constructor of the File struct.
+ *
+ * @param file is the name of the included file.
+ * @param pos is the position in the parent file, at which this file
+ * was included.
+ * @param ctx is the context in which the feil was included.
+ */
+ File(std::string file, TextCursor::Position pos,
+ TextCursor::Context ctx)
+ : file(file), pos(pos), ctx(ctx)
+ {
+ }
+ };
+
+ /**
+ * The message struct represents a single log message and all information
+ * attached to it.
+ */
+ struct Message {
+ /**
+ * Severity of the log message.
+ */
+ Severity severity;
+
+ /**
+ * Actual log message.
+ */
+ std::string msg;
+
+ /**
+ * Position in the text the message refers to.
+ */
+ TextCursor::Position pos;
+
+ /**
+ * Context the message refers to.
+ */
+ TextCursor::Context ctx;
+
+ /**
+ * Constructor of the Message struct.
+ *
+ * @param severity describes the message severity.
+ * @param msg contains the actual message.
+ * @param line is the line in the above file the message refers to.
+ * @param column is the column in the above file the message refers to.
+ */
+ Message(Severity severity, std::string msg, TextCursor::Position pos,
+ TextCursor::Context ctx)
+ : severity(severity),
+ msg(std::move(msg)),
+ pos(std::move(pos)),
+ ctx(std::move(ctx)){};
+ };
+
+protected:
+ /**
+ * Minimum severity a log message should have before it is discarded.
+ */
+ const Severity minSeverity;
+
+ /**
+ * Maximum encountered log message severity.
+ */
+ Severity maxEncounteredSeverity;
+
+ /**
+ * Function to be overriden by child classes to actually display or store
+ * the messages. The default implementation just discards all incomming
+ * messages.
+ *
+ * @param msg is an instance of the Message struct containing the data that
+ * should be logged.
+ */
+ virtual void processMessage(Message msg) {}
+
+ /**
+ * Called whenever a new file is pushed onto the stack.
+ *
+ * @param file is the file that should be pushed onto the stack.
+ */
+ virtual void processPushFile(File file) {}
+
+ /**
+ * Called whenever a file is popped from the stack.
+ */
+ virtual void processPopFile() {}
+
+public:
+ /**
+ * Constructor of the Logger class.
+ *
+ * @param minSeverity is the minimum severity a log message should have.
+ * Messages below this severity are discarded.
+ */
+ Logger(Severity minSeverity = DEFAULT_MIN_SEVERITY)
+ : minSeverity(minSeverity), maxEncounteredSeverity(Severity::DEBUG)
+ {
+ }
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~Logger(){};
+
+ // No copy
+ Logger(const Logger &) = delete;
+
+ // No assign
+ Logger &operator=(const Logger &) = delete;
+
+ /**
+ * Logs the given message. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param severity is the severity of the log message.
+ * @param msg is the actual log message.
+ * @param pos is the position the log message refers to.
+ * @param ctx describes the context of the log message.
+ */
+ void log(Severity severity, std::string msg,
+ TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{});
+
+ /**
+ * Logs the given loggable exception.
+ *
+ * @param ex is the exception that should be logged.
+ */
+ void log(const LoggableException &ex)
+ {
+ log(Severity::ERROR, ex.msg, ex.getPosition(), ex.getContext());
+ }
+
+ /**
+ * Logs the given message. The file name is set to the topmost file name on
+ * the file name stack.
+ *
+ * @param severity is the severity of the log message.
+ * @param msg is the actual log message.
+ * @param pos is a reference to a variable which provides position and
+ * context information.
+ */
+ template <class PosType>
+ void logAt(Severity severity, std::string msg, PosType &pos)
+ {
+ log(severity, std::move(msg), pos.getPosition(), pos.getContext());
+ }
+
+ /**
+ * Logs a debug message. Debug messages will be discarded if the software
+ * is compiled in the release mode (with the NDEBUG flag).
+ *
+ * @param msg is the actual log message.
+ * @param pos describes the position of the debug message.
+ * @param ctx describes the context of the debug message.
+ */
+ void debug(std::string msg,
+ TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{})
+ {
+#ifndef NDEBUG
+ log(Severity::DEBUG, std::move(msg), std::move(pos), std::move(ctx));
+#endif
+ }
+
+ /**
+ * Logs a debug message. Debug messages will be discarded if the software
+ * is compiled in the release mode.
+ *
+ * @param msg is the actual log message.
+ * @param pos is a reference to a variable which provides position and
+ * context information.
+ */
+ template <class PosType>
+ void debug(std::string msg, PosType &pos)
+ {
+#ifndef NDEBUG
+ logAt(Severity::DEBUG, std::move(msg), pos);
+#endif
+ }
+
+ /**
+ * Logs a note.
+ *
+ * @param msg is the actual log message.
+ * @param pos describes the position of the note.
+ * @param ctx describes the context of the note.
+ */
+ void note(std::string msg,
+ TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{})
+ {
+ log(Severity::NOTE, std::move(msg), std::move(pos), std::move(ctx));
+ }
+
+ /**
+ * Logs a note.
+ *
+ * @param msg is the actual log message.
+ * @param pos is a reference to a variable which provides position and
+ * context information.
+ */
+ template <class PosType>
+ void note(std::string msg, PosType &pos)
+ {
+ logAt(Severity::NOTE, std::move(msg), pos);
+ }
+
+ /**
+ * Logs a warning.
+ *
+ * @param msg is the actual log message.
+ * @param pos describes the position of the warning.
+ * @param ctx describes the context of the warning.
+ */
+ void warning(std::string msg,
+ TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{})
+ {
+ log(Severity::WARNING, std::move(msg), std::move(pos), std::move(ctx));
+ }
+
+ /**
+ * Logs a warning.
+ *
+ * @param msg is the actual log message.
+ * @param pos is a reference to a variable which provides position and
+ * context information.
+ */
+ template <class PosType>
+ void warning(std::string msg, PosType &pos)
+ {
+ logAt(Severity::WARNING, std::move(msg), pos);
+ }
+
+ /**
+ * Logs an error message.
+ *
+ * @param msg is the actual log message.
+ * @param pos is the position at which the error occured.
+ * @param ctx describes the context in which the error occured.
+ */
+ void error(std::string msg,
+ TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{})
+ {
+ log(Severity::ERROR, std::move(msg), std::move(pos), std::move(ctx));
+ }
+
+ /**
+ * Logs an error message.
+ *
+ * @param msg is the actual log message.
+ * @param pos is a reference to a variable which provides position and
+ * context information.
+ */
+ template <class PosType>
+ void error(std::string msg, PosType &pos)
+ {
+ logAt(Severity::ERROR, std::move(msg), pos);
+ }
+
+ /**
+ * Logs a fatal error message.
+ *
+ * @param msg is the actual log message.
+ * @param pos is the position at which the error occured.
+ * @param ctx describes the context in which the error occured.
+ */
+ void fatalError(std::string msg,
+ TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{})
+ {
+ log(Severity::FATAL_ERROR, std::move(msg), std::move(pos),
+ std::move(ctx));
+ }
+
+ /**
+ * Logs a fatal error message.
+ *
+ * @param msg is the actual log message.
+ * @param pos is a reference to a variable which provides position and
+ * context information.
+ */
+ template <class PosType>
+ void fatalError(std::string msg, PosType &pos)
+ {
+ logAt(Severity::FATAL_ERROR, std::move(msg), pos);
+ }
+
+ /**
+ * Pushes a new file name onto the internal filename stack.
+ *
+ * @param name is the name of the file to be added to the stack.
+ * @param pos is the position from which the new file is included.
+ * @param ctx is the context in which the new file is included.
+ */
+ void pushFile(std::string name,
+ TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{})
+ {
+ processPushFile(File(std::move(name), std::move(pos), std::move(ctx)));
+ }
+
+ /**
+ * Pops the filename from the internal filename stack.
+ *
+ * @return the current size of the filename stack.
+ */
+ void popFile() { processPopFile(); }
+
+ /**
+ * Returns the maximum severity that was encountered by the Logger but at
+ * least Severity::DEBUG.
+ *
+ * @return the severity of the most severe log message but at least
+ * Severity::DEBUG.
+ */
+ Severity getMaxEncounteredSeverity() { return maxEncounteredSeverity; }
+
+ /**
+ * Returns the minimum severity. Messages with a smaller severity are
+ * discarded.
+ *
+ * @return the minimum severity.
+ */
+ Severity getMinSeverity() { return minSeverity; }
+
+ /**
+ * Returns a forked logger instance which can be used to collect log
+ * messages for which it is not sure whether they will be used.
+ */
+ LoggerFork fork();
+};
+
+/**
+ * Fork of the Logger -- stores all logged messages without actually pushing
+ * them to the underlying logger instance.
+ */
+class LoggerFork : public Logger {
+private:
+ friend Logger;
+
+ /**
+ * Intanally used to store the incomming function calls.
+ */
+ enum class CallType { MESSAGE, PUSH_FILE, POP_FILE };
+
+ /**
+ * Datastructure used to represent a logger function call.
+ */
+ struct Call {
+ /**
+ * Type of the function call.
+ */
+ CallType type;
+
+ /**
+ * Index of the associated data in the type-specific vector.
+ */
+ size_t dataIdx;
+
+ /**
+ * Constructor of the Call structure.
+ *
+ * @param type is the type of the call.
+ * @param dataIdx is the index of the associated data in the type
+ * specific data vector.
+ */
+ Call(CallType type, size_t dataIdx) : type(type), dataIdx(dataIdx) {}
+ };
+
+ /**
+ * Vector storing all incomming calls.
+ */
+ std::vector<Call> calls;
+
+ /**
+ * Vector storing all incomming messages.
+ */
+ std::vector<Message> messages;
+
+ /**
+ * Vector storing all incomming pushed files.
+ */
+ std::vector<File> files;
+
+ /**
+ * Parent logger instance.
+ */
+ Logger *parent;
+
+ /**
+ * Constructor of the LoggerFork class.
+ *
+ * @param minSeverity is the minimum severity a message should have to be
+ * stored.
+ * @param parent is the parent logger instance.
+ */
+ LoggerFork(Logger *parent, Severity minSeverity)
+ : Logger(minSeverity), parent(parent)
+ {
+ }
+
+protected:
+ void processMessage(Message msg) override;
+ void processPushFile(File file) override;
+ void processPopFile() override;
+
+public:
+ /**
+ * Commits all collected messages to the parent Logger instance.
+ */
+ void commit();
+
+ /**
+ * Explicitly declared move constructor.
+ */
+ LoggerFork(LoggerFork &&l)
+ : Logger(l.getMinSeverity()),
+ calls(std::move(l.calls)),
+ messages(std::move(l.messages)),
+ files(std::move(l.files)),
+ parent(std::move(l.parent))
+ {
+ }
+};
+
+/**
+ * Class extending the Logger class and printing the log messages to the given
+ * stream.
+ */
+class TerminalLogger : public Logger {
+private:
+ /**
+ * Reference to the target output stream.
+ */
+ std::ostream &os;
+
+ /**
+ * If true, the TerminalLogger will use colors to make the log messages
+ * prettier.
+ */
+ bool useColor;
+
+ /**
+ * Stack used to keep the file references.
+ */
+ std::stack<File> files;
+
+ /**
+ * The size of the stack the last time a file backtrace was printed.
+ */
+ size_t lastFilePrinted = 0;
+
+protected:
+ void processMessage(Message msg) override;
+ void processPushFile(File file) override;
+ void processPopFile() override;
+
+public:
+ /**
+ * Constructor of the TerminalLogger class.
+ *
+ * @param os is the output stream the log messages should be logged to.
+ * Should be set to std::cerr in most cases.
+ * @param useColor if true, the TerminalLogger class will do its best to
+ * use ANSI/VT100 control sequences for colored log messages.
+ * @param minSeverity is the minimum severity below which log messages are
+ * discarded.
+ */
+ TerminalLogger(std::ostream &os, bool useColor = false,
+ Severity minSeverity = DEFAULT_MIN_SEVERITY)
+ : Logger(minSeverity), os(os), useColor(useColor)
+ {
+ }
+
+ /**
+ * Returns the name of the topmost file.
+ */
+ std::string currentFilename();
+};
+}
+
+#endif /* _OUSIA_LOGGER_HPP_ */
+
diff --git a/src/core/common/TextCursor.hpp b/src/core/common/TextCursor.hpp
new file mode 100644
index 0000000..2633345
--- /dev/null
+++ b/src/core/common/TextCursor.hpp
@@ -0,0 +1,168 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _OUSIA_TEXT_CURSOR_HPP_
+#define _OUSIA_TEXT_CURSOR_HPP_
+
+namespace ousia {
+namespace TextCursor {
+
+/**
+ * Type used for representing line or column positions.
+ */
+using PosType = unsigned int;
+
+/**
+ * Struct representing a position within the text. A position is defined by a
+ * byte offset (which is always reproducable), a line number and a column
+ * number.
+ */
+struct Position {
+ /**
+ * Current line, starting with one.
+ */
+ PosType line;
+
+ /**
+ * Current column, starting with one.
+ */
+ PosType column;
+
+ /**
+ * Current byte offset.
+ */
+ size_t offs;
+
+ /**
+ * Default constructor of the Position struct, initializes all memebers
+ * with zero.
+ */
+ Position() : line(0), column(0), offs(0) {}
+
+ /**
+ * Creates a new Position struct with only a line and no column.
+ *
+ * @param line is the line number.
+ * @param column is the column number.
+ */
+ Position(PosType line) : line(line), column(0), offs(0) {}
+
+ /**
+ * Creates a new Position struct with a line and column.
+ *
+ * @param line is the line number.
+ * @param column is the column number.
+ */
+ Position(PosType line, PosType column) : line(line), column(column), offs(0)
+ {
+ }
+
+ /**
+ * Creates a new Position struct with a line, column and byte offset.
+ *
+ * @param line is the line number.
+ * @param column is the column number.
+ * @param offs is the byte offset.
+ */
+ Position(PosType line, PosType column, size_t offs)
+ : line(line), column(column), offs(offs)
+ {
+ }
+
+ /**
+ * Returns true, if the line number is valid, false otherwise.
+ *
+ * @return true for valid line numbers.
+ */
+ bool hasLine() const { return line > 0; }
+
+ /**
+ * Returns true, if the column number is valid, false otherwise.
+ *
+ * @return true for valid column numbers.
+ */
+ bool hasColumn() const { return column > 0; }
+};
+
+/**
+ * Represents the current context a CharReader is in. Used for building error
+ * messages.
+ */
+struct Context {
+ /**
+ * Set to the content of the current line.
+ */
+ std::string text;
+
+ /**
+ * Relative position (in characters) within that line. May point to
+ * locations beyond the text content.
+ */
+ PosType relPos;
+
+ /**
+ * Set to true if the beginning of the line has been truncated (because
+ * the reader position is too far away from the actual position of the
+ * line).
+ */
+ bool truncatedStart;
+
+ /**
+ * Set to true if the end of the line has been truncated (because the
+ * reader position is too far away from the actual end position of the
+ * line.
+ */
+ bool truncatedEnd;
+
+ /**
+ * Default constructor, initializes all members with zero values.
+ */
+ Context() : text(), relPos(0), truncatedStart(false), truncatedEnd(false) {}
+
+ /**
+ * Constructor of the Context class.
+ *
+ * @param text is the current line the text cursor is at.
+ * @param relPos is the relative position of the text cursor within that
+ * line.
+ * @param truncatedStart specifies whether the text was truncated at the
+ * beginning.
+ * @param truncatedEnd specifies whether the text was truncated at the
+ * end.
+ */
+ Context(std::string text, size_t relPos, bool truncatedStart,
+ bool truncatedEnd)
+ : text(std::move(text)),
+ relPos(relPos),
+ truncatedStart(truncatedStart),
+ truncatedEnd(truncatedEnd)
+ {
+ }
+
+ /**
+ * Returns true the context text is not empty.
+ *
+ * @return true if the context is valid and e.g. should be printed.
+ */
+ bool valid() const { return !text.empty(); }
+};
+}
+}
+
+#endif /* _OUSIA_TEXT_CURSOR_HPP_ */
+
diff --git a/src/core/Utils.cpp b/src/core/common/Utils.cpp
index c460ed4..c460ed4 100644
--- a/src/core/Utils.cpp
+++ b/src/core/common/Utils.cpp
diff --git a/src/core/Utils.hpp b/src/core/common/Utils.hpp
index 5332b50..5332b50 100644
--- a/src/core/Utils.hpp
+++ b/src/core/common/Utils.hpp
diff --git a/src/core/variant/Variant.cpp b/src/core/common/Variant.cpp
index d33cd4f..27fc6e7 100644
--- a/src/core/variant/Variant.cpp
+++ b/src/core/common/Variant.cpp
@@ -18,8 +18,7 @@
#include <sstream>
-#include <core/Utils.hpp>
-
+#include "Utils.hpp"
#include "Variant.hpp"
namespace ousia {
diff --git a/src/core/variant/Variant.hpp b/src/core/common/Variant.hpp
index 1e62644..d411fd3 100644
--- a/src/core/variant/Variant.hpp
+++ b/src/core/common/Variant.hpp
@@ -39,10 +39,9 @@
// http://nikic.github.io/2012/02/02/Pointer-magic-for-efficient-dynamic-value-representations.html
// later (will allow to use 8 bytes for a variant)
-#include <core/Exceptions.hpp>
+#include "Exceptions.hpp"
namespace ousia {
-namespace variant {
/**
* Instances of the Variant class represent any kind of data that is exchanged
@@ -758,9 +757,5 @@ public:
};
}
-// Alias for the (very often used and unambigous) variant class
-using Variant = variant::Variant;
-}
-
#endif /* _OUSIA_VARIANT_HPP_ */
diff --git a/src/core/variant/Reader.cpp b/src/core/common/VariantReader.cpp
index ba857af..a31a658 100644
--- a/src/core/variant/Reader.cpp
+++ b/src/core/common/VariantReader.cpp
@@ -21,18 +21,16 @@
#include <cmath>
#include <sstream>
-#include <core/Utils.hpp>
-
-#include "Reader.hpp"
+#include "VariantReader.hpp"
+#include "Utils.hpp"
namespace ousia {
-namespace variant {
// TODO: Better error messages (like "Expected 'x' but got 'y'")
// TODO: Replace delims with single char delim where possible
// TODO: Use custom return value instead of std::pair
// TODO: Allow buffered char reader to "fork"
-// TODO: Rename BufferedCharReader to shorter CharReader
+// TODO: Rename CharReader to shorter CharReader
// TODO: Implement context in CharReader (to allow error messages to extract the
// current line)
@@ -97,13 +95,13 @@ private:
* Appends the value of the character c to the internal number
* representation and reports any errors that might occur.
*/
- bool appendChar(char c, int base, Part p, BufferedCharReader &reader,
+ bool appendChar(char c, int base, Part p, CharReader &reader,
Logger &logger)
{
// Check whether the given character is valid
int v = charValue(c);
if (v < 0 || v >= base) {
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
+ logger.error(ERR_UNEXPECTED_CHAR, reader);
return false;
}
@@ -123,7 +121,7 @@ private:
// Check for any overflows
if (a < 0 || n < 0 || d < 0 || e < 0) {
- logger.errorAt(ERR_TOO_LARGE, reader);
+ logger.error(ERR_TOO_LARGE, reader);
return false;
}
return true;
@@ -176,135 +174,139 @@ public:
* the given logger instance. Numbers are terminated by one of the given
* delimiters.
*/
- bool parse(BufferedCharReader &reader, Logger &logger,
- const std::unordered_set<char> &delims)
- {
- State state = State::INIT;
- char c;
+ bool parse(CharReader &reader, Logger &logger,
+ const std::unordered_set<char> &delims);
+};
- // Consume the first whitespace characters
- reader.consumeWhitespace();
+bool Number::parse(CharReader &reader, Logger &logger,
+ const std::unordered_set<char> &delims)
+{
+ State state = State::INIT;
+ char c;
- // Iterate over the FSM to extract numbers
- while (reader.peek(&c)) {
- // Abort, once a delimiter or whitespace is reached
- if (Utils::isWhitespace(c) || delims.count(c)) {
- reader.resetPeek();
- break;
- }
+ // Consume the first whitespace characters
+ reader.consumeWhitespace();
- // The character is not a whitespace character and not a delimiter
- switch (state) {
- case State::INIT:
- case State::HAS_MINUS:
- switch (c) {
- case '-':
- // Do not allow multiple minus signs
- if (state == State::HAS_MINUS) {
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
- return false;
- }
- state = State::HAS_MINUS;
- s = -1;
- break;
- case '0':
- // Remember a leading zero for the detection of "0x"
- state = State::LEADING_ZERO;
- break;
- case '.':
- // Remember a leading point as ".eXXX" is invalid
- state = State::LEADING_POINT;
- break;
- default:
- state = State::INT;
- if (!appendChar(c, 10, Part::A, reader, logger)) {
- return false;
- }
- break;
- }
- break;
- case State::LEADING_ZERO:
- if (c == 'x' || c == 'X') {
- state = State::HEX;
+ // Iterate over the FSM to extract numbers
+ while (reader.peek(c)) {
+ // Abort, once a delimiter or whitespace is reached
+ if (Utils::isWhitespace(c) || delims.count(c)) {
+ reader.resetPeek();
+ break;
+ }
+
+ // The character is not a whitespace character and not a delimiter
+ switch (state) {
+ case State::INIT:
+ case State::HAS_MINUS:
+ switch (c) {
+ case '-':
+ // Do not allow multiple minus signs
+ if (state == State::HAS_MINUS) {
+ logger.error(ERR_UNEXPECTED_CHAR, reader);
+ return false;
+ }
+ state = State::HAS_MINUS;
+ s = -1;
break;
- }
- // fallthrough
- case State::INT:
- switch (c) {
- case '.':
- state = State::POINT;
- break;
- case 'e':
- case 'E':
- state = State::EXP_INIT;
- break;
- default:
- state = State::INT;
- if (!appendChar(c, 10, Part::A, reader, logger)) {
- return false;
- }
- break;
- }
- break;
- case State::HEX:
- if (!appendChar(c, 16, Part::A, reader, logger)) {
- return false;
- }
- break;
- case State::LEADING_POINT:
- case State::POINT:
- switch (c) {
- case 'e':
- case 'E':
- if (state == State::LEADING_POINT) {
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
- return false;
- }
- state = State::EXP_INIT;
- break;
- default:
- state = State::POINT;
- if (!appendChar(c, 10, Part::N, reader, logger)) {
- return false;
- }
- break;
- }
+ case '0':
+ // Remember a leading zero for the detection of "0x"
+ state = State::LEADING_ZERO;
+ break;
+ case '.':
+ // Remember a leading point as ".eXXX" is invalid
+ state = State::LEADING_POINT;
+ break;
+ default:
+ state = State::INT;
+ if (!appendChar(c, 10, Part::A, reader, logger)) {
+ return false;
+ }
+ break;
+ }
+ break;
+ case State::LEADING_ZERO:
+ if (c == 'x' || c == 'X') {
+ state = State::HEX;
break;
- case State::EXP_HAS_MINUS:
- case State::EXP_INIT:
- if (c == '-') {
- if (state == State::EXP_HAS_MINUS) {
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
+ }
+ // fallthrough
+ case State::INT:
+ switch (c) {
+ case '.':
+ state = State::POINT;
+ break;
+ case 'e':
+ case 'E':
+ state = State::EXP_INIT;
+ break;
+ default:
+ state = State::INT;
+ if (!appendChar(c, 10, Part::A, reader, logger)) {
+ return false;
+ }
+ break;
+ }
+ break;
+ case State::HEX:
+ if (!appendChar(c, 16, Part::A, reader, logger)) {
+ return false;
+ }
+ break;
+ case State::LEADING_POINT:
+ case State::POINT:
+ switch (c) {
+ case 'e':
+ case 'E':
+ if (state == State::LEADING_POINT) {
+ logger.error(ERR_UNEXPECTED_CHAR, reader);
return false;
}
- state = State::EXP_HAS_MINUS;
- sE = -1;
- } else {
- state = State::EXP;
- if (!appendChar(c, 10, Part::E, reader, logger)) {
+ state = State::EXP_INIT;
+ break;
+ default:
+ state = State::POINT;
+ if (!appendChar(c, 10, Part::N, reader, logger)) {
return false;
}
+ break;
+ }
+ break;
+ case State::EXP_HAS_MINUS:
+ case State::EXP_INIT:
+ if (c == '-') {
+ if (state == State::EXP_HAS_MINUS) {
+ logger.error(ERR_UNEXPECTED_CHAR, reader);
+ return false;
}
- break;
- case State::EXP:
+ state = State::EXP_HAS_MINUS;
+ sE = -1;
+ } else {
+ state = State::EXP;
if (!appendChar(c, 10, Part::E, reader, logger)) {
return false;
}
- break;
- }
- reader.consumePeek();
+ }
+ break;
+ case State::EXP:
+ if (!appendChar(c, 10, Part::E, reader, logger)) {
+ return false;
+ }
+ break;
}
+ reader.consumePeek();
+ }
- // States in which ending is valid. Log an error in other states
- if (state == State::LEADING_ZERO || state == State::HEX ||
- state == State::INT || state == State::POINT ||
- state == State::EXP) {
- return true;
- }
- logger.errorAt(ERR_UNEXPECTED_END, reader);
- return false;
+ // States in which ending is valid. Log an error in other states
+ if (state == State::LEADING_ZERO || state == State::HEX ||
+ state == State::INT || state == State::POINT ||
+ state == State::EXP) {
+ return true;
}
-};
+ logger.error(ERR_UNEXPECTED_END, reader);
+ return false;
+}
+
/* Class Reader */
@@ -317,15 +319,15 @@ static const int STATE_WHITESPACE = 5;
static const int STATE_RESYNC = 6;
template <class T>
-static std::pair<bool, T> error(BufferedCharReader &reader, Logger &logger,
+static std::pair<bool, T> error(CharReader &reader, Logger &logger,
const char *err, T res)
{
- logger.errorAt(err, reader);
+ logger.error(err, reader);
return std::make_pair(false, std::move(res));
}
-std::pair<bool, std::string> Reader::parseString(
- BufferedCharReader &reader, Logger &logger,
+std::pair<bool, std::string> VariantReader::parseString(
+ CharReader &reader, Logger &logger,
const std::unordered_set<char> *delims)
{
// Initialize the internal state
@@ -339,9 +341,9 @@ std::pair<bool, std::string> Reader::parseString(
// Statemachine whic iterates over each character in the stream
// TODO: Combination of peeking and consumePeek is stupid as consumePeek is
// the default (read and putBack would obviously be better, yet the latter
- // is not trivial to implement in the current BufferedCharReader).
+ // is not trivial to implement in the current CharReader).
char c;
- while (reader.peek(&c)) {
+ while (reader.peek(c)) {
switch (state) {
case STATE_INIT:
if (c == '"' || c == '\'') {
@@ -408,7 +410,7 @@ std::pair<bool, std::string> Reader::parseString(
if (Utils::isNumeric(c)) {
// TODO: Parse octal 000 sequence
} else {
- logger.errorAt(ERR_INVALID_ESCAPE, reader);
+ logger.error(ERR_INVALID_ESCAPE, reader);
}
break;
}
@@ -422,8 +424,8 @@ std::pair<bool, std::string> Reader::parseString(
return error(reader, logger, ERR_UNEXPECTED_END, res.str());
}
-std::pair<bool, Variant::arrayType> Reader::parseArray(
- BufferedCharReader &reader, Logger &logger, char delim)
+std::pair<bool, Variant::arrayType> VariantReader::parseArray(
+ CharReader &reader, Logger &logger, char delim)
{
Variant::arrayType res;
bool hadError = false;
@@ -436,7 +438,7 @@ std::pair<bool, Variant::arrayType> Reader::parseArray(
// Iterate over the characters, use the parseGeneric function to read the
// pairs
- while (reader.peek(&c)) {
+ while (reader.peek(c)) {
// Generically handle the end of the array
if (state != STATE_INIT && c == delim) {
reader.consumePeek();
@@ -474,7 +476,7 @@ std::pair<bool, Variant::arrayType> Reader::parseArray(
} else if (!Utils::isWhitespace(c)) {
hadError = true;
state = STATE_RESYNC;
- logger.errorAt(ERR_UNEXPECTED_CHAR, reader);
+ logger.error(ERR_UNEXPECTED_CHAR, reader);
}
reader.consumePeek();
break;
@@ -490,8 +492,8 @@ std::pair<bool, Variant::arrayType> Reader::parseArray(
return error(reader, logger, ERR_UNEXPECTED_END, res);
}
-std::pair<bool, std::string> Reader::parseUnescapedString(
- BufferedCharReader &reader, Logger &logger,
+std::pair<bool, std::string> VariantReader::parseUnescapedString(
+ CharReader &reader, Logger &logger,
const std::unordered_set<char> &delims)
{
std::stringstream res;
@@ -503,7 +505,7 @@ std::pair<bool, std::string> Reader::parseUnescapedString(
// Copy all characters, skip whitespace at the end
int state = STATE_IN_STRING;
- while (reader.peek(&c)) {
+ while (reader.peek(c)) {
if (delims.count(c)) {
reader.resetPeek();
return std::make_pair(true, res.str());
@@ -527,8 +529,8 @@ std::pair<bool, std::string> Reader::parseUnescapedString(
return std::make_pair(true, res.str());
}
-std::pair<bool, int64_t> Reader::parseInteger(
- BufferedCharReader &reader, Logger &logger,
+std::pair<bool, int64_t> VariantReader::parseInteger(
+ CharReader &reader, Logger &logger,
const std::unordered_set<char> &delims)
{
Number n;
@@ -544,8 +546,8 @@ std::pair<bool, int64_t> Reader::parseInteger(
return std::make_pair(false, n.intValue());
}
-std::pair<bool, double> Reader::parseDouble(
- BufferedCharReader &reader, Logger &logger,
+std::pair<bool, double> VariantReader::parseDouble(
+ CharReader &reader, Logger &logger,
const std::unordered_set<char> &delims)
{
Number n;
@@ -553,15 +555,15 @@ std::pair<bool, double> Reader::parseDouble(
return std::make_pair(res, n.doubleValue());
}
-std::pair<bool, Variant> Reader::parseGeneric(
- BufferedCharReader &reader, Logger &logger,
+std::pair<bool, Variant> VariantReader::parseGeneric(
+ CharReader &reader, Logger &logger,
const std::unordered_set<char> &delims)
{
char c;
// Skip all whitespace characters
reader.consumeWhitespace();
- while (reader.peek(&c)) {
+ while (reader.peek(c)) {
// Stop if a delimiter is reached
if (delims.count(c)) {
return error(reader, logger, ERR_UNEXPECTED_END, nullptr);
@@ -577,11 +579,19 @@ std::pair<bool, Variant> Reader::parseGeneric(
// TODO: Parse struct descriptor
}
- // Try to parse a number if a character in [0-9-] is reached
+ // Try to parse everything that looks like a number as number
if (Utils::isNumeric(c) || c == '-') {
- reader.resetPeek();
Number n;
- if (n.parse(reader, logger, delims)) {
+
+ // Fork the reader
+ CharReaderFork fork = reader.fork();
+
+ // TODO: Fork logger
+
+ // Try to parse the number
+ if (n.parse(fork, logger, delims)) {
+ // Parsing was successful, advance the reader
+ fork.commit();
if (n.isInt()) {
return std::make_pair(
true,
@@ -589,8 +599,6 @@ std::pair<bool, Variant> Reader::parseGeneric(
} else {
return std::make_pair(true, n.doubleValue());
}
- } else {
- return std::make_pair(false, n.doubleValue());
}
}
@@ -614,5 +622,4 @@ std::pair<bool, Variant> Reader::parseGeneric(
return error(reader, logger, ERR_UNEXPECTED_END, nullptr);
}
}
-}
diff --git a/src/core/variant/Reader.hpp b/src/core/common/VariantReader.hpp
index 710f7c4..5e7c5d2 100644
--- a/src/core/variant/Reader.hpp
+++ b/src/core/common/VariantReader.hpp
@@ -17,7 +17,7 @@
*/
/**
- * @file Reader.hpp
+ * @file VariantReader.hpp
*
* Provides parsers for various micro formats. These formats include integers,
* doubles, strings, JSON and the Ousía struct notation.
@@ -32,23 +32,21 @@
#include <unordered_set>
#include <utility>
-#include <core/BufferedCharReader.hpp>
-#include <core/Logger.hpp>
-
+#include "CharReader.hpp"
+#include "Logger.hpp"
#include "Variant.hpp"
namespace ousia {
-namespace variant {
-class Reader {
+class VariantReader {
private:
/**
* Parses a string which may either be enclosed by " or ', unescapes
* entities in the string as specified for JavaScript.
*
- * @param reader is a reference to the BufferedCharReader instance which is
- * the source for the character data. The reader will be positioned after
- * the terminating quote character or at the terminating delimiting
+ * @param VariantReader is a reference to the CharReader instance which is
+ * the source for the character data. The VariantReader will be positioned
+ * after the terminating quote character or at the terminating delimiting
* character.
* @param logger is the logger instance that should be used to log error
* messages and warnings.
@@ -58,7 +56,7 @@ private:
* is read.
*/
static std::pair<bool, std::string> parseString(
- BufferedCharReader &reader, Logger &logger,
+ CharReader &VariantReader, Logger &logger,
const std::unordered_set<char> *delims);
public:
@@ -66,9 +64,9 @@ public:
* Parses a string which may either be enclosed by " or ', unescapes
* entities in the string as specified for JavaScript.
*
- * @param reader is a reference to the BufferedCharReader instance which is
- * the source for the character data. The reader will be positioned after
- * the terminating quote character or at the terminating delimiting
+ * @param VariantReader is a reference to the CharReader instance which is
+ * the source for the character data. The VariantReader will be positioned
+ * after the terminating quote character or at the terminating delimiting
* character.
* @param logger is the logger instance that should be used to log error
* messages and warnings.
@@ -77,93 +75,92 @@ public:
* outside).
*/
static std::pair<bool, std::string> parseString(
- BufferedCharReader &reader, Logger &logger,
+ CharReader &VariantReader, Logger &logger,
const std::unordered_set<char> &delims)
{
- return parseString(reader, logger, &delims);
+ return parseString(VariantReader, logger, &delims);
}
/**
* Parses a string which may either be enclosed by " or ', unescapes
* entities in the string as specified for JavaScript.
*
- * @param reader is a reference to the BufferedCharReader instance which is
- * the source for the character data. The reader will be positioned after
- * the terminating quote character or at the terminating delimiting
+ * @param VariantReader is a reference to the CharReader instance which is
+ * the source for the character data. The VariantReader will be positioned
+ * after the terminating quote character or at the terminating delimiting
* character.
* @param logger is the logger instance that should be used to log error
* messages and warnings.
*/
- static std::pair<bool, std::string> parseString(BufferedCharReader &reader,
+ static std::pair<bool, std::string> parseString(CharReader &VariantReader,
Logger &logger)
{
- return parseString(reader, logger, nullptr);
+ return parseString(VariantReader, logger, nullptr);
}
/**
- * Extracts an unescaped string from the given buffered char reader
+ * Extracts an unescaped string from the given buffered char VariantReader
* instance. This function just reads text until one of the given delimiter
* characters is reached.
*
- * @param reader is a reference to the BufferedCharReader instance which is
- * the source for the character data. The reader will be positioned at the
- * terminating delimiting character.
+ * @param VariantReader is a reference to the CharReader instance which is
+ * the source for the character data. The VariantReader will be positioned
+ * at the terminating delimiting character.
* @param delims is a set of characters which will terminate the string.
* These characters are not included in the result. May not be nullptr.
*/
static std::pair<bool, std::string> parseUnescapedString(
- BufferedCharReader &reader, Logger &logger,
+ CharReader &VariantReader, Logger &logger,
const std::unordered_set<char> &delims);
/**
- * Parses an integer from the given buffered char reader instance until one
- * of the given delimiter characters is reached.
+ * Parses an integer from the given buffered char VariantReader instance
+ * until one of the given delimiter characters is reached.
*
- * @param reader is a reference to the BufferedCharReader instance from
- * which the character data should been reader. The reader will be
- * positioned at the terminating delimiting character or directly after the
- * integer.
+ * @param VariantReader is a reference to the CharReader instance from
+ * which the character data should been VariantReader. The VariantReader
+ * will be positioned at the terminating delimiting character or directly
+ * after the integer.
*/
static std::pair<bool, int64_t> parseInteger(
- BufferedCharReader &reader, Logger &logger,
+ CharReader &VariantReader, Logger &logger,
const std::unordered_set<char> &delims);
/**
- * Parses an double from the given buffered char reader instance until one
- * of the given delimiter characters is reached.
+ * Parses an double from the given buffered char VariantReader instance
+ * until one of the given delimiter characters is reached.
*
- * @param reader is a reference to the BufferedCharReader instance from
- * which the character data should been reader. The reader will be
- * positioned at the terminating delimiting character or directly after the
- * integer.
+ * @param VariantReader is a reference to the CharReader instance from
+ * which the character data should been VariantReader. The VariantReader
+ * will be positioned at the terminating delimiting character or directly
+ * after the integer.
*/
static std::pair<bool, double> parseDouble(
- BufferedCharReader &reader, Logger &logger,
+ CharReader &VariantReader, Logger &logger,
const std::unordered_set<char> &delims);
/**
* Parses an array of values.
*/
static std::pair<bool, Variant::arrayType> parseArray(
- BufferedCharReader &reader, Logger &logger, char delim = 0);
+ CharReader &VariantReader, Logger &logger, char delim = 0);
/**
* Tries to parse the most specific item from the given stream until one of
* the given delimiters is reached or a meaningful literal has been read.
* The resulting variant represents the value that has been read.
*
- * @param reader is a reference to the BufferedCharReader instance which is
- * the source for the character data. The reader will be positioned at the
- * terminating delimiting character.
+ * @param VariantReader is a reference to the CharReader instance which is
+ * the source for the character data. The VariantReader will be positioned
+ * at the terminating delimiting character.
* @param delims is a set of characters which will terminate the string.
* These characters are not included in the result. May not be nullptr.
*/
static std::pair<bool, Variant> parseGeneric(
- BufferedCharReader &reader, Logger &logger,
+ CharReader &VariantReader, Logger &logger,
const std::unordered_set<char> &delims);
};
}
-}
#endif /* _OUSIA_VARIANT_READER_HPP_ */
diff --git a/src/core/parser/Parser.hpp b/src/core/parser/Parser.hpp
index 5dac956..e155cfd 100644
--- a/src/core/parser/Parser.hpp
+++ b/src/core/parser/Parser.hpp
@@ -32,10 +32,10 @@
#include <set>
#include <string>
-#include <core/Exceptions.hpp>
#include <core/Node.hpp>
-#include <core/Logger.hpp>
#include <core/Registry.hpp>
+#include <core/common/Exceptions.hpp>
+#include <core/common/Logger.hpp>
#include "Scope.hpp"
diff --git a/src/core/parser/ParserStack.cpp b/src/core/parser/ParserStack.cpp
index dca7f35..5e801ee 100644
--- a/src/core/parser/ParserStack.cpp
+++ b/src/core/parser/ParserStack.cpp
@@ -20,8 +20,8 @@
#include "ParserStack.hpp"
-#include <core/Utils.hpp>
-#include <core/Exceptions.hpp>
+#include <core/common/Utils.hpp>
+#include <core/common/Exceptions.hpp>
namespace ousia {
namespace parser {
diff --git a/src/core/parser/ParserStack.hpp b/src/core/parser/ParserStack.hpp
index c5ed4e4..233f4f9 100644
--- a/src/core/parser/ParserStack.hpp
+++ b/src/core/parser/ParserStack.hpp
@@ -37,7 +37,7 @@
#include <stack>
#include <vector>
-#include <core/variant/Variant.hpp>
+#include <core/common/Variant.hpp>
#include "Parser.hpp"
diff --git a/src/plugins/css/CSSParser.cpp b/src/plugins/css/CSSParser.cpp
index 4bbcc18..5985047 100644
--- a/src/plugins/css/CSSParser.cpp
+++ b/src/plugins/css/CSSParser.cpp
@@ -18,7 +18,7 @@
#include "CSSParser.hpp"
-#include <core/variant/Reader.hpp>
+#include <core/common/VariantReader.hpp>
namespace ousia {
namespace parser {
@@ -77,7 +77,7 @@ static const std::map<int, CodeTokenDescriptor> CSS_DESCRIPTORS = {
Rooted<Node> CSSParser::parse(std::istream &is, ParserContext &ctx)
{
- BufferedCharReader input{is};
+ CharReader input{is};
CodeTokenizer tokenizer{input, CSS_ROOT, CSS_DESCRIPTORS};
tokenizer.ignoreComments = true;
tokenizer.ignoreLinebreaks = true;
@@ -227,13 +227,14 @@ Rooted<SelectorNode> CSSParser::parsePrimitiveSelector(CodeTokenizer &tokenizer,
// parse the argument list.
Variant::arrayType args;
// we require at least one argument, if parantheses are used
- args.push_back(variant::Reader::parseGeneric(tokenizer.getInput(),
+ // XXX
+ args.push_back(VariantReader::parseGeneric(tokenizer.getInput(),
ctx.logger,
{',', ')'}).second);
while (expect(COMMA, tokenizer, t, false, ctx)) {
// as long as we find commas we expect new arguments.
args.push_back(
- variant::Reader::parseGeneric(
+ VariantReader::parseGeneric(
tokenizer.getInput(), ctx.logger, {',', ')'}).second);
}
expect(PAREN_CLOSE, tokenizer, t, true, ctx);
@@ -333,7 +334,7 @@ bool CSSParser::parseRule(CodeTokenizer &tokenizer, ParserContext &ctx,
expect(COLON, tokenizer, t, true, ctx);
// then the value
// TODO: Resolve key for appropriate parsing function here.
- value = variant::Reader::parseGeneric(tokenizer.getInput(), ctx.logger,
+ value = VariantReader::parseGeneric(tokenizer.getInput(), ctx.logger,
{';'}).second;
// and a ;
expect(SEMICOLON, tokenizer, t, true, ctx);
diff --git a/src/plugins/css/CSSParser.hpp b/src/plugins/css/CSSParser.hpp
index 82f0cd1..eeb5b2c 100644
--- a/src/plugins/css/CSSParser.hpp
+++ b/src/plugins/css/CSSParser.hpp
@@ -22,9 +22,9 @@
#include <vector>
#include <utility>
-#include <core/BufferedCharReader.hpp>
#include <core/CodeTokenizer.hpp>
#include <core/CSS.hpp>
+#include <core/common/CharReader.hpp>
#include <core/parser/Parser.hpp>
namespace ousia {
diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp
index ce2857e..824219a 100644
--- a/src/plugins/xml/XmlParser.cpp
+++ b/src/plugins/xml/XmlParser.cpp
@@ -20,7 +20,7 @@
#include <expat.h>
-#include <core/Utils.hpp>
+#include <core/common/Utils.hpp>
#include <core/parser/ParserStack.hpp>
#include "XmlParser.hpp"
@@ -204,11 +204,15 @@ Rooted<Node> XmlParser::parse(std::istream &is, ParserContext &ctx)
// Parse the data and handle any XML error
if (!XML_ParseBuffer(&p, bytesRead, bytesRead == 0)) {
- const int line = XML_GetCurrentLineNumber(&p);
- const int column = XML_GetCurrentColumnNumber(&p);
+ const TextCursor::PosType line =
+ static_cast<TextCursor::PosType>(XML_GetCurrentLineNumber(&p));
+ const TextCursor::PosType column = static_cast<TextCursor::PosType>(
+ XML_GetCurrentColumnNumber(&p));
+ const size_t offs = XML_GetCurrentByteIndex(&p);
const XML_Error code = XML_GetErrorCode(&p);
const std::string msg = std::string{XML_ErrorString(code)};
- throw ParserException{"XML Syntax Error: " + msg, line, column};
+ throw ParserException{"XML Syntax Error: " + msg, line, column,
+ offs};
}
// Abort once there are no more bytes in the stream
diff --git a/test/core/BufferedCharReaderTest.cpp b/test/core/BufferedCharReaderTest.cpp
deleted file mode 100644
index b3498f7..0000000
--- a/test/core/BufferedCharReaderTest.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- Ousía
- Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <string>
-#include <iostream>
-
-#include "gtest/gtest.h"
-
-#include <core/BufferedCharReader.hpp>
-
-namespace ousia{
-
-TEST(BufferedCharReaderTest, SimpleReadTest)
-{
- std::string testStr{"this is a test"};
- char c;
-
- // Feed a test string into the reader
- BufferedCharReader reader{testStr};
-
- // Try to read the test string
- std::string res;
- while (!reader.atEnd()) {
- ASSERT_TRUE(reader.read(&c));
- res.append(&c, 1);
- }
-
- // The two strings must equal
- ASSERT_STREQ(testStr.c_str(), res.c_str()) ;
-
- // We must now be at line 1, column 15
- ASSERT_EQ(1, reader.getLine());
- ASSERT_EQ(testStr.size() + 1, reader.getColumn());
-
- // If we call either read or peek, false is returned
- ASSERT_FALSE(reader.read(&c));
- ASSERT_FALSE(reader.peek(&c));
-}
-
-TEST(BufferedCharReaderTest, SimplePeekTest)
-{
- std::string testStr{"this is a test"};
- char c;
-
- // Feed a test string into the reader
- BufferedCharReader reader{testStr};
-
- // Try to read the test string
- std::string res;
- while (reader.peek(&c)) {
- res.append(&c, 1);
- }
-
- // Peeking does not trigger the "atEnd" flag
- ASSERT_FALSE(reader.atEnd());
-
- // The two strings must equal
- ASSERT_STREQ(testStr.c_str(), res.c_str());
-
- // We must now be at line 1, column 1 and NOT at the end of the stream
- ASSERT_EQ(1, reader.getLine());
- ASSERT_EQ(1, reader.getColumn());
- ASSERT_FALSE(reader.atEnd());
-
- // If we consume the peek, we must be at line 1, column 15 and we should be
- // at the end of the stream
- reader.consumePeek();
- ASSERT_EQ(1, reader.getLine());
- ASSERT_EQ(testStr.size() + 1, reader.getColumn());
- ASSERT_TRUE(reader.atEnd());
-
- // If we call either read or peek, false is returned
- ASSERT_FALSE(reader.read(&c));
- ASSERT_FALSE(reader.peek(&c));
-}
-
-TEST(BufferedCharReaderTest, SplittedPeakTest)
-{
- std::string testStr{"this is a test"};
- char c;
-
- // Feed a test string into the reader
- BufferedCharReader reader;
-
- // Try to peek the test string, feed char after char into the reader
- std::string res;
- for (unsigned int i = 0; i < testStr.length(); i++) {
- reader.feed(std::string(&testStr[i], 1));
- while (reader.peek(&c)) {
- res.append(&c, 1);
- }
- }
- reader.close();
-
- // Consume the peeked data
- ASSERT_FALSE(reader.atEnd());
- reader.consumePeek();
- ASSERT_TRUE(reader.atEnd());
-
- // The two strings must equal
- ASSERT_STREQ(testStr.c_str(), res.c_str()) ;
-
- // We must now be at line 1, column 15
- ASSERT_EQ(1, reader.getLine());
- ASSERT_EQ(testStr.size() + 1, reader.getColumn());
-
- // If we call either read or peek, false is returned
- ASSERT_FALSE(reader.read(&c));
- ASSERT_FALSE(reader.peek(&c));
-}
-
-TEST(BufferedCharReaderTest, RowColumnCounterTest)
-{
- // Feed a test string into the reader
- BufferedCharReader reader{"1\n\r2\n3\r\n\n4"};
-
- // We should currently be in line 1, column 1
- ASSERT_EQ(1, reader.getLine());
- ASSERT_EQ(1, reader.getColumn());
-
- // Read two characters
- char c;
- for (int i = 0; i < 2; i++) reader.read(&c);
- ASSERT_EQ(2, reader.getLine());
- ASSERT_EQ(1, reader.getColumn());
-
- // Read two characters
- for (int i = 0; i < 2; i++) reader.read(&c);
- ASSERT_EQ(3, reader.getLine());
- ASSERT_EQ(1, reader.getColumn());
-
- // Read three characters
- for (int i = 0; i < 3; i++) reader.read(&c);
- ASSERT_EQ(5, reader.getLine());
- ASSERT_EQ(1, reader.getColumn());
-}
-
-TEST(BufferedCharReaderTest, LinebreakSubstitutionTest)
-{
- // Feed a test string into the reader
- BufferedCharReader reader{"this\n\ris\n\rjust\na test\r\n\rtest\n\r"};
-
- // Read all characters from the test string
- std::string res;
- char c;
- while (reader.read(&c)) {
- res.append(&c, 1);
- }
-
- // Test for equality
- ASSERT_STREQ("this\nis\njust\na test\n\ntest\n", res.c_str());
-}
-
-TEST(BufferedCharReaderTest, RowColumnCounterUTF8Test)
-{
- // Feed a test string with some umlauts into the reader
- BufferedCharReader reader{"\x61\xc3\x96\xc3\x84\xc3\x9c\xc3\x9f"};
-
- // Read all bytes
- char c;
- while (reader.read(&c));
-
- // The sequence above equals 5 UTF-8 characters (so after reading all the
- // cursor is at position 6)
- ASSERT_EQ(1, reader.getLine());
- ASSERT_EQ(6, reader.getColumn());
-}
-
-}
-
diff --git a/test/core/CodeTokenizerTest.cpp b/test/core/CodeTokenizerTest.cpp
index 1432564..4d11622 100644
--- a/test/core/CodeTokenizerTest.cpp
+++ b/test/core/CodeTokenizerTest.cpp
@@ -32,15 +32,15 @@ static const int CURLY_CLOSE = 41;
TEST(CodeTokenizer, testTokenizer)
{
- BufferedCharReader reader;
- reader.feed("/**\n"); // 1
- reader.feed(" * Some Block Comment\n"); // 2
- reader.feed(" */\n"); // 3
- reader.feed("var my_string = 'My \\'String\\'';\n"); // 4
- reader.feed("// and a line comment\n"); // 5
- reader.feed("var my_obj = { a = 4;}"); // 6
- // 123456789012345678901234567890123456789
- // 0 1 2 3
+ CharReader reader{
+ "/**\n" // 1
+ " * Some Block Comment\n" // 2
+ " */\n" // 3
+ "var my_string = 'My \\'String\\'';\n" // 4
+ "// and a line comment\n" // 5
+ "var my_obj = { a = 4;}"}; // 6
+ // 123456789012345678901234567890123456789
+ // 0 1 2 3
TokenTreeNode root{{{"/*", 1},
{"*/", 2},
{"//", 3},
@@ -68,10 +68,10 @@ TEST(CodeTokenizer, testTokenizer)
{STRING, "My 'String'", 17, 4, 32, 4},
{TOKEN_TEXT, ";", 32, 4, 33, 4},
{LINEBREAK, "\n", 33, 4, 1, 5},
- //this is slightly counter-intuitive but makes sense if you think about
- //it: As a line comment is ended by a line break the line break is
- //technically still a part of the line comment and thus the ending
- //is in the next line.
+ // this is slightly counter-intuitive but makes sense if you think about
+ // it: As a line comment is ended by a line break the line break is
+ // technically still a part of the line comment and thus the ending
+ // is in the next line.
{LINE_COMMENT, " and a line comment", 1, 5, 1, 6},
{TOKEN_TEXT, "var", 1, 6, 4, 6},
{TOKEN_TEXT, "my_obj", 5, 6, 11, 6},
diff --git a/test/core/LoggerTest.cpp b/test/core/LoggerTest.cpp
deleted file mode 100644
index abb76de..0000000
--- a/test/core/LoggerTest.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- Ousía
- Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <iostream>
-
-#include <gtest/gtest.h>
-
-#include <core/Logger.hpp>
-
-namespace ousia {
-
-struct Pos {
- int line, column;
- Pos(int line, int column) : line(line), column(column){};
- int getLine() const { return line; }
- int getColumn() const { return column; }
-};
-
-TEST(TerminalLogger, log)
-{
- // Test for manual visual expection only -- no assertions
- TerminalLogger logger{std::cerr, true};
- logger.pushFilename("test.odp");
-
- logger.debug("This is a test debug message", 10, 20);
- logger.debug("This is a test debug message with no column", 10);
- logger.debug("This is a test debug message with no line");
- logger.debug("This is a test debug message with no file", "");
- logger.debug("This is a test debug message with no file but a line", "",
- 10);
- logger.debug(
- "This is a test debug message with no file but a line and a column", "",
- 10, 20);
- logger.note("This is a test note", 10, 20);
- logger.warning("This is a test warning", 10, 20);
- logger.error("This is a test error", 10, 20);
- logger.fatalError("This is a test fatal error!", 10, 20);
-
- try {
- throw LoggableException{"An exception"};
- }
- catch (const LoggableException &ex) {
- logger.log(ex);
- }
-
- try {
- throw LoggableException{"An exception at position", Pos(10, 20)};
- }
- catch (const LoggableException &ex) {
- logger.log(ex);
- }
-
- logger.logAt(Severity::ERROR, "This is a positioned log message",
- Pos(10, 20));
- logger.debugAt("This is a positioned debug message", Pos(10, 20));
- logger.noteAt("This is a positioned log error", Pos(10, 20));
-}
-}
-
diff --git a/test/core/RegistryTest.cpp b/test/core/RegistryTest.cpp
index 4450227..8280188 100644
--- a/test/core/RegistryTest.cpp
+++ b/test/core/RegistryTest.cpp
@@ -22,7 +22,7 @@
#include <sstream>
-#include <core/Logger.hpp>
+#include <core/common/Logger.hpp>
namespace ousia {
diff --git a/test/core/TokenizerTest.cpp b/test/core/TokenizerTest.cpp
index da6b578..2b80662 100644
--- a/test/core/TokenizerTest.cpp
+++ b/test/core/TokenizerTest.cpp
@@ -18,7 +18,7 @@
#include <gtest/gtest.h>
-#include <core/BufferedCharReader.hpp>
+#include <core/common/CharReader.hpp>
#include <core/Tokenizer.hpp>
@@ -65,10 +65,9 @@ TEST(Tokenizer, testTokenization)
{
TokenTreeNode root{{{"/", 1}, {"/*", 2}, {"*/", 3}}};
- BufferedCharReader reader;
- reader.feed("Test/Test /* Block Comment */");
- // 12345678901234567890123456789
- // 0 1 2
+ CharReader reader{"Test/Test /* Block Comment */"};
+ // 12345678901234567890123456789
+ // 0 1 2
std::vector<Token> expected = {
{TOKEN_TEXT, "Test", 1, 1, 5, 1},
@@ -97,10 +96,7 @@ TEST(Tokenizer, testIncompleteTokens)
{
TokenTreeNode root{{{"ab", 1}, {"c", 2}}};
- BufferedCharReader reader;
- reader.feed("ac");
- // 1234567890
- // 0 1
+ CharReader reader{"ac"};
std::vector<Token> expected = {
{TOKEN_TEXT, "a", 1, 1, 2, 1},
diff --git a/test/core/utils/CharReaderTest.cpp b/test/core/common/CharReaderTest.cpp
index d5c7aad..9c1026c 100644
--- a/test/core/utils/CharReaderTest.cpp
+++ b/test/core/common/CharReaderTest.cpp
@@ -22,10 +22,9 @@
#include "gtest/gtest.h"
-#include <core/utils/CharReader.hpp>
+#include <core/common/CharReader.hpp>
namespace ousia {
-namespace utils {
/* Test data */
@@ -95,6 +94,8 @@ TEST(Buffer, simpleRead)
// The two strings must equal
ASSERT_EQ(testStr, res);
+
+ buf.deleteCursor(cursor);
}
TEST(Buffer, cursorManagement)
@@ -112,6 +113,10 @@ TEST(Buffer, cursorManagement)
buf.deleteCursor(c2);
Buffer::CursorId c4 = buf.createCursor();
ASSERT_EQ(1U, c4);
+
+ buf.deleteCursor(c1);
+ buf.deleteCursor(c3);
+ buf.deleteCursor(c4);
}
TEST(Buffer, twoCursors)
@@ -152,6 +157,9 @@ TEST(Buffer, twoCursors)
// The two strings must equal
ASSERT_EQ(testStr, res1);
ASSERT_EQ(testStr, res2);
+
+ buf.deleteCursor(cur1);
+ buf.deleteCursor(cur2);
}
TEST(Buffer, copyCursors)
@@ -203,6 +211,10 @@ TEST(Buffer, copyCursors)
ASSERT_EQ("test3", res3);
ASSERT_TRUE(buf.atEnd(cur3));
+
+ buf.deleteCursor(cur1);
+ buf.deleteCursor(cur2);
+ buf.deleteCursor(cur3);
}
TEST(Buffer, moveCursor)
@@ -260,6 +272,8 @@ TEST(Buffer, moveCursor)
}
ASSERT_EQ("test3", res);
}
+
+ buf.deleteCursor(cursor);
}
struct VectorReadState {
@@ -302,6 +316,8 @@ TEST(Buffer, simpleStream)
// The read data and the original data must be equal
ASSERT_EQ(DATA, res);
+
+ buf.deleteCursor(cursor);
}
TEST(Buffer, streamTwoCursors)
@@ -337,6 +353,9 @@ TEST(Buffer, streamTwoCursors)
// The read data and the original data must be equal
ASSERT_EQ(DATA, res1);
ASSERT_EQ(DATA, res2);
+
+ buf.deleteCursor(cur1);
+ buf.deleteCursor(cur2);
}
TEST(Buffer, streamTwoCursorsMovingInterleaved)
@@ -386,6 +405,9 @@ TEST(Buffer, streamTwoCursorsMovingInterleaved)
// The read data and the original data must be equal
ASSERT_EQ(DATA, res1);
ASSERT_EQ(DATA, res2);
+
+ buf.deleteCursor(cur1);
+ buf.deleteCursor(cur2);
}
TEST(Buffer, streamMoveForward)
@@ -407,6 +429,8 @@ TEST(Buffer, streamMoveForward)
res.push_back(c);
}
ASSERT_EQ(partialData, res);
+
+ buf.deleteCursor(cursor);
}
/* CharReader Test */
@@ -636,8 +660,8 @@ TEST(CharReaderTest, context)
// Retrieval at beginning of stream
{
CharReader reader{testStr};
- CharReader::Context ctx = reader.getContext(80);
- ASSERT_EQ("first line", ctx.line);
+ TextCursor::Context ctx = reader.getContext(80);
+ ASSERT_EQ("first line", ctx.text);
ASSERT_EQ(0U, ctx.relPos);
ASSERT_FALSE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
@@ -646,13 +670,13 @@ TEST(CharReaderTest, context)
// Retrieval in middle of line
{
CharReader reader{testStr};
- CharReader::Context ctx = reader.getContext(80);
+ TextCursor::Context ctx = reader.getContext(80);
char c;
for (int i = 0; i < 5; i++)
reader.read(c);
- ASSERT_EQ("first line", ctx.line);
+ ASSERT_EQ("first line", ctx.text);
ASSERT_EQ(0U, ctx.relPos);
ASSERT_FALSE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
@@ -666,8 +690,8 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 11; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(80);
- ASSERT_EQ("first line", ctx.line);
+ TextCursor::Context ctx = reader.getContext(80);
+ ASSERT_EQ("first line", ctx.text);
ASSERT_EQ(10U, ctx.relPos);
ASSERT_FALSE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
@@ -681,8 +705,8 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 5; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(3);
- ASSERT_EQ("t l", ctx.line);
+ TextCursor::Context ctx = reader.getContext(3);
+ ASSERT_EQ("t l", ctx.text);
ASSERT_EQ(1U, ctx.relPos);
ASSERT_TRUE(ctx.truncatedStart);
ASSERT_TRUE(ctx.truncatedEnd);
@@ -696,8 +720,8 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 12; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(80);
- ASSERT_EQ("second line", ctx.line);
+ TextCursor::Context ctx = reader.getContext(80);
+ ASSERT_EQ("second line", ctx.text);
ASSERT_EQ(0U, ctx.relPos);
ASSERT_FALSE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
@@ -711,8 +735,8 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 23; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(80);
- ASSERT_EQ("second line", ctx.line);
+ TextCursor::Context ctx = reader.getContext(80);
+ ASSERT_EQ("second line", ctx.text);
ASSERT_EQ(11U, ctx.relPos);
ASSERT_FALSE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
@@ -726,8 +750,8 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 24; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(80);
- ASSERT_EQ("last line", ctx.line);
+ TextCursor::Context ctx = reader.getContext(80);
+ ASSERT_EQ("last line", ctx.text);
ASSERT_EQ(0U, ctx.relPos);
ASSERT_FALSE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
@@ -741,8 +765,8 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 28; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(80);
- ASSERT_EQ("last line", ctx.line);
+ TextCursor::Context ctx = reader.getContext(80);
+ ASSERT_EQ("last line", ctx.text);
ASSERT_EQ(4U, ctx.relPos);
ASSERT_FALSE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
@@ -756,8 +780,8 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 28; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(3);
- ASSERT_EQ("t l", ctx.line);
+ TextCursor::Context ctx = reader.getContext(3);
+ ASSERT_EQ("t l", ctx.text);
ASSERT_EQ(1U, ctx.relPos);
ASSERT_TRUE(ctx.truncatedStart);
ASSERT_TRUE(ctx.truncatedEnd);
@@ -771,8 +795,8 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 100; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(80);
- ASSERT_EQ("last line", ctx.line);
+ TextCursor::Context ctx = reader.getContext(80);
+ ASSERT_EQ("last line", ctx.text);
ASSERT_EQ(9U, ctx.relPos);
ASSERT_FALSE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
@@ -786,13 +810,12 @@ TEST(CharReaderTest, context)
for (int i = 0; i < 100; i++)
reader.read(c);
- CharReader::Context ctx = reader.getContext(4);
- ASSERT_EQ("line", ctx.line);
+ TextCursor::Context ctx = reader.getContext(4);
+ ASSERT_EQ("line", ctx.text);
ASSERT_EQ(4U, ctx.relPos);
ASSERT_TRUE(ctx.truncatedStart);
ASSERT_FALSE(ctx.truncatedEnd);
}
}
}
-}
diff --git a/test/core/common/LoggerTest.cpp b/test/core/common/LoggerTest.cpp
new file mode 100644
index 0000000..cc9f701
--- /dev/null
+++ b/test/core/common/LoggerTest.cpp
@@ -0,0 +1,102 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <core/common/Logger.hpp>
+
+namespace ousia {
+
+struct Pos {
+ TextCursor::Position pos;
+ TextCursor::Context ctx;
+
+ Pos(TextCursor::Position pos = TextCursor::Position{},
+ TextCursor::Context ctx = TextCursor::Context{})
+ : pos(pos), ctx(ctx){};
+
+ TextCursor::Position getPosition() { return pos; }
+ TextCursor::Context getContext() { return ctx; }
+};
+
+TEST(TerminalLogger, log)
+{
+ // Test for manual visual expection only -- no assertions
+ TerminalLogger logger{std::cerr, true};
+ logger.pushFile("test.odp");
+
+ logger.debug("This is a test debug message", TextCursor::Position{10, 20});
+ logger.debug("This is a test debug message with no column",
+ TextCursor::Position{10});
+ logger.debug("This is a test debug message with no line");
+ logger.note("This is a test note", TextCursor::Position{10, 20});
+ logger.warning("This is a test warning", TextCursor::Position{10, 20});
+ logger.error("This is a test error", TextCursor::Position{10, 20});
+ logger.fatalError("This is a test fatal error!",
+ TextCursor::Position{10, 20});
+
+ logger.error("This is a test error with context",
+ TextCursor::Position{10, 20},
+ TextCursor::Context{"int bla = blub;", 10, true, false});
+
+ Pos pos(TextCursor::Position{10, 20});
+
+ try {
+ throw LoggableException{"An exception"};
+ }
+ catch (const LoggableException &ex) {
+ logger.log(ex);
+ }
+
+ try {
+ throw LoggableException{"An exception at position", pos};
+ }
+ catch (const LoggableException &ex) {
+ logger.log(ex);
+ }
+
+ logger.logAt(Severity::ERROR, "This is a positioned log message", pos);
+}
+
+TEST(TerminalLogger, fork)
+{
+ // Test for manual visual expection only -- no assertions
+ TerminalLogger logger{std::cerr, true};
+
+ LoggerFork fork = logger.fork();
+
+ fork.pushFile("test.odp");
+ fork.error("This is a test error with context",
+ TextCursor::Position{10, 20},
+ TextCursor::Context{"int bla = blub;", 10, true, false});
+ fork.pushFile("test2.odp");
+ fork.error("This is a test error without context");
+ fork.popFile();
+ fork.error("Another error");
+ fork.popFile();
+ fork.error("Another error");
+
+ // Print all error messages
+ fork.commit();
+}
+
+
+}
+
diff --git a/test/core/UtilsTest.cpp b/test/core/common/UtilsTest.cpp
index 0a7d2a3..2858038 100644
--- a/test/core/UtilsTest.cpp
+++ b/test/core/common/UtilsTest.cpp
@@ -18,7 +18,7 @@
#include <gtest/gtest.h>
-#include <core/Utils.hpp>
+#include <core/common/Utils.hpp>
namespace ousia {
diff --git a/test/core/variant/ReaderTest.cpp b/test/core/common/VariantReaderTest.cpp
index 595bb57..d9bb74e 100644
--- a/test/core/variant/ReaderTest.cpp
+++ b/test/core/common/VariantReaderTest.cpp
@@ -19,7 +19,7 @@
#include <iostream>
#include <gtest/gtest.h>
-#include <core/variant/Reader.hpp>
+#include <core/common/VariantReader.hpp>
namespace ousia {
namespace variant {
@@ -31,32 +31,32 @@ TEST(Reader, readString)
{
// Simple, double quoted string
{
- BufferedCharReader reader("\"hello world\"");
- auto res = Reader::parseString(reader, logger);
+ CharReader reader("\"hello world\"");
+ auto res = VariantReader::parseString(reader, logger);
ASSERT_TRUE(res.first);
ASSERT_EQ("hello world", res.second);
}
// Simple, double quoted string with whitespace
{
- BufferedCharReader reader(" \"hello world\" ");
- auto res = Reader::parseString(reader, logger);
+ CharReader reader(" \"hello world\" ");
+ auto res = VariantReader::parseString(reader, logger);
ASSERT_TRUE(res.first);
ASSERT_EQ("hello world", res.second);
}
// Simple, single quoted string
{
- BufferedCharReader reader("'hello world'");
- auto res = Reader::parseString(reader, logger);
+ CharReader reader("'hello world'");
+ auto res = VariantReader::parseString(reader, logger);
ASSERT_TRUE(res.first);
ASSERT_EQ("hello world", res.second);
}
// Escape characters
{
- BufferedCharReader reader("'\\'\\\"\\b\\f\\n\\r\\t\\v'");
- auto res = Reader::parseString(reader, logger);
+ CharReader reader("'\\'\\\"\\b\\f\\n\\r\\t\\v'");
+ auto res = VariantReader::parseString(reader, logger);
ASSERT_TRUE(res.first);
ASSERT_EQ("'\"\b\f\n\r\t\v", res.second);
}
@@ -66,32 +66,32 @@ TEST(Reader, parseUnescapedString)
{
// Simple case
{
- BufferedCharReader reader("hello world;");
- auto res = Reader::parseUnescapedString(reader, logger, {';'});
+ CharReader reader("hello world;");
+ auto res = VariantReader::parseUnescapedString(reader, logger, {';'});
ASSERT_TRUE(res.first);
ASSERT_EQ("hello world", res.second);
}
// Simple case with whitespace
{
- BufferedCharReader reader(" hello world ; ");
- auto res = Reader::parseUnescapedString(reader, logger, {';'});
+ CharReader reader(" hello world ; ");
+ auto res = VariantReader::parseUnescapedString(reader, logger, {';'});
ASSERT_TRUE(res.first);
ASSERT_EQ("hello world", res.second);
}
// Linebreaks
{
- BufferedCharReader reader(" hello\nworld ; ");
- auto res = Reader::parseUnescapedString(reader, logger, {';'});
+ CharReader reader(" hello\nworld ; ");
+ auto res = VariantReader::parseUnescapedString(reader, logger, {';'});
ASSERT_TRUE(res.first);
ASSERT_EQ("hello\nworld", res.second);
}
// End of stream
{
- BufferedCharReader reader(" hello world ");
- auto res = Reader::parseUnescapedString(reader, logger, {';'});
+ CharReader reader(" hello world ");
+ auto res = VariantReader::parseUnescapedString(reader, logger, {';'});
ASSERT_TRUE(res.first);
ASSERT_EQ("hello world", res.second);
}
@@ -103,76 +103,76 @@ TEST(Reader, parseInteger)
{
// Valid integers
{
- BufferedCharReader reader("0 ");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("0 ");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(0, res.second);
}
{
- BufferedCharReader reader("42 ");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("42 ");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(42, res.second);
}
{
- BufferedCharReader reader("-42");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("-42");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(-42, res.second);
}
{
- BufferedCharReader reader(" -0x4A2 ");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader(" -0x4A2 ");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(-0x4A2, res.second);
}
{
- BufferedCharReader reader(" 0Xaffe");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader(" 0Xaffe");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(0xAFFE, res.second);
}
{
- BufferedCharReader reader("0x7FFFFFFFFFFFFFFF");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("0x7FFFFFFFFFFFFFFF");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(0x7FFFFFFFFFFFFFFFL, res.second);
}
{
- BufferedCharReader reader("-0x7FFFFFFFFFFFFFFF");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("-0x7FFFFFFFFFFFFFFF");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(-0x7FFFFFFFFFFFFFFFL, res.second);
}
// Invalid integers
{
- BufferedCharReader reader("-");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("-");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_FALSE(res.first);
}
{
- BufferedCharReader reader("0a");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("0a");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_FALSE(res.first);
}
{
- BufferedCharReader reader("-0xag");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("-0xag");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_FALSE(res.first);
}
{
- BufferedCharReader reader("0x8000000000000000");
- auto res = Reader::parseInteger(reader, logger, noDelim);
+ CharReader reader("0x8000000000000000");
+ auto res = VariantReader::parseInteger(reader, logger, noDelim);
ASSERT_FALSE(res.first);
}
}
@@ -181,64 +181,64 @@ TEST(Reader, parseDouble)
{
// Valid doubles
{
- BufferedCharReader reader("1.25");
- auto res = Reader::parseDouble(reader, logger, noDelim);
+ CharReader reader("1.25");
+ auto res = VariantReader::parseDouble(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(1.25, res.second);
}
{
- BufferedCharReader reader(".25");
- auto res = Reader::parseDouble(reader, logger, noDelim);
+ CharReader reader(".25");
+ auto res = VariantReader::parseDouble(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(.25, res.second);
}
{
- BufferedCharReader reader(".25e1");
- auto res = Reader::parseDouble(reader, logger, noDelim);
+ CharReader reader(".25e1");
+ auto res = VariantReader::parseDouble(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(2.5, res.second);
}
{
- BufferedCharReader reader("-2.5e-1");
- auto res = Reader::parseDouble(reader, logger, noDelim);
+ CharReader reader("-2.5e-1");
+ auto res = VariantReader::parseDouble(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(-0.25, res.second);
}
{
- BufferedCharReader reader("-50e-2");
- auto res = Reader::parseDouble(reader, logger, noDelim);
+ CharReader reader("-50e-2");
+ auto res = VariantReader::parseDouble(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(-0.5, res.second);
}
{
- BufferedCharReader reader("-1.");
- auto res = Reader::parseDouble(reader, logger, noDelim);
+ CharReader reader("-1.");
+ auto res = VariantReader::parseDouble(reader, logger, noDelim);
ASSERT_TRUE(res.first);
ASSERT_EQ(-1., res.second);
}
{
- BufferedCharReader reader("-50.e-2");
- auto res = Reader::parseDouble(reader, logger, {'.'});
+ CharReader reader("-50.e-2");
+ auto res = VariantReader::parseDouble(reader, logger, {'.'});
ASSERT_TRUE(res.first);
ASSERT_EQ(-50, res.second);
}
// Invalid doubles
{
- BufferedCharReader reader(".e1");
- auto res = Reader::parseDouble(reader, logger, noDelim);
+ CharReader reader(".e1");
+ auto res = VariantReader::parseDouble(reader, logger, noDelim);
ASSERT_FALSE(res.first);
}
{
- BufferedCharReader reader("0e100000");
- auto res = Reader::parseDouble(reader, logger, noDelim);
+ CharReader reader("0e100000");
+ auto res = VariantReader::parseDouble(reader, logger, noDelim);
ASSERT_FALSE(res.first);
}
}
@@ -247,13 +247,13 @@ TEST(Reader, parseArray)
{
// Simple case (only primitive data types)
{
- BufferedCharReader reader("[\"Hello, World\", unescaped\n string ,\n"
+ CharReader reader("[\"Hello, World\", unescaped\n string ,\n"
"1234, 0.56, true, false, null]");
- auto res = Reader::parseArray(reader, logger);
+ auto res = VariantReader::parseArray(reader, logger);
ASSERT_TRUE(res.first);
// Make sure array has the correct size
- ASSERT_EQ(7, res.second.size());
+ ASSERT_EQ(7U, res.second.size());
// Check the types
ASSERT_TRUE(res.second[0].isString());
@@ -275,12 +275,12 @@ TEST(Reader, parseArray)
// Ending with comma
{
- BufferedCharReader reader("[ 'test' ,]");
- auto res = Reader::parseArray(reader, logger);
+ CharReader reader("[ 'test' ,]");
+ auto res = VariantReader::parseArray(reader, logger);
ASSERT_TRUE(res.first);
// Make sure the array has the correct size
- ASSERT_EQ(1, res.second.size());
+ ASSERT_EQ(1U, res.second.size());
// Check the types
ASSERT_TRUE(res.second[0].isString());
@@ -290,22 +290,23 @@ TEST(Reader, parseArray)
}
// Recovery from invalid values
- // TODO: Actually parseGeneric should fall back to returning a simple string
- // if parsing of a special (non-string) type failed
{
- BufferedCharReader reader("[ 0invalidNumber, str, 1invalid]");
- auto res = Reader::parseArray(reader, logger);
- ASSERT_FALSE(res.first);
+ CharReader reader("[ 0invalidNumber, str, 1invalid]");
+ auto res = VariantReader::parseArray(reader, logger);
+ ASSERT_TRUE(res.first);
// Make sure the array has the correct size
- ASSERT_EQ(3, res.second.size());
+ ASSERT_EQ(3U, res.second.size());
- // Check the types (only for the valid entries, the other types are
- // undefined)
+ // Check the types (all must be strings since the numbers are invalid)
+ ASSERT_TRUE(res.second[0].isString());
ASSERT_TRUE(res.second[1].isString());
+ ASSERT_TRUE(res.second[2].isString());
// Check the values
+ ASSERT_EQ("0invalidNumber", res.second[0].asString());
ASSERT_EQ("str", res.second[1].asString());
+ ASSERT_EQ("1invalid", res.second[2].asString());
}
}
@@ -313,8 +314,8 @@ TEST(Reader, parseGeneric)
{
// Simple case, unescaped string
{
- BufferedCharReader reader("hello world");
- auto res = Reader::parseGeneric(reader, logger, {';'});
+ CharReader reader("hello world");
+ auto res = VariantReader::parseGeneric(reader, logger, {';'});
ASSERT_TRUE(res.first);
ASSERT_TRUE(res.second.isString());
ASSERT_EQ("hello world", res.second.asString());
@@ -322,8 +323,8 @@ TEST(Reader, parseGeneric)
// Simple case, double quoted string
{
- BufferedCharReader reader(" \"hello world\" ");
- auto res = Reader::parseGeneric(reader, logger, {';'});
+ CharReader reader(" \"hello world\" ");
+ auto res = VariantReader::parseGeneric(reader, logger, {';'});
ASSERT_TRUE(res.first);
ASSERT_TRUE(res.second.isString());
ASSERT_EQ("hello world", res.second.asString());
@@ -331,8 +332,8 @@ TEST(Reader, parseGeneric)
// Simple case, single quoted string
{
- BufferedCharReader reader(" 'hello world' ");
- auto res = Reader::parseGeneric(reader, logger, {';'});
+ CharReader reader(" 'hello world' ");
+ auto res = VariantReader::parseGeneric(reader, logger, {';'});
ASSERT_TRUE(res.first);
ASSERT_TRUE(res.second.isString());
ASSERT_EQ("hello world", res.second.asString());
diff --git a/test/core/variant/VariantTest.cpp b/test/core/common/VariantTest.cpp
index e51cf36..580846e 100644
--- a/test/core/variant/VariantTest.cpp
+++ b/test/core/common/VariantTest.cpp
@@ -20,7 +20,7 @@
#include <gtest/gtest.h>
-#include <core/variant/Variant.hpp>
+#include <core/common/Variant.hpp>
namespace ousia {
diff --git a/test/plugins/css/CSSParserTest.cpp b/test/plugins/css/CSSParserTest.cpp
index 6499375..3ea3a19 100644
--- a/test/plugins/css/CSSParserTest.cpp
+++ b/test/plugins/css/CSSParserTest.cpp
@@ -186,11 +186,11 @@ TEST(CSSParser, testParseCSS)
{
Rooted<RuleSet> ruleSet = A->getRuleSet();
ASSERT_EQ(2, ruleSet->getRules().size());
- variant::Variant v = ruleSet->getRules()["ident1"];
- ASSERT_EQ(variant::Variant::Type::STRING, v.getType());
+ Variant v = ruleSet->getRules()["ident1"];
+ ASSERT_EQ(Variant::Type::STRING, v.getType());
ASSERT_EQ("val4", v.asString());
v = ruleSet->getRules()["ident2"];
- ASSERT_EQ(variant::Variant::Type::STRING, v.getType());
+ ASSERT_EQ(Variant::Type::STRING, v.getType());
ASSERT_EQ("val2", v.asString());
}
/*
@@ -211,8 +211,8 @@ TEST(CSSParser, testParseCSS)
{
Rooted<RuleSet> ruleSet = Aselect->getRuleSet();
ASSERT_EQ(1, ruleSet->getRules().size());
- variant::Variant v = ruleSet->getRules()["ident3"];
- ASSERT_EQ(variant::Variant::Type::STRING, v.getType());
+ Variant v = ruleSet->getRules()["ident3"];
+ ASSERT_EQ(Variant::Type::STRING, v.getType());
ASSERT_EQ("val3", v.asString());
}
/*
@@ -250,11 +250,11 @@ TEST(CSSParser, testParseCSS)
{
Rooted<RuleSet> ruleSet = BA->getRuleSet();
ASSERT_EQ(2, ruleSet->getRules().size());
- variant::Variant v = ruleSet->getRules()["ident1"];
- ASSERT_EQ(variant::Variant::Type::STRING, v.getType());
+ Variant v = ruleSet->getRules()["ident1"];
+ ASSERT_EQ(Variant::Type::STRING, v.getType());
ASSERT_EQ("val1", v.asString());
v = ruleSet->getRules()["ident2"];
- ASSERT_EQ(variant::Variant::Type::STRING, v.getType());
+ ASSERT_EQ(Variant::Type::STRING, v.getType());
ASSERT_EQ("val2", v.asString());
}
}
diff --git a/test/plugins/xml/XmlParserTest.cpp b/test/plugins/xml/XmlParserTest.cpp
index 7dc8c24..39b1a9d 100644
--- a/test/plugins/xml/XmlParserTest.cpp
+++ b/test/plugins/xml/XmlParserTest.cpp
@@ -36,7 +36,7 @@ TEST(XmlParser, mismatchedTagException)
p.parse("<document>\n</document2>", ctx);
}
catch (ParserException ex) {
- ASSERT_EQ(2, ex.line);
+ ASSERT_EQ(2U, ex.pos.line);
hadException = true;
}
ASSERT_TRUE(hadException);