diff --git a/.gitmodules b/.gitmodules index 2c139441a..94cc07e61 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,6 @@ [submodule "lib/picosha2"] path = lib/picosha2 url = https://github.com/okdshin/PicoSHA2.git -[submodule "lib/termcolor"] - path = lib/termcolor - url = https://github.com/ikalnytskyi/termcolor.git [submodule "lib/replxx"] path = lib/replxx url = https://github.com/AmokHuginnsson/replxx.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 88dade39b..b4192e88d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ - removed `VM::getUserPointer` and `VM::setUserPointer` - removed `ARK_PROFILER_COUNT` define - removed useless `\0` escape in strings +- removed `termcolor` dependency to rely on `fmt` for coloring outputs ## [3.5.0] - 2023-02-19 ### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index a3e487499..ec2af6c07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,9 +102,6 @@ endif () # Link libraries -add_subdirectory("${ark_SOURCE_DIR}/lib/termcolor" EXCLUDE_FROM_ALL) -target_link_libraries(ArkReactor PUBLIC termcolor) - target_include_directories(ArkReactor SYSTEM PUBLIC "${ark_SOURCE_DIR}/lib/picosha2/" @@ -179,7 +176,7 @@ if (ARK_TESTS) add_subdirectory(${ark_SOURCE_DIR}/lib/ut) target_include_directories(unittests PUBLIC ${ark_SOURCE_DIR}/include) - target_link_libraries(unittests PUBLIC ArkReactor termcolor ut) + target_link_libraries(unittests PUBLIC ArkReactor ut) add_compile_definitions(BOOST_UT_DISABLE_MODULE) target_compile_features(unittests PRIVATE cxx_std_20) @@ -192,7 +189,7 @@ if (ARK_BENCHMARKS) CPMAddPackage("gh:google/benchmark@1.8.3") add_executable(bench tests/benchmarks/main.cpp) - target_link_libraries(bench PUBLIC ArkReactor termcolor benchmark::benchmark) + target_link_libraries(bench PUBLIC ArkReactor benchmark::benchmark) target_compile_features(bench PRIVATE cxx_std_20) target_compile_definitions(bench PRIVATE ARK_TESTS_ROOT="${CMAKE_CURRENT_SOURCE_DIR}/") enable_lto(bench) @@ -209,7 +206,7 @@ if (ARK_BUILD_EXE) add_subdirectory("${ark_SOURCE_DIR}/lib/clipp" EXCLUDE_FROM_ALL) target_include_directories(arkscript SYSTEM PUBLIC "${ark_SOURCE_DIR}/lib/clipp/include") - target_link_libraries(arkscript PUBLIC ArkReactor replxx clipp termcolor) + target_link_libraries(arkscript PUBLIC ArkReactor replxx clipp) target_compile_features(arkscript PRIVATE cxx_std_20) enable_lto(arkscript) diff --git a/include/Ark/Exceptions.hpp b/include/Ark/Exceptions.hpp index 30b47fd29..18a576549 100644 --- a/include/Ark/Exceptions.hpp +++ b/include/Ark/Exceptions.hpp @@ -111,8 +111,9 @@ namespace Ark * @param target_line line where the error is * @param col_start where the error starts on the given line * @param sym_size bad expression that triggered the error + * @param colorize generate colors or not */ - ARK_API void makeContext(std::ostream& os, const std::string& code, std::size_t target_line, std::size_t col_start, std::size_t sym_size); + ARK_API void makeContext(std::ostream& os, const std::string& code, std::size_t target_line, std::size_t col_start, std::size_t sym_size, bool colorize); /** * @brief Helper used by the compiler to generate a colorized context from a node @@ -127,10 +128,10 @@ namespace Ark * @brief Generate a diagnostic from an error and print it to the standard output * * @param e code error - * @param code code of the file in which the error occurred * @param os output stream + * @param colorize generate colors or not */ - ARK_API void generate(const CodeError& e, std::string code = "", std::ostream& os = std::cout); + ARK_API void generate(const CodeError& e, std::ostream& os = std::cout, bool colorize = true); } } diff --git a/include/Ark/Logger.hpp b/include/Ark/Logger.hpp index 341a5c37e..87e61c40d 100644 --- a/include/Ark/Logger.hpp +++ b/include/Ark/Logger.hpp @@ -47,27 +47,21 @@ namespace Ark::internal void info(const char* fmt, Args&&... args) { if (shouldInfo()) - std::cout << fmt::format("[INFO ][{}] ", m_name) - << fmt::vformat(fmt, fmt::make_format_args(args...)) - << std::endl; + fmt::println("[INFO ][{}] {}", m_name, fmt::vformat(fmt, fmt::make_format_args(args...))); } template void debug(const char* fmt, Args&&... args) { if (shouldDebug()) - std::cout << fmt::format("[DEBUG][{}] ", m_name) - << fmt::vformat(fmt, fmt::make_format_args(args...)) - << std::endl; + fmt::println("[DEBUG][{}] {}", m_name, fmt::vformat(fmt, fmt::make_format_args(args...))); } template void trace(const char* fmt, Args&&... args) { if (shouldTrace()) - std::cout << fmt::format("[TRACE][{}] ", m_name) - << fmt::vformat(fmt, fmt::make_format_args(args...)) - << std::endl; + fmt::println("[TRACE][{}] {}", m_name, fmt::vformat(fmt, fmt::make_format_args(args...))); } private: diff --git a/include/termcolor/proxy.hpp b/include/termcolor/proxy.hpp deleted file mode 100644 index e3f5dbbcc..000000000 --- a/include/termcolor/proxy.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef INCLUDE_TERMCOLOR_PROXY_HPP -#define INCLUDE_TERMCOLOR_PROXY_HPP - -#ifdef WIN32 -# define NOMINMAX -#endif - -#ifdef max -# undef max -#endif - -#ifdef abs -# undef abs -#endif - -#include -#include - -#endif diff --git a/lib/README.md b/lib/README.md index 1a43712c7..a2c3566ce 100644 --- a/lib/README.md +++ b/lib/README.md @@ -6,7 +6,6 @@ Includes * [fmt](https://github.com/fmtlib/fmt), MIT License * [picosha2](https://github.com/okdshin/PicoSHA2), MIT License * [replxx](https://github.com/AmokHuginnsson/replxx/blob/master/LICENSE.md), MIT License + specifities -* [termcolor](https://github.com/ikalnytskyi/termcolor), BSD (3-clause) License * [ut](https://github.com/boost-ext/ut), BSL 1.0 All used by [Ark](https://github.com/ArkScript-lang/Ark) diff --git a/lib/modules b/lib/modules index e3627a0b4..924a52c57 160000 --- a/lib/modules +++ b/lib/modules @@ -1 +1 @@ -Subproject commit e3627a0b48e61a014b6a8cdf06a1edc8808117e7 +Subproject commit 924a52c57943d39f5c08b32690a6c765fd5921cc diff --git a/lib/termcolor b/lib/termcolor deleted file mode 160000 index 13f559a97..000000000 --- a/lib/termcolor +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 13f559a970025cd0d5bf9f9077dfa2d618588fbe diff --git a/src/arkreactor/Builtins/IO.cpp b/src/arkreactor/Builtins/IO.cpp index 7ac0f74f6..c7df14562 100644 --- a/src/arkreactor/Builtins/IO.cpp +++ b/src/arkreactor/Builtins/IO.cpp @@ -24,8 +24,8 @@ namespace Ark::internal::Builtins::IO Value print(std::vector& n, VM* vm) { for (auto& value : n) - std::cout << value.toString(*vm); - std::cout << '\n'; + fmt::print("{}", value.toString(*vm)); + fmt::println(""); return nil; } @@ -43,7 +43,7 @@ namespace Ark::internal::Builtins::IO Value puts_(std::vector& n, VM* vm) { for (auto& value : n) - std::cout << value.toString(*vm); + fmt::print("{}", value.toString(*vm)); return nil; } @@ -189,6 +189,8 @@ namespace Ark::internal::Builtins::IO std::vector r; for (const auto& entry : std::filesystem::directory_iterator(n[0].string())) + // cppcheck-suppress useStlAlgorithm + // We can't use std::transform with a directory_iterator r.emplace_back(entry.path().string()); return Value(std::move(r)); diff --git a/src/arkreactor/Compiler/BytecodeReader.cpp b/src/arkreactor/Compiler/BytecodeReader.cpp index 078f98ce3..9fd5fd484 100644 --- a/src/arkreactor/Compiler/BytecodeReader.cpp +++ b/src/arkreactor/Compiler/BytecodeReader.cpp @@ -4,9 +4,9 @@ #include #include -#include #include #include +#include namespace Ark { @@ -198,34 +198,30 @@ namespace Ark const std::optional sEnd, const std::optional cPage) const { - std::ostream& os = std::cout; - if (!checkMagic()) { - os << "Invalid format"; + fmt::print("Invalid format"); return; } auto [major, minor, patch] = version(); - os << "Version: " << major << "." << minor << "." << patch << "\n"; - os << "Timestamp: " << timestamp() << "\n"; - os << "SHA256: "; + fmt::println("Version: {}.{}.{}", major, minor, patch); + fmt::println("Timestamp: {}", timestamp()); + fmt::print("SHA256: "); for (const auto sha = sha256(); unsigned char h : sha) - os << fmt::format("{:02x}", h); - os << "\n\n"; + fmt::print("{:02x}", h); + fmt::print("\n\n"); // reading the different tables, one after another if ((sStart.has_value() && !sEnd.has_value()) || (!sStart.has_value() && sEnd.has_value())) { - os << termcolor::red << "Both start and end parameter need to be provided together\n" - << termcolor::reset; + fmt::print(fmt::fg(fmt::color::red), "Both start and end parameter need to be provided together\n"); return; } if (sStart.has_value() && sEnd.has_value() && sStart.value() >= sEnd.value()) { - os << termcolor::red << "Invalid slice start and end arguments\n" - << termcolor::reset; + fmt::print(fmt::fg(fmt::color::red), "Invalid slice start and end arguments\n"); return; } @@ -240,12 +236,12 @@ namespace Ark bool showSym = (segment == BytecodeSegment::All || segment == BytecodeSegment::Symbols); if (showSym && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size)) - os << termcolor::red << "Slice start or end can't be greater than the segment size: " << size << "\n"; + fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size); else if (showSym && sStart.has_value() && sEnd.has_value()) sliceSize = sEnd.value() - sStart.value() + 1; if (showSym || segment == BytecodeSegment::HeadersOnly) - os << termcolor::cyan << "Symbols table" << termcolor::reset << " (length: " << sliceSize << ")\n"; + fmt::println("{} (length: {})", fmt::styled("Symbols table", fmt::fg(fmt::color::cyan)), sliceSize); for (std::size_t j = 0; j < size; ++j) { @@ -253,11 +249,11 @@ namespace Ark showSym = showSym && (j >= start.value() && j <= end.value()); if (showSym) - os << fmt::format("{}) {}\n", j, syms.symbols[j]); + fmt::println("{}) {}", j, syms.symbols[j]); } if (showSym) - os << "\n"; + fmt::print("\n"); if (segment == BytecodeSegment::Symbols) return; } @@ -269,12 +265,12 @@ namespace Ark bool showVal = (segment == BytecodeSegment::All || segment == BytecodeSegment::Values); if (showVal && sStart.has_value() && sEnd.has_value() && (sStart.value() > size || sEnd.value() > size)) - os << termcolor::red << "Slice start or end can't be greater than the segment size: " << size << "\n"; + fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", size); else if (showVal && sStart.has_value() && sEnd.has_value()) sliceSize = sEnd.value() - sStart.value() + 1; if (showVal || segment == BytecodeSegment::HeadersOnly) - os << termcolor::green << "Constants table" << termcolor::reset << " (length: " << sliceSize << ")\n"; + fmt::println("{} (length: {})", fmt::styled("Constants table", fmt::fg(fmt::color::cyan)), sliceSize); for (std::size_t j = 0; j < size; ++j) { @@ -286,25 +282,23 @@ namespace Ark switch (const auto val = vals.values[j]; val.valueType()) { case ValueType::Number: - os << fmt::format("{}) (Number) {}\n", j, val.number()); + fmt::println("{}) (Number) {}", j, val.number()); break; case ValueType::String: - os << fmt::format("{}) (String) {}\n", j, val.string()); + fmt::println("{}) (String) {}", j, val.string()); break; case ValueType::PageAddr: - os << fmt::format("{}) (PageAddr) {}\n", j, val.pageAddr()); + fmt::println("{}) (PageAddr) {}", j, val.pageAddr()); break; default: - os << termcolor::red << "Value type not handled: " << types_to_str[static_cast(val.valueType())] - << '\n' - << termcolor::reset; + fmt::print(fmt::fg(fmt::color::red), "Value type not handled: {}\n", types_to_str[static_cast(val.valueType())]); break; } } } if (showVal) - os << "\n"; + fmt::print("\n"); if (segment == BytecodeSegment::Values) return; } @@ -323,6 +317,44 @@ namespace Ark } }; + enum class ArgKind + { + Symbol, + Value, + Builtin, + Raw + }; + + struct Arg + { + ArgKind kind; + uint16_t arg; + }; + + const auto color_print_inst = [&syms, &vals, &stringify_value](const std::string& name, std::optional arg = std::nullopt) { + fmt::print("{}", fmt::styled(name, fmt::fg(fmt::color::gold))); + if (arg.has_value()) + { + switch (auto [kind, idx] = arg.value(); kind) + { + case ArgKind::Symbol: + fmt::print(fmt::fg(fmt::color::green), " {}\n", syms.symbols[idx]); + break; + case ArgKind::Value: + fmt::print(fmt::fg(fmt::color::magenta), " {}\n", stringify_value(vals.values[idx])); + break; + case ArgKind::Builtin: + fmt::print(" {}\n", Builtins::builtins[idx].first); + break; + case ArgKind::Raw: + fmt::print(fmt::fg(fmt::color::red), " ({})\n", idx); + break; + } + } + else + fmt::print("\n"); + }; + if (segment == BytecodeSegment::All || segment == BytecodeSegment::Code || segment == BytecodeSegment::HeadersOnly) { uint16_t pp = 0; @@ -335,12 +367,16 @@ namespace Ark displayCode = pp == wanted_page.value(); if (displayCode) - os << termcolor::magenta << "Code segment " << pp << termcolor::reset << " (length: " << page.size() << ")\n"; + fmt::println( + "{} {} (length: {})", + fmt::styled("Code segment", fmt::fg(fmt::color::magenta)), + fmt::styled(pp, fmt::fg(fmt::color::magenta)), + page.size()); if (page.empty()) { if (displayCode) - os << "NOP"; + fmt::print("NOP"); } else { @@ -348,7 +384,7 @@ namespace Ark { if (sStart.has_value() && sEnd.has_value() && ((sStart.value() > page.size()) || (sEnd.value() > page.size()))) { - os << termcolor::red << "Slice start or end can't be greater than the segment size: " << page.size() << termcolor::reset << "\n"; + fmt::print(fmt::fg(fmt::color::red), "Slice start or end can't be greater than the segment size: {}\n", page.size()); return; } @@ -359,125 +395,122 @@ namespace Ark const auto arg = static_cast((page[j + 2] << 8) + page[j + 3]); // instruction number - os << termcolor::cyan << fmt::format("{:>4}", j / 4) << termcolor::reset; + fmt::print(fmt::fg(fmt::color::cyan), "{:>4}", j / 4); // padding inst arg arg - os << fmt::format(" {:02x} {:02x} {:02x} {:02x} ", padding, inst, page[j + 2], page[j + 3]); - os << termcolor::yellow; + fmt::print(" {:02x} {:02x} {:02x} {:02x} ", padding, inst, page[j + 2], page[j + 3]); if (inst == NOP) - os << "NOP\n"; + color_print_inst("NOP"); else if (inst == LOAD_SYMBOL) - os << "LOAD_SYMBOL " << termcolor::green << syms.symbols[arg] << "\n"; + color_print_inst("LOAD_SYMBOL", Arg { ArgKind::Symbol, arg }); else if (inst == LOAD_CONST) - os << "LOAD_CONST " << termcolor::magenta << stringify_value(vals.values[arg]) << "\n"; + color_print_inst("LOAD_CONST", Arg { ArgKind::Symbol, arg }); else if (inst == POP_JUMP_IF_TRUE) - os << "POP_JUMP_IF_TRUE " << termcolor::red << "(" << arg << ")\n"; + color_print_inst("POP_JUMP_IF_TRUE", Arg { ArgKind::Raw, arg }); else if (inst == STORE) - os << "STORE " << termcolor::green << syms.symbols[arg] << "\n"; + color_print_inst("STORE", Arg { ArgKind::Symbol, arg }); else if (inst == LET) - os << "LET " << termcolor::green << syms.symbols[arg] << "\n"; + color_print_inst("LET", Arg { ArgKind::Symbol, arg }); else if (inst == POP_JUMP_IF_FALSE) - os << "POP_JUMP_IF_FALSE " << termcolor::red << "(" << arg << ")\n"; + color_print_inst("POP_JUMP_IF_FALSE", Arg { ArgKind::Raw, arg }); else if (inst == JUMP) - os << "JUMP " << termcolor::red << "(" << arg << ")\n"; + color_print_inst("JUMP", Arg { ArgKind::Raw, arg }); else if (inst == RET) - os << "RET\n"; + color_print_inst("RET"); else if (inst == HALT) - os << "HALT\n"; + color_print_inst("HALT"); else if (inst == CALL) - os << "CALL " << termcolor::reset << "(" << arg << ")\n"; + color_print_inst("CALL", Arg { ArgKind::Raw, arg }); else if (inst == CAPTURE) - os << "CAPTURE " << termcolor::reset << syms.symbols[arg] << "\n"; + color_print_inst("CAPTURE", Arg { ArgKind::Symbol, arg }); else if (inst == BUILTIN) - os << "BUILTIN " << termcolor::reset << Builtins::builtins[arg].first << "\n"; + color_print_inst("BUILTIN", Arg { ArgKind::Builtin, arg }); else if (inst == MUT) - os << "MUT " << termcolor::green << syms.symbols[arg] << "\n"; + color_print_inst("MUT", Arg { ArgKind::Symbol, arg }); else if (inst == DEL) - os << "DEL " << termcolor::green << syms.symbols[arg] << "\n"; + color_print_inst("DEL", Arg { ArgKind::Symbol, arg }); else if (inst == SAVE_ENV) - os << "SAVE_ENV\n"; + color_print_inst("SAVE_ENV"); else if (inst == GET_FIELD) - os << "GET_FIELD " << termcolor::green << syms.symbols[arg] << "\n"; + color_print_inst("GET_FIELD", Arg { ArgKind::Symbol, arg }); else if (inst == PLUGIN) - os << "PLUGIN " << termcolor::magenta << stringify_value(vals.values[arg]) << "\n"; + color_print_inst("PLUGIN", Arg { ArgKind::Value, arg }); else if (inst == LIST) - os << "LIST " << termcolor::reset << "(" << arg << ")\n"; + color_print_inst("LIST", Arg { ArgKind::Raw, arg }); else if (inst == APPEND) - os << "APPEND " << termcolor::reset << "(" << arg << ")\n"; + color_print_inst("APPEND", Arg { ArgKind::Raw, arg }); else if (inst == CONCAT) - os << "CONCAT " << termcolor::reset << "(" << arg << ")\n"; + color_print_inst("CONCAT", Arg { ArgKind::Raw, arg }); else if (inst == APPEND_IN_PLACE) - os << "APPEND_IN_PLACE " << termcolor::reset << "(" << arg << ")\n"; + color_print_inst("APPEND_IN_PLACE", Arg { ArgKind::Raw, arg }); else if (inst == CONCAT_IN_PLACE) - os << "CONCAT_IN_PLACE " << termcolor::reset << "(" << arg << ")\n"; + color_print_inst("CONCAT_IN_PLACE", Arg { ArgKind::Raw, arg }); else if (inst == POP_LIST) - os << "POP_LIST " << termcolor::reset << "\n"; + color_print_inst("POP_LIST"); else if (inst == POP_LIST_IN_PLACE) - os << "POP_LIST_IN_PLACE " << termcolor::reset << "\n"; + color_print_inst("POP_LIST_IN_PLACE"); else if (inst == POP) - os << "POP\n"; + color_print_inst("POP"); else if (inst == ADD) - os << "ADD\n"; + color_print_inst("ADD"); else if (inst == SUB) - os << "SUB\n"; + color_print_inst("SUB"); else if (inst == MUL) - os << "MUL\n"; + color_print_inst("MUL"); else if (inst == DIV) - os << "DIV\n"; + color_print_inst("DIV"); else if (inst == GT) - os << "GT\n"; + color_print_inst("GT"); else if (inst == LT) - os << "LT\n"; + color_print_inst("LT"); else if (inst == LE) - os << "LE\n"; + color_print_inst("LE"); else if (inst == GE) - os << "GE\n"; + color_print_inst("GE"); else if (inst == NEQ) - os << "NEQ\n"; + color_print_inst("NEQ"); else if (inst == EQ) - os << "EQ\n"; + color_print_inst("EQ"); else if (inst == LEN) - os << "LEN\n"; + color_print_inst("LEN"); else if (inst == EMPTY) - os << "EMPTY\n"; + color_print_inst("EMPTY"); else if (inst == TAIL) - os << "TAIL\n"; + color_print_inst("TAIL"); else if (inst == HEAD) - os << "HEAD\n"; + color_print_inst("HEAD"); else if (inst == ISNIL) - os << "ISNIL\n"; + color_print_inst("ISNIL"); else if (inst == ASSERT) - os << "ASSERT\n"; + color_print_inst("ASSERT"); else if (inst == TO_NUM) - os << "TO_NUM\n"; + color_print_inst("TO_NUM"); else if (inst == TO_STR) - os << "TO_STR\n"; + color_print_inst("TO_STR"); else if (inst == AT) - os << "AT\n"; + color_print_inst("AT"); else if (inst == AND_) - os << "AND_\n"; + color_print_inst("AND_"); else if (inst == OR_) - os << "OR_\n"; + color_print_inst("OR_"); else if (inst == MOD) - os << "MOD\n"; + color_print_inst("MOD"); else if (inst == TYPE) - os << "TYPE\n"; + color_print_inst("TYPE"); else if (inst == HASFIELD) - os << "HASFIELD\n"; + color_print_inst("HASFIELD"); else if (inst == NOT) - os << "NOT\n"; + color_print_inst("NOT"); else { - os << termcolor::reset << fmt::format("Unknown instruction: {:02x}", inst) << '\n' - << termcolor::reset; + fmt::println("Unknown instruction: {:02x}", inst); return; } } } } if (displayCode && segment != BytecodeSegment::HeadersOnly) - os << "\n" - << termcolor::reset; + fmt::print("\n"); ++pp; } diff --git a/src/arkreactor/Compiler/Compiler.cpp b/src/arkreactor/Compiler/Compiler.cpp index 36048451a..2f363b41f 100644 --- a/src/arkreactor/Compiler/Compiler.cpp +++ b/src/arkreactor/Compiler/Compiler.cpp @@ -6,8 +6,8 @@ #include #include #include -#include #include +#include #include #include @@ -254,7 +254,7 @@ namespace Ark void Compiler::compilerWarning(const std::string& message, const Node& node) { - std::cout << termcolor::yellow << "Warning " << termcolor::reset << Diagnostics::makeContextWithNode(message, node) << "\n"; + fmt::println("{} {}", fmt::styled("Warning", fmt::fg(fmt::color::dark_orange)), Diagnostics::makeContextWithNode(message, node)); } void Compiler::throwCompilerError(const std::string& message, const Node& node) diff --git a/src/arkreactor/Exceptions.cpp b/src/arkreactor/Exceptions.cpp index 7b89a143a..625d95fad 100644 --- a/src/arkreactor/Exceptions.cpp +++ b/src/arkreactor/Exceptions.cpp @@ -1,9 +1,12 @@ #include -#include #include -#include +#include +#include +#include +#include +#include #include #include #include @@ -26,9 +29,12 @@ namespace Ark::Diagnostics { // clang-format off constexpr std::array pairing_color { - termcolor::bright_blue, - termcolor::bright_green, - termcolor::bright_yellow + fmt::color::light_blue, + fmt::color::light_green, + fmt::color::light_salmon, + fmt::color::light_yellow, + fmt::color::light_cyan, + fmt::color::light_coral }; // clang-format on constexpr std::size_t pairing_color_size = pairing_color.size(); @@ -69,14 +75,14 @@ namespace Ark::Diagnostics break; } - ss << pairing_color[pairing_color_index] << c << termcolor::reset; + fmt::print(ss, "{}", fmt::styled(c, fmt::fg(pairing_color[pairing_color_index]))); } else - ss << c; + fmt::print(ss, "{}", c); } } - void makeContext(std::ostream& os, const std::string& code, const std::size_t target_line, const std::size_t col_start, const std::size_t sym_size) + void makeContext(std::ostream& os, const std::string& code, const std::size_t target_line, const std::size_t col_start, const std::size_t sym_size, const bool colorize) { const std::vector ctx = Utils::splitString(code, '\n'); if (target_line >= ctx.size()) @@ -89,15 +95,16 @@ namespace Ark::Diagnostics for (auto i = first_line; i < last_line; ++i) { - os << termcolor::green << std::setw(5) << (i + 1) << termcolor::reset << " |"; - if (!ctx[i].empty()) - os << ' '; - colorizeLine(ctx[i], line_color_context_counts, os); - os << "\n"; + fmt::print(os, "{: >5} |{}", i + 1, !ctx[i].empty() ? " " : ""); + if (colorize) + colorizeLine(ctx[i], line_color_context_counts, os); + else + fmt::print(os, "{}", ctx[i]); + fmt::print(os, "\n"); if (i == target_line || (i > target_line && overflow > 0)) { - os << " |"; + fmt::print(os, " |"); // if we have an overflow then we start at the beginning of the line const std::size_t curr_col_start = (overflow == 0) ? col_start : 0; // if we have an overflow, it is used as the end of the line @@ -106,34 +113,29 @@ namespace Ark::Diagnostics // update the overflow to avoid going here again if not needed overflow = (overflow > ctx[i].size()) ? overflow - ctx[i].size() : 0; - // fixing padding when the error is on the first character - if (curr_col_start == 0) - os << " "; - - // padding of spaces - for (std::size_t j = 0; j < curr_col_start; ++j) - os << " "; - - // underline the error - os << termcolor::red << "^"; - for (std::size_t j = curr_col_start + 1; j < col_end; ++j) - os << "~"; - - os << termcolor::reset << "\n"; + fmt::print( + os, + "{: <{}}{:~<{}}\n", + // padding of spaces + " ", + std::max(1ul, curr_col_start), // fixing padding when the error is on the first character + // underline the error in red + fmt::styled("^", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()), + col_end - curr_col_start); } } } template - void helper(std::ostream& os, const std::string& message, const std::string& filename, const std::string& code, const T& expr, const std::size_t line, std::size_t column, const std::size_t sym_size) + void helper(std::ostream& os, const std::string& message, bool colorize, const std::string& filename, const std::string& code, const T& expr, const std::size_t line, std::size_t column, const std::size_t sym_size) { if (filename != ARK_NO_NAME_FILE) - os << "In file " << filename << "\n"; - os << "At " << expr << " @ " << (line + 1) << ":" << column << "\n"; + fmt::print(os, "In file {}\n", filename); + fmt::print(os, "At {} @ {}:{}\n", expr, line + 1, column); if (!code.empty()) - makeContext(os, code, line, column, sym_size); - os << " " << message; + makeContext(os, code, line, column, sym_size, colorize); + fmt::print(os, " {}", message); } std::string makeContextWithNode(const std::string& message, const internal::Node& node) @@ -148,6 +150,7 @@ namespace Ark::Diagnostics helper( ss, message, + true, node.filename(), (node.filename() == ARK_NO_NAME_FILE) ? "" : Utils::readFile(node.filename()), node.repr(), @@ -158,7 +161,7 @@ namespace Ark::Diagnostics return ss.str(); } - void generate(const CodeError& e, std::string code, std::ostream& os) + void generate(const CodeError& e, std::ostream& os, bool colorize) { std::string escaped_symbol; if (e.symbol.has_value()) @@ -179,15 +182,14 @@ namespace Ark::Diagnostics escaped_symbol = e.expr; std::string file_content; - if (e.filename == ARK_NO_NAME_FILE) - file_content = std::move(code); - else + if (e.filename != ARK_NO_NAME_FILE) file_content = Utils::readFile(e.filename); // TODO enhance the error messages helper( os, e.what(), + colorize, e.filename, file_content, escaped_symbol, diff --git a/src/arkreactor/TypeChecker.cpp b/src/arkreactor/TypeChecker.cpp index fc7ad89d4..8a6f8a412 100644 --- a/src/arkreactor/TypeChecker.cpp +++ b/src/arkreactor/TypeChecker.cpp @@ -2,7 +2,8 @@ #include #include -#include +#include +#include #include @@ -29,8 +30,15 @@ namespace Ark::types auto displayArg = [](const Typedef& td, bool correct) { const std::string arg_str = typeListToString(td.types); - std::cout << " -> " << (td.variadic ? "variadic " : "") - << (correct ? termcolor::green : termcolor::magenta) << td.name << termcolor::reset << " (" << arg_str << ") "; + fmt::print( + " -> {}{} ({}) ", + td.variadic ? "variadic " : "", + fmt::styled( + td.name, + correct + ? fmt::fg(fmt::color::green) + : fmt::fg(fmt::color::magenta)), + arg_str); }; for (std::size_t i = 0, end = contract.arguments.size(); i < end; ++i) @@ -50,8 +58,7 @@ namespace Ark::types if (bad_type) { displayArg(td, false); - std::cout << termcolor::red << bad_type << termcolor::reset - << " argument" << (bad_type > 1 ? "s" : "") << " do not match"; + fmt::print("{} argument{} do not match", fmt::styled(bad_type, fmt::fg(fmt::color::red)), bad_type > 1 ? "s" : ""); } else displayArg(td, true); @@ -62,24 +69,24 @@ namespace Ark::types if (i < args.size() && td.types[0] != ValueType::Any && std::ranges::find(td.types, args[i].valueType()) == td.types.end()) { displayArg(td, false); - std::cout << "was of type " << termcolor::red << types_to_str[static_cast(args[i].valueType())]; + fmt::print("was of type {}", fmt::styled(types_to_str[static_cast(args[i].valueType())], fmt::fg(fmt::color::red))); } // non-provided argument else if (i >= args.size()) { displayArg(td, false); - std::cout << termcolor::red << "was not provided"; + fmt::print(fmt::fg(fmt::color::red), "was not provided"); } else displayArg(td, true); } - std::cout << termcolor::reset << "\n"; + fmt::print("\n"); } } [[noreturn]] void generateError(const std::string_view& funcname, const std::vector& contracts, const std::vector& args) { - std::cout << "Function " << termcolor::blue << funcname << termcolor::reset << " expected "; + fmt::print("Function {} expected ", fmt::styled(funcname, fmt::fg(fmt::color::blue))); std::vector sanitizedArgs; std::ranges::copy_if(args, std::back_inserter(sanitizedArgs), [](const Value& value) -> bool { @@ -100,28 +107,28 @@ namespace Ark::types if (min_argc != max_argc) { - std::cout << "between " - << termcolor::yellow << min_argc << termcolor::reset - << " argument" << (min_argc > 1 ? "s" : "") << " and " - << termcolor::yellow << max_argc << termcolor::reset - << " argument" << (max_argc > 1 ? "s" : ""); + fmt::print( + "between {} argument{} and {} argument{}", + fmt::styled(min_argc, fmt::fg(fmt::color::yellow)), + min_argc > 1 ? "s" : "", + fmt::styled(max_argc, fmt::fg(fmt::color::yellow)), + max_argc > 1 ? "s" : ""); if (sanitizedArgs.size() < min_argc || sanitizedArgs.size() > max_argc) correct_argcount = false; } else { - std::cout << termcolor::yellow << min_argc << termcolor::reset - << " argument" << (min_argc > 1 ? "s" : ""); + fmt::print("{} argument{}", fmt::styled(min_argc, fmt::fg(fmt::color::yellow)), min_argc > 1 ? "s" : ""); if (sanitizedArgs.size() != min_argc) correct_argcount = false; } if (!correct_argcount) - std::cout << " but got " << termcolor::red << sanitizedArgs.size(); + fmt::print(" but got {}", fmt::styled(sanitizedArgs.size(), fmt::fg(fmt::color::red))); - std::cout << termcolor::reset << "\n"; + fmt::print("\n"); displayContract(contracts[0], sanitizedArgs); for (std::size_t i = 1, end = contracts.size(); i < end; ++i) diff --git a/src/arkreactor/VM/State.cpp b/src/arkreactor/VM/State.cpp index a37e08168..c4674dbb8 100644 --- a/src/arkreactor/VM/State.cpp +++ b/src/arkreactor/VM/State.cpp @@ -11,8 +11,8 @@ #include #include -#include #include +#include namespace Ark { @@ -46,7 +46,7 @@ namespace Ark } catch (const std::exception& e) // FIXME I don't like this shit { - std::cout << e.what() << std::endl; + fmt::println("{}", e.what()); return false; } } @@ -73,8 +73,7 @@ namespace Ark { if (!Utils::fileExists(file)) { - std::cerr << termcolor::red << "Can not find file '" << file << "'\n" - << termcolor::reset; + fmt::print(fmt::fg(fmt::color::red), "Can not find file '{}'\n", file); return false; } m_filename = file; diff --git a/src/arkreactor/VM/VM.cpp b/src/arkreactor/VM/VM.cpp index 9b7ae6b08..9f187ee01 100644 --- a/src/arkreactor/VM/VM.cpp +++ b/src/arkreactor/VM/VM.cpp @@ -3,10 +3,10 @@ #include #include #include - -#include #include -#include +#include +#include + #include #include #include @@ -1067,7 +1067,7 @@ namespace Ark } catch (const std::exception& e) { - std::cout << e.what() << "\n"; + fmt::println("{}", e.what()); backtrace(context); #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION // don't report a "failed" exit code so that the fuzzers can more accurately triage crashes @@ -1078,7 +1078,7 @@ namespace Ark } catch (...) { - std::cout << "Unknown error\n"; + fmt::println("Unknown error"); backtrace(context); m_exit_code = 1; @@ -1091,9 +1091,9 @@ namespace Ark auto end_time = std::chrono::system_clock::now(); auto d = std::chrono::duration_cast(end_time - start_time); - std::cout << "\nInstructions executed: " << instructions_executed << "\n" - << "Time spent: " << d.count() << " us\n" - << (static_cast(instructions_executed) / d.count()) << " MIPS\n"; + fmt::println("\nInstructions executed: {}", instructions_executed); + fmt::println("Time spent: {} us", d.count()); + fmt::println("{} MIPS", static_cast(instructions_executed) / d.count()); #endif return m_exit_code; @@ -1127,7 +1127,7 @@ namespace Ark while (context.fc != 0) { - std::cerr << "[" << termcolor::cyan << context.fc << termcolor::reset << "] "; + fmt::print("[{}] ", fmt::styled(context.fc, fmt::fg(fmt::color::cyan))); if (context.pp != 0) { const uint16_t id = findNearestVariableIdWithValue( @@ -1135,9 +1135,9 @@ namespace Ark context); if (id < m_state.m_symbols.size()) - std::cerr << "In function `" << termcolor::green << m_state.m_symbols[id] << termcolor::reset << "'\n"; + fmt::println("In function `{}'", fmt::styled(m_state.m_symbols[id], fmt::fg(fmt::color::green))); else // should never happen - std::cerr << "In function `" << termcolor::yellow << "???" << termcolor::reset << "'\n"; + fmt::println("In function `{}'", fmt::styled("???", fmt::fg(fmt::color::gold))); Value* ip; do @@ -1151,24 +1151,25 @@ namespace Ark } else { - std::cout << "In global scope\n"; + fmt::println("In global scope"); break; } if (original_frame_count - context.fc > 7) { - std::cout << "...\n"; + fmt::println("..."); break; } } // display variables values in the current scope - std::cout << "\nCurrent scope variables values:\n"; + fmt::println("\nCurrent scope variables values:"); for (std::size_t i = 0, size = old_scope.size(); i < size; ++i) { - std::cerr << termcolor::cyan << m_state.m_symbols[old_scope.m_data[i].first] << termcolor::reset - << " = " << old_scope.m_data[i].second.toString(*this); - std::cerr << "\n"; + fmt::println( + "{} = {}", + fmt::styled(m_state.m_symbols[old_scope.m_data[i].first], fmt::fg(fmt::color::cyan)), + old_scope.m_data[i].second.toString(*this)); } while (context.fc != 1) @@ -1182,8 +1183,7 @@ namespace Ark pop(context); } - std::cerr << termcolor::reset - << "At IP: " << (saved_ip / 4) // dividing by 4 because the instructions are actually on 4 bytes + std::cerr << "At IP: " << (saved_ip / 4) // dividing by 4 because the instructions are actually on 4 bytes << ", PP: " << saved_pp << ", SP: " << saved_sp << "\n"; diff --git a/src/arkscript/Formatter.cpp b/src/arkscript/Formatter.cpp index 5a4467b14..cf46be42e 100644 --- a/src/arkscript/Formatter.cpp +++ b/src/arkscript/Formatter.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -82,12 +82,11 @@ void Formatter::warnIfCommentsWereRemoved(const std::string& original_code, cons { if (std::ranges::count(original_code, '#') != std::ranges::count(m_output, '#')) { - std::cout << termcolor::yellow << "Warning" << termcolor::reset << ": one or more comments from the original source code seem to have been removed by mistake while formatting "; - if (filename != ARK_NO_NAME_FILE) - std::cout << "'" << filename << "'" << std::endl; - else - std::cout << "file" << std::endl; - std::cout << "Please fill an issue on GitHub: https://github.com/ArkScript-lang/Ark" << std::endl; + fmt::println( + "{}: one or more comments from the original source code seem to have been removed by mistake while formatting {}", + fmt::styled("Warning", fmt::fg(fmt::color::dark_orange)), + filename != ARK_NO_NAME_FILE ? filename : "file"); + fmt::println("Please fill an issue on GitHub: https://github.com/ArkScript-lang/Ark"); } } diff --git a/src/arkscript/REPL/Repl.cpp b/src/arkscript/REPL/Repl.cpp index 8c0d0d2ed..bf85613bb 100644 --- a/src/arkscript/REPL/Repl.cpp +++ b/src/arkscript/REPL/Repl.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -90,7 +89,7 @@ namespace Ark m_state.reset(); } else - std::cout << "\nCouldn't run code\n"; + fmt::println("\nCouldn't run code"); } } @@ -153,19 +152,19 @@ namespace Ark // specific commands handling if (line == "quit" || buf == nullptr) { - std::cout << "\nExiting REPL\n"; + fmt::println("\nExiting REPL"); m_running = false; return std::nullopt; } if (line == "help") { - std::cout << "Available commands:\n"; - std::cout << " help -- display this message\n"; - std::cout << " quit -- quit the REPL\n"; - std::cout << " save -- save the history to disk\n"; - std::cout << " history -- print saved code\n"; - std::cout << " reset -- reset the VM state\n"; + fmt::println("Available commands:"); + fmt::println(" help -- display this message"); + fmt::println(" quit -- quit the REPL"); + fmt::println(" save -- save the history to disk"); + fmt::println(" history -- print saved code"); + fmt::println(" reset -- reset the VM state"); return std::nullopt; } @@ -174,15 +173,12 @@ namespace Ark std::ofstream history_file("arkscript_repl_history.ark"); m_repl.history_save(history_file); - fmt::print("Saved {} lines of history to arkscript_repl_history.ark\n", m_line_count); - + fmt::println("Saved {} lines of history to arkscript_repl_history.ark", m_line_count); return std::nullopt; } if (line == "history") { - std::cout << "\n" - << m_code << "\n"; - + fmt::println("\n{}", m_code); return std::nullopt; } if (line == "reset") diff --git a/src/arkscript/main.cpp b/src/arkscript/main.cpp index 91019cbb8..2fba316a0 100644 --- a/src/arkscript/main.cpp +++ b/src/arkscript/main.cpp @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include @@ -71,7 +71,8 @@ int main(int argc, char** argv) option("-foptimizer").call([&] { passes |= Ark::FeatureASTOptimizer; }) | option("-fno-optimizer").call([&] { passes &= ~Ark::FeatureASTOptimizer; }) ).doc("Toggle on and off the optimizer pass"); - auto compiler_passes_flag = (import_solver_pass_flag, macro_proc_pass_flag, optimizer_pass_flag); + // cppcheck-suppress constStatement + const auto compiler_passes_flag = (import_solver_pass_flag, macro_proc_pass_flag, optimizer_pass_flag); auto cli = ( option("-h", "--help").set(selected, mode::help).doc("Display this message") @@ -169,7 +170,7 @@ int main(int argc, char** argv) else if (Utils::fileExists("./lib")) lib_paths.emplace_back("lib"); else - std::cerr << termcolor::yellow << "Warning" << termcolor::reset << " Couldn't read ARKSCRIPT_PATH environment variable" << std::endl; + fmt::println("{}: Couldn't read ARKSCRIPT_PATH environment variable", fmt::styled("Warning", fmt::fg(fmt::color::dark_orange))); } switch (selected) @@ -179,12 +180,12 @@ int main(int argc, char** argv) break; case mode::version: - std::cout << fmt::format("{}\n", ARK_FULL_VERSION); + fmt::println(ARK_FULL_VERSION); break; case mode::dev_info: { - std::cout << fmt::format( + fmt::println( "Have been compiled with {}\n\n" "sizeof(Ark::Value) = {}B\n" " sizeof(Value_t) = {}B\n" @@ -200,7 +201,7 @@ int main(int argc, char** argv) "\nMisc\n" " sizeof(vector) = {}B\n" " sizeof(char) = {}B\n" - "\nsizeof(Node) = {}B\n", + "\nsizeof(Node) = {}B", ARK_COMPILER, // value sizeof(Ark::Value), @@ -270,7 +271,7 @@ int main(int argc, char** argv) { JsonCompiler compiler(debug, lib_paths); compiler.feed(file); - std::cout << compiler.compile() << std::endl; + fmt::println("{}", compiler.compile()); break; } @@ -303,7 +304,7 @@ int main(int argc, char** argv) Formatter formatter(file, dry_run); formatter.run(); if (dry_run) - std::cout << formatter.output() << std::endl; + fmt::println("{}", formatter.output()); } } } diff --git a/tests/errors/run-tests b/tests/errors/run-tests index 1b7c41f74..66c443208 100755 --- a/tests/errors/run-tests +++ b/tests/errors/run-tests @@ -23,7 +23,7 @@ passed=0 failed=0 for f in ./**/*.ark; do - output=$($ark "$f" --lib ../../lib 2>&1) + output=$($ark "$f" --lib ../../lib 2>&1 | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]+;?)*)?[mGK]//g") expected=$(cat "${f%.*}.expected") case "$output" in diff --git a/tests/unittests/ParserSuite.cpp b/tests/unittests/ParserSuite.cpp index 1e2f764c3..bcb031b01 100644 --- a/tests/unittests/ParserSuite.cpp +++ b/tests/unittests/ParserSuite.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -82,8 +81,7 @@ ut::suite<"Parser"> parser_suite = [] { catch (const Ark::CodeError& e) { std::stringstream ss; - ss << termcolor::nocolorize; - Ark::Diagnostics::generate(e, "", ss); + Ark::Diagnostics::generate(e, ss, /* colorize= */ false); should("output the same error message (" + data.stem + ")") = [&] { std::string tested = ss.str();