diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/common/Logger.cpp | 143 | ||||
-rw-r--r-- | src/core/common/Logger.hpp | 61 | ||||
-rw-r--r-- | src/core/common/SourceContextReader.cpp | 18 | ||||
-rw-r--r-- | src/core/common/SourceContextReader.hpp | 20 | ||||
-rw-r--r-- | src/core/frontend/Terminal.cpp (renamed from src/core/common/Terminal.cpp) | 20 | ||||
-rw-r--r-- | src/core/frontend/Terminal.hpp (renamed from src/core/common/Terminal.hpp) | 14 | ||||
-rw-r--r-- | src/core/frontend/TerminalLogger.cpp | 177 | ||||
-rw-r--r-- | src/core/frontend/TerminalLogger.hpp | 79 | ||||
-rw-r--r-- | src/core/resource/ResourceManager.cpp | 9 | ||||
-rw-r--r-- | src/core/resource/ResourceManager.hpp | 20 |
10 files changed, 361 insertions, 200 deletions
diff --git a/src/core/common/Logger.cpp b/src/core/common/Logger.cpp index aa61e6a..54156f2 100644 --- a/src/core/common/Logger.cpp +++ b/src/core/common/Logger.cpp @@ -20,8 +20,6 @@ #include <sstream> #include "Logger.hpp" -#include "Terminal.hpp" -#include "Utils.hpp" namespace ousia { @@ -118,49 +116,49 @@ void LoggerFork::commit() purge(); } -/* Class ScopedLogger */ +/* Class GuardedLogger */ -ScopedLogger::ScopedLogger(Logger &parent, SourceLocation loc) +GuardedLogger::GuardedLogger(Logger &parent, SourceLocation loc) : parent(parent), depth(0) { pushDefaultLocation(loc); } -ScopedLogger::~ScopedLogger() +GuardedLogger::~GuardedLogger() { while (depth > 0) { popDefaultLocation(); } } -void ScopedLogger::processMessage(const Message &msg) +void GuardedLogger::processMessage(const Message &msg) { parent.processMessage(msg); } -bool ScopedLogger::filterMessage(const Message &msg) +bool GuardedLogger::filterMessage(const Message &msg) { return parent.filterMessage(msg); } -void ScopedLogger::processPushDefaultLocation(const SourceLocation &loc) +void GuardedLogger::processPushDefaultLocation(const SourceLocation &loc) { parent.processPushDefaultLocation(loc); depth++; } -void ScopedLogger::processPopDefaultLocation() +void GuardedLogger::processPopDefaultLocation() { depth--; parent.processPopDefaultLocation(); } -void ScopedLogger::processSetDefaultLocation(const SourceLocation &loc) +void GuardedLogger::processSetDefaultLocation(const SourceLocation &loc) { parent.processSetDefaultLocation(loc); } -void ScopedLogger::processSetSourceContextCallback( +void GuardedLogger::processSetSourceContextCallback( SourceContextCallback sourceContextCallback) { parent.processSetSourceContextCallback(sourceContextCallback); @@ -265,128 +263,5 @@ bool ConcreteLogger::hasFatalError() return getSeverityCount(Severity::FATAL_ERROR) > 0; } -/* Class TerminalLogger */ - -void TerminalLogger::processMessage(const Message &msg) -{ - Terminal t(useColor); - - // Fetch filename, position and context - const SourceContext ctx = messageContext(msg); - - // Print the file name - if (ctx.hasFile()) { - os << t.bright() << ctx.filename << t.reset(); - } - - // Print line and column number - if (ctx.hasLine()) { - if (ctx.hasFile()) { - os << ':'; - } - os << t.bright() << ctx.startLine << t.reset(); - if (ctx.hasColumn()) { - os << ':' << ctx.startColumn; - } - } - - // Print the optional seperator - if (ctx.hasFile() || ctx.hasLine()) { - os << ": "; - } - - // Print the severity - switch (msg.severity) { - case Severity::DEBUG: - break; - case Severity::NOTE: - os << t.color(Terminal::CYAN, true) << "note: "; - break; - case Severity::WARNING: - os << t.color(Terminal::MAGENTA, true) << "warning: "; - break; - case Severity::ERROR: - os << t.color(Terminal::RED, true) << "error: "; - break; - case Severity::FATAL_ERROR: - os << t.color(Terminal::RED, true) << "fatal error: "; - break; - } - os << t.reset(); - - // Print the actual message - os << msg.msg << std::endl; - - // Print the error message context if available - if (ctx.hasText()) { - // Iterate over each line in the text - std::vector<std::string> lines = Utils::split(ctx.text, '\n'); - - const size_t relLen = ctx.relLen ? ctx.relLen : 1; - const size_t relPos = ctx.relPos; - const size_t pstart = relPos; - const size_t pend = relPos + relLen; - - size_t lstart = 0; - size_t lend = 0; - for (size_t n = 0; n < lines.size(); n++) { - bool firstLine = n == 0; - bool lastLine = n == lines.size() - 1; - - // Indicate truncation and indent non-first lines - if (ctx.truncatedStart && firstLine) { - os << "[...] "; - } - if (!firstLine) { - os << "\t"; - } - - // Print the actual line - os << lines[n]; - - // Indicate truncation - if (ctx.truncatedEnd && lastLine) { - os << " [...]"; - } - os << std::endl; - - // Repeat truncation or indendation space in the next line - if (ctx.truncatedStart && firstLine) { - os << " "; - } - if (!firstLine) { - os << "\t"; - } - - // Print the position indicators - lend = lastLine ? pend : lstart + lines[n].size(); - for (size_t i = lstart; i < lend; i++) { - if (i >= pstart && i < pend) { - os << t.color(Terminal::GREEN); - for (; i < std::min(lend, pend); i++) { - if (relLen == 1) { - os << '^'; - } else { - os << '~'; - } - if (i < ctx.text.size() && ctx.text[i] == '\t') { - os << '\t'; - } - } - os << t.reset(); - } else { - if (i < ctx.text.size() && ctx.text[i] == '\t') { - os << '\t'; - } else { - os << ' '; - } - } - } - os << std::endl; - - lstart = lend; - } - } -} } diff --git a/src/core/common/Logger.hpp b/src/core/common/Logger.hpp index 85b1bb1..afe58be 100644 --- a/src/core/common/Logger.hpp +++ b/src/core/common/Logger.hpp @@ -19,9 +19,8 @@ /** * @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. + * Contains classes for logging messages in Ousía. Provides various base Logger + * classes that allow to Fork logger instances or to create a GuardedLogger. * * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) */ @@ -30,7 +29,6 @@ #define _OUSIA_LOGGER_HPP_ #include <cstdint> -#include <ostream> #include <string> #include <vector> @@ -109,7 +107,7 @@ inline MessageMode operator|(MessageMode a, MessageMode b) // Forward declaration class LoggerFork; -class ScopedLogger; +class GuardedLogger; /** * The Logger class is the base class the individual logging systems should @@ -123,7 +121,7 @@ class ScopedLogger; class Logger { public: friend LoggerFork; - friend ScopedLogger; + friend GuardedLogger; /** * The message struct represents a single log message and all information @@ -611,12 +609,12 @@ public: }; /** - * The ScopedLogger class can be used to automatically pop any pushed file from + * The GuardedLogger class can be used to automatically pop any pushed file from * the File stack maintained by a Logger class (in a RAII manner). This * simplifies managing pushing and popping files in case there are multiple * return calls or exceptions thrown. */ -class ScopedLogger : public Logger { +class GuardedLogger : public Logger { private: /** * Reference to the parent logger instance. @@ -668,20 +666,20 @@ protected: public: /** - * Constructor of the ScopedLogger class, pushes a first file instance onto + * Constructor of the GuardedLogger class, pushes a first file instance onto * the file stack. * * @param parent is the parent logger instance to which all calls should * be relayed. * @param loc specifies the first source location. */ - ScopedLogger(Logger &parent, SourceLocation loc = SourceLocation{}); + GuardedLogger(Logger &parent, SourceLocation loc = SourceLocation{}); /** - * Destructor of the ScopedLogger class, automatically unwinds the file + * Destructor of the GuardedLogger class, automatically unwinds the file * stack. */ - ~ScopedLogger(); + ~GuardedLogger(); }; /** @@ -818,45 +816,6 @@ public: bool hasFatalError(); }; -/** - * Class extending the Logger class and printing the log messages to the - * given - * stream. - */ -class TerminalLogger : public ConcreteLogger { -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: - void processMessage(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) - : ConcreteLogger(minSeverity), os(os), useColor(useColor) - { - } -}; } #endif /* _OUSIA_LOGGER_HPP_ */ diff --git a/src/core/common/SourceContextReader.cpp b/src/core/common/SourceContextReader.cpp index 65a6281..d5d379c 100644 --- a/src/core/common/SourceContextReader.cpp +++ b/src/core/common/SourceContextReader.cpp @@ -56,8 +56,8 @@ SourceContext SourceContextReader::readContext(CharReader &reader, size_t offs = 0; auto it = std::lower_bound(cache.begin(), cache.end(), start); if (it != cache.begin()) { - it--; // Go to the previous entry - offs = *it; // Read the corresponding byte offset + it--; // Go to the previous entry + offs = *it; // Read the corresponding byte offset size_t line = it - cache.begin() + 1; ctx.startLine = line; ctx.endLine = line; @@ -182,17 +182,23 @@ SourceContext SourceContextReader::readContext(CharReader &reader, } // Update the relative position and length, set the "truncated" flags - size_t us = static_cast<size_t>(s), ue = static_cast<size_t>(e); - ctx.relPos = start - lineBufStart - us; - ctx.relLen = std::min(ctx.relLen, ue - us); + ctx.relPos = std::max<ssize_t>(0, start - lineBufStart - s); + ctx.relLen = std::min<ssize_t>(ctx.relLen, e - s); ctx.truncatedStart = s > ts || lastLineStart < lineBufStart; ctx.truncatedEnd = e < te; // Copy the selected area to the output string - ctx.text = std::string{&lineBuf[s], ue - us}; + ctx.text = std::string{&lineBuf[s], static_cast<size_t>(e - s)}; } return ctx; } + +SourceContext SourceContextReader::readContext(CharReader &reader, + const SourceRange &range, + const std::string &filename) +{ + return readContext(reader, range, MAX_MAX_CONTEXT_LENGTH, filename); +} } diff --git a/src/core/common/SourceContextReader.hpp b/src/core/common/SourceContextReader.hpp index 35e71b3..cd29880 100644 --- a/src/core/common/SourceContextReader.hpp +++ b/src/core/common/SourceContextReader.hpp @@ -82,7 +82,25 @@ public: * @return a SourceContext instance describing the */ SourceContext readContext(CharReader &reader, const SourceRange &range, - size_t maxContextLength = MAX_MAX_CONTEXT_LENGTH, + size_t maxContextLength, + const std::string &filename = ""); + + /** + * Returns the context for the char reader and the given SourceRange. + * Returns an invalid source context if either the given range is invalid + * or the byte offset described in the SourceRange cannot be reached because + * the CharReader cannot be seeked back to this position. Does not limit + * the output context. + * + * @param reader is the CharReader instance from which the context should be + * read. + * @param range describes the Range within the source file for which the + * context should be extraced. + * @param filename is the filename that should be stored in the returned + * context. + * @return a SourceContext instance describing the + */ + SourceContext readContext(CharReader &reader, const SourceRange &range, const std::string &filename = ""); }; } diff --git a/src/core/common/Terminal.cpp b/src/core/frontend/Terminal.cpp index 447e595..5664564 100644 --- a/src/core/common/Terminal.cpp +++ b/src/core/frontend/Terminal.cpp @@ -41,9 +41,23 @@ std::string Terminal::bright() const if (!useColor) { return std::string{}; } - std::stringstream ss; - ss << "\x1b[1m"; - return ss.str(); + return "\x1b[1m"; +} + +std::string Terminal::italic() const +{ + if (!useColor) { + return std::string{}; + } + return "\x1b[3m"; +} + +std::string Terminal::underline() const +{ + if (!useColor) { + return std::string{}; + } + return "\x1b[4m"; } std::string Terminal::reset() const diff --git a/src/core/common/Terminal.hpp b/src/core/frontend/Terminal.hpp index 730853d..90a2e6f 100644 --- a/src/core/common/Terminal.hpp +++ b/src/core/frontend/Terminal.hpp @@ -112,6 +112,20 @@ public: std::string bright() const; /** + * Makes the text italic. + * + * @return a control string to be included in the output stream. + */ + std::string italic() const; + + /** + * Underlines the text. + * + * @return a control string to be included in the output stream. + */ + std::string underline() const; + + /** * Returns a control string for switching to the default mode. * * @return a control string to be included in the output stream. diff --git a/src/core/frontend/TerminalLogger.cpp b/src/core/frontend/TerminalLogger.cpp new file mode 100644 index 0000000..3bead06 --- /dev/null +++ b/src/core/frontend/TerminalLogger.cpp @@ -0,0 +1,177 @@ +/* + 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 <core/common/Utils.hpp> + +#include "Terminal.hpp" +#include "TerminalLogger.hpp" + +namespace ousia { + +/* Class TerminalLogger */ + +void TerminalLogger::processMessage(const Message &msg) +{ + Terminal t(useColor); + + // Fetch filename, position and context + const SourceContext ctx = messageContext(msg); + + // Print the file name + if (ctx.hasFile()) { + os << t.bright() << ctx.filename << t.reset(); + } + + // Print line and column number + if (ctx.hasLine()) { + if (ctx.hasFile()) { + os << ':'; + } + os << t.bright() << ctx.startLine << t.reset(); + if (ctx.hasColumn()) { + os << ':' << ctx.startColumn; + } + } + + // Print the optional seperator + if (ctx.hasFile() || ctx.hasLine()) { + os << ": "; + } + + // Print the severity + switch (msg.severity) { + case Severity::DEBUG: + break; + case Severity::NOTE: + os << t.color(Terminal::CYAN, true) << "note: "; + break; + case Severity::WARNING: + os << t.color(Terminal::MAGENTA, true) << "warning: "; + break; + case Severity::ERROR: + os << t.color(Terminal::RED, true) << "error: "; + break; + case Severity::FATAL_ERROR: + os << t.color(Terminal::RED, true) << "fatal error: "; + break; + } + os << t.reset(); + + // Print the actual message + os << msg.msg << std::endl; + + // Print the error message context if available + if (ctx.hasText()) { + // Iterate over each line in the text + std::vector<std::string> lines = Utils::split(ctx.text, '\n'); + + const size_t relLen = ctx.relLen ? ctx.relLen : 1; + const size_t relPos = ctx.relPos; + const size_t pstart = relPos; + const size_t pend = relPos + relLen; + + size_t lstart = 0; + size_t lend = 0; + for (size_t n = 0; n < lines.size(); n++) { + bool firstLine = n == 0; + bool lastLine = n == lines.size() - 1; + + // Indicate truncation and indent non-first lines + if (ctx.truncatedStart && firstLine) { + os << t.italic() << "[...] " << t.reset(); + } + if (!firstLine) { + os << "\t"; + } + + // Print the actual line, replace tabs + for (char c: lines[n]) { + if (c == '\t') { + os << " "; + } else { + os << c; + } + } + if (!lastLine) { + os << t.color(Terminal::BLACK) << "¶" << t.reset(); + } + + // Indicate truncation + if (ctx.truncatedEnd && lastLine) { + os << t.italic() << " [...]" << t.reset(); + } + os << std::endl; + + // Repeat truncation or indendation space in the next line + if (ctx.truncatedStart && firstLine) { + os << " "; + } + if (!firstLine) { + os << "\t"; + } + + // Print the position indicators + lend = lastLine ? pend : lstart + lines[n].size(); + bool inRegion = false; + for (size_t i = lstart; i < lend + 1; i++) { + if (i >= pstart && i < pend) { + if (!inRegion) { + os << t.color(Terminal::GREEN); + inRegion = true; + } + } else { + if (inRegion) { + os << t.reset(); + inRegion = false; + } + } + char c = i < ctx.text.size() ? ctx.text[i] : ' '; + if (c == '\t') { + if (inRegion) { + if (relLen == 1) { + os << "^ "; + } else { + os << "~~~~"; + } + } else { + os << " "; + } + } else { + if (inRegion) { + if (relLen == 1) { + os << "^"; + } else { + os << "~"; + } + } else { + os << " "; + } + } + } + if (inRegion) { + os << t.reset(); + } + os << std::endl; + + lstart = lend + 1; // skip newline + } + } +} + +} + diff --git a/src/core/frontend/TerminalLogger.hpp b/src/core/frontend/TerminalLogger.hpp new file mode 100644 index 0000000..03930e9 --- /dev/null +++ b/src/core/frontend/TerminalLogger.hpp @@ -0,0 +1,79 @@ +/* + 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 TerminalLogger.hpp + * + * Provides the TerminalLogger class, which is used to log messages to an output + * stream, possibly a Terminal. + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_TERMINAL_LOGGER_HPP_ +#define _OUSIA_TERMINAL_LOGGER_HPP_ + +#include <ostream> + +#include <core/common/Logger.hpp> + +namespace ousia { + +/** + * Class extending the Logger class and printing (possibly colored) log messages + * to the given stream. + */ +class TerminalLogger : public ConcreteLogger { +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: + void processMessage(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) + : ConcreteLogger(minSeverity), os(os), useColor(useColor) + { + } +}; + +} + +#endif /* _OUSIA_TERMINAL_LOGGER_HPP_ */ + + diff --git a/src/core/resource/ResourceManager.cpp b/src/core/resource/ResourceManager.cpp index a5e76b0..184a16d 100644 --- a/src/core/resource/ResourceManager.cpp +++ b/src/core/resource/ResourceManager.cpp @@ -22,6 +22,7 @@ #include <core/common/Exceptions.hpp> #include <core/common/Logger.hpp> #include <core/common/Rtti.hpp> +#include <core/common/SourceContextReader.hpp> #include <core/common/Utils.hpp> #include <core/model/Node.hpp> #include <core/parser/ParserContext.hpp> @@ -128,7 +129,7 @@ Rooted<Node> ResourceManager::parse(ParserContext &ctx, Resource &resource, Rooted<Node> node; try { // Set the current source id in the logger instance - ScopedLogger logger(ctx.logger, SourceLocation{sourceId}); + GuardedLogger logger(ctx.logger, SourceLocation{sourceId}); // Fetch the input stream and create a char reader std::unique_ptr<std::istream> is = resource.stream(); @@ -280,5 +281,11 @@ SourceContext ResourceManager::readContext(const SourceLocation &location, } return SourceContext{}; } + +SourceContext ResourceManager::readContext(const SourceLocation &location) +{ + return readContext(location, SourceContextReader::MAX_MAX_CONTEXT_LENGTH); +} + } diff --git a/src/core/resource/ResourceManager.hpp b/src/core/resource/ResourceManager.hpp index d5381b9..221e2cc 100644 --- a/src/core/resource/ResourceManager.hpp +++ b/src/core/resource/ResourceManager.hpp @@ -34,7 +34,6 @@ #include <core/common/Location.hpp> #include <core/common/Rtti.hpp> -#include <core/common/SourceContextReader.hpp> #include <core/managed/Managed.hpp> #include "Resource.hpp" @@ -230,9 +229,22 @@ public: * @return a valid SourceContext if a valid SourceLocation was given or an * invalid SourceContext if the location is invalid. */ - SourceContext readContext( - const SourceLocation &location, - size_t maxContextLength = SourceContextReader::MAX_MAX_CONTEXT_LENGTH); + SourceContext readContext(const SourceLocation &location, + size_t maxContextLength); + /** + * Creates and returns a SourceContext structure containing information + * about the given SourceLocation (such as line and column number). Throws + * a LoggableException if an irrecoverable error occurs while looking up the + * context (such as a no longer existing resource). Does not limit the + * context length. + * + * @param location is the SourceLocation for which context information + * should be retrieved. This method is used by the Logger class to print + * pretty messages. + * @return a valid SourceContext if a valid SourceLocation was given or an + * invalid SourceContext if the location is invalid. + */ + SourceContext readContext(const SourceLocation &location); }; } |