diff --git a/include/anthem/input/Location.h b/include/anthem/input/Location.h new file mode 100644 index 0000000..e15b337 --- /dev/null +++ b/include/anthem/input/Location.h @@ -0,0 +1,32 @@ +#ifndef __ANTHEM__OUTPUT__LOCATION_H +#define __ANTHEM__OUTPUT__LOCATION_H + +namespace anthem +{ +namespace input +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Location +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Location +{ + const char *sectionStart = nullptr; + const char *sectionEnd = nullptr; + + int rowStart = -1; + int rowEnd = -1; + + int columnStart = -1; + int columnEnd = -1; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/include/anthem/output/ColorStream.h b/include/anthem/output/ColorStream.h new file mode 100644 index 0000000..dd5928a --- /dev/null +++ b/include/anthem/output/ColorStream.h @@ -0,0 +1,294 @@ +#ifndef __ANTHEM__OUTPUT__COLOR_STREAM_H +#define __ANTHEM__OUTPUT__COLOR_STREAM_H + +#include +#include + +namespace anthem +{ +namespace output +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// ColorStream +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class ColorStream +{ + public: + enum class ColorPolicy + { + Never, + Auto, + Always + }; + + private: + using CharacterType = std::ostream::char_type; + using TraitsType = std::ostream::traits_type; + + public: + ColorStream(std::ostream &stream) + : m_stream{stream}, + m_colorPolicy{ColorPolicy::Auto} + { + } + + void setColorPolicy(ColorPolicy colorPolicy) + { + m_colorPolicy = colorPolicy; + } + + bool supportsColor() const + { + if (m_colorPolicy == ColorPolicy::Never) + return false; + + if (m_colorPolicy == ColorPolicy::Always) + return true; + + if (&m_stream == &std::cout) + return isatty(fileno(stdin)); + + if (&m_stream == &std::cerr) + return isatty(fileno(stderr)); + + return false; + } + + std::ostream &stream() + { + return m_stream; + } + + inline ColorStream &operator<<(short value); + inline ColorStream &operator<<(unsigned short value); + inline ColorStream &operator<<(int value); + inline ColorStream &operator<<(unsigned int value); + inline ColorStream &operator<<(long value); + inline ColorStream &operator<<(unsigned long value); + inline ColorStream &operator<<(long long value); + inline ColorStream &operator<<(unsigned long long value); + inline ColorStream &operator<<(float value); + inline ColorStream &operator<<(double value); + inline ColorStream &operator<<(long double value); + inline ColorStream &operator<<(bool value); + inline ColorStream &operator<<(const void *value); + inline ColorStream &operator<<(const char *value); + inline ColorStream &operator<<(const signed char *value); + inline ColorStream &operator<<(const unsigned char *value); + inline ColorStream &operator<<(std::basic_streambuf *sb); + inline ColorStream &operator<<(std::ios_base &(*func)(std::ios_base &)); + inline ColorStream &operator<<(std::basic_ios &(*func)(std::basic_ios &)); + inline ColorStream &operator<<(std::basic_ostream &(*func)(std::basic_ostream &)); + + inline ColorStream &operator<<(char value); + inline ColorStream &operator<<(signed char value); + inline ColorStream &operator<<(unsigned char value); + + private: + std::ostream &m_stream; + ColorPolicy m_colorPolicy; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(short value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(unsigned short value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(int value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(unsigned int value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(long value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(unsigned long value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(long long value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(unsigned long long value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(float value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(double value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(long double value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(bool value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(const void *value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(const char *value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(const signed char *value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(const unsigned char *value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(std::basic_streambuf* sb) +{ + m_stream << sb; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(std::ios_base &(*func)(std::ios_base &)) +{ + m_stream << func; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(std::basic_ios &(*func)(std::basic_ios &)) +{ + m_stream << func; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(std::basic_ostream &(*func)(std::basic_ostream &)) +{ + m_stream << func; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline ColorStream &operator<<(ColorStream &colorStream, const std::basic_string &string) +{ + colorStream.stream() << string; + return colorStream; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(char value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(signed char value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &ColorStream::operator<<(unsigned char value) +{ + m_stream << value; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/include/anthem/output/Formatting.h b/include/anthem/output/Formatting.h new file mode 100644 index 0000000..86938d6 --- /dev/null +++ b/include/anthem/output/Formatting.h @@ -0,0 +1,244 @@ +#ifndef __ANTHEM_OUTPUT__FORMATTING_H +#define __ANTHEM_OUTPUT__FORMATTING_H + +#include + +#include + +namespace anthem +{ +namespace output +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Formatting +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +enum class Color +{ + Default = 39, + Black = 30, + Red = 31, + Green = 32, + Yellow = 33, + Blue = 34, + Magenta = 35, + Cyan = 36, + LightGray = 37, + DarkGray = 90, + LightRed = 91, + LightGreen = 92, + LightYellow = 93, + LightBlue = 94, + LightMagenta = 95, + LightCyan = 96, + White = 97 +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +enum class FontWeight +{ + Normal = 21, + Bold = 1 +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Format +{ + Color color = Color::Default; + FontWeight fontWeight = FontWeight::Normal; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Format &format) +{ + if (!stream.supportsColor()) + return stream; + + const auto fontWeightCode = static_cast(format.fontWeight); + const auto colorCode = static_cast(format.color); + + return (stream << "\033[" << fontWeightCode << ";" << colorCode << "m"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct ResetFormat +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const ResetFormat &) +{ + if (!stream.supportsColor()) + return stream; + + return (stream << "\033[0m"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Token +{ + const char *name; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Function: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Function &function) +{ + return (stream + << Format({Color::White, FontWeight::Bold}) + << function.name + << ResetFormat()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Keyword: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Keyword &keyword) +{ + return (stream + << Format({Color::Blue, FontWeight::Normal}) + << keyword.name + << ResetFormat()); +} +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Number: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Number &number) +{ + return (stream + << Format({Color::Yellow, FontWeight::Normal}) + << number.name + << ResetFormat()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Variable: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Variable &variable) +{ + return (stream + << Format({Color::Green, FontWeight::Bold}) + << variable.name + << ResetFormat()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct String: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const String &string) +{ + return (stream + << Format({Color::Green, FontWeight::Normal}) + << "\"" << string.name << "\"" + << ResetFormat()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Boolean: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Boolean &boolean) +{ + return (stream + << Format({Color::Red, FontWeight::Normal}) + << boolean.name + << ResetFormat()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Reserved: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Reserved &reserved) +{ + return (stream + << Format({Color::White, FontWeight::Normal}) + << reserved.name + << ResetFormat()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Heading1: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Heading1 &heading1) +{ + return (stream + << Format({Color::Blue, FontWeight::Bold}) + << "%---------------------------------------" << std::endl + << "% " << heading1.name << std::endl + << "%---------------------------------------" + << ResetFormat() + << std::endl); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Heading2: public Token +{ +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline ColorStream &operator<<(ColorStream &stream, const Heading2 &heading2) +{ + return (stream + << Format({Color::Blue, FontWeight::Bold}) + << "% " << heading2.name + << ResetFormat()); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/include/anthem/output/Logger.h b/include/anthem/output/Logger.h new file mode 100644 index 0000000..4d695b1 --- /dev/null +++ b/include/anthem/output/Logger.h @@ -0,0 +1,54 @@ +#ifndef __ANTHEM__OUTPUT__LOGGER_H +#define __ANTHEM__OUTPUT__LOGGER_H + +#include + +#include +#include +#include + +namespace anthem +{ +namespace output +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Logger +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class Logger +{ + public: + Logger(); + + Logger(const Logger &other) = default; + Logger &operator=(const Logger &other) = default; + + Logger(Logger &&other) = default; + Logger &operator=(Logger &&other) = default; + + ColorStream &outputStream(); + ColorStream &errorStream(); + + // The level from which on messages should be printed + void setOutputPriority(Priority outputLevel); + void setColorPolicy(ColorStream::ColorPolicy colorPolicy); + + void log(Priority priority, const char *message); + void log(Priority priority, const input::Location &location, const char *message); + + private: + ColorStream m_outputStream; + ColorStream m_errorStream; + + Priority m_outputPriority; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/include/anthem/output/Priority.h b/include/anthem/output/Priority.h new file mode 100644 index 0000000..47a5738 --- /dev/null +++ b/include/anthem/output/Priority.h @@ -0,0 +1,28 @@ +#ifndef __ANTHEM__OUTPUT__PRIORITY_H +#define __ANTHEM__OUTPUT__PRIORITY_H + +namespace anthem +{ +namespace output +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Priority +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +enum class Priority +{ + Debug, + Note, + Warning, + Error +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ac8a63..2076c74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,9 +3,15 @@ set(target anthem) file(GLOB core_sources "anthem/*.cpp") file(GLOB core_headers "../include/anthem/*.h") +file(GLOB output_sources "anthem/output/*.cpp") +file(GLOB output_headers "../include/anthem/output/*.h") + set(sources ${core_sources} ${core_headers} + + ${output_sources} + ${output_headers} ) set(includes diff --git a/src/anthem/output/Logger.cpp b/src/anthem/output/Logger.cpp new file mode 100644 index 0000000..bc215a9 --- /dev/null +++ b/src/anthem/output/Logger.cpp @@ -0,0 +1,135 @@ +#include + +#include + +namespace anthem +{ +namespace output +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Logger +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +constexpr Format priorityFormat(Priority priority) +{ + switch (priority) + { + case Priority::Debug: + return {Color::Green, FontWeight::Bold}; + case Priority::Note: + return {Color::Cyan, FontWeight::Bold}; + case Priority::Warning: + return {Color::Magenta, FontWeight::Bold}; + case Priority::Error: + return {Color::Red, FontWeight::Bold}; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +constexpr const char *priorityName(Priority priority) +{ + switch (priority) + { + case Priority::Debug: + return "debug"; + case Priority::Note: + return "note"; + case Priority::Warning: + return "warning"; + case Priority::Error: + return "error"; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +constexpr const Format MessageBodyFormat = {Color::White, FontWeight::Bold}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +constexpr const Format LocationFormat = {Color::White, FontWeight::Bold}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +Logger::Logger() +: m_outputStream{std::cout}, + m_errorStream{std::cerr}, + m_outputPriority{Priority::Warning} +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &Logger::outputStream() +{ + return m_outputStream; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +ColorStream &Logger::errorStream() +{ + return m_errorStream; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Logger::setOutputPriority(Priority outputPriority) +{ + m_outputPriority = outputPriority; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Logger::setColorPolicy(ColorStream::ColorPolicy colorPolicy) +{ + m_outputStream.setColorPolicy(colorPolicy); + m_errorStream.setColorPolicy(colorPolicy); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Logger::log(Priority priority, const char *message) +{ + const auto priorityID = static_cast(priority); + + auto &stream = + (priorityID > static_cast(Priority::Warning)) + ? m_errorStream + : m_outputStream; + + stream + << priorityFormat(priority) << priorityName(priority) << ":" + << ResetFormat() << " " + << MessageBodyFormat << message + << ResetFormat() << std::endl; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Logger::log(Priority priority, const input::Location &location, const char *message) +{ + const auto priorityID = static_cast(priority); + + auto &stream = + (priorityID > static_cast(Priority::Warning)) + ? m_errorStream + : m_outputStream; + + stream + << LocationFormat + << location.sectionStart << ":" << location.rowStart << ":" << location.columnStart << ":" + << priorityFormat(priority) << priorityName(priority) << ":" + << ResetFormat() << " " + << MessageBodyFormat << message + << ResetFormat() << std::endl; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +}