From 22d75ed856620601788b2567c6b28e4858b18681 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 21 Jan 2021 11:36:58 +0100 Subject: [PATCH] Improved logging and aborting from pattern language builtin functions --- include/views/view_pattern.hpp | 2 +- .../include/hex/api/content_registry.hpp | 5 +- .../libimhex/include/hex/lang/evaluator.hpp | 56 ++++++----- .../libimhex/source/api/content_registry.cpp | 2 +- .../source/lang/builtin_functions.cpp | 46 ++++----- plugins/libimhex/source/lang/evaluator.cpp | 98 +++++++++---------- source/views/view_pattern.cpp | 12 +-- 7 files changed, 114 insertions(+), 107 deletions(-) diff --git a/include/views/view_pattern.hpp b/include/views/view_pattern.hpp index 59924cf9b..a8f23a925 100644 --- a/include/views/view_pattern.hpp +++ b/include/views/view_pattern.hpp @@ -28,7 +28,7 @@ namespace hex { std::filesystem::path m_possiblePatternFile; TextEditor m_textEditor; - std::vector> m_console; + std::vector> m_console; imgui_addons::ImGuiFileBrowser m_fileBrowser; void loadPatternFile(std::string path); diff --git a/plugins/libimhex/include/hex/api/content_registry.hpp b/plugins/libimhex/include/hex/api/content_registry.hpp index 4aa76588d..ee48f8262 100644 --- a/plugins/libimhex/include/hex/api/content_registry.hpp +++ b/plugins/libimhex/include/hex/api/content_registry.hpp @@ -16,6 +16,7 @@ namespace hex { class View; namespace lang { class ASTNode; } + namespace lang { class LogConsole; } /* The Content Registry is the heart of all features in ImHex that are in some way extendable by Plugins. @@ -82,10 +83,10 @@ namespace hex { struct Function { u32 parameterCount; - std::function)> func; + std::function)> func; }; - static void add(std::string_view name, u32 parameterCount, const std::function)> &func); + static void add(std::string_view name, u32 parameterCount, const std::function)> &func); static std::map& getEntries(); }; diff --git a/plugins/libimhex/include/hex/lang/evaluator.hpp b/plugins/libimhex/include/hex/lang/evaluator.hpp index be800b1da..9336ba0ef 100644 --- a/plugins/libimhex/include/hex/lang/evaluator.hpp +++ b/plugins/libimhex/include/hex/lang/evaluator.hpp @@ -14,19 +14,44 @@ namespace hex::lang { - class Evaluator { + class LogConsole { public: - enum ConsoleLogLevel { + enum Level { Debug, Info, Warning, Error }; + const auto& getLog() { return this->m_consoleLog; } + + using EvaluateError = std::string; + + void log(Level level, std::string_view message) { + switch (level) { + default: + case Level::Debug: this->m_consoleLog.emplace_back(level, "[-] " + std::string(message)); break; + case Level::Info: this->m_consoleLog.emplace_back(level, "[i] " + std::string(message)); break; + case Level::Warning: this->m_consoleLog.emplace_back(level, "[*] " + std::string(message)); break; + case Level::Error: this->m_consoleLog.emplace_back(level, "[!] " + std::string(message)); break; + } + } + + [[noreturn]] static void abortEvaluation(std::string_view message) { + throw EvaluateError(message); + } + + private: + std::vector> m_consoleLog; + }; + + class Evaluator { + public: Evaluator(prv::Provider* &provider, std::endian defaultDataEndian); std::optional> evaluate(const std::vector& ast); - const auto& getConsoleLog() { return this->m_consoleLog; } + + auto& getConsole() { return this->m_console; } private: std::map m_types; @@ -36,26 +61,7 @@ namespace hex::lang { std::vector m_endianStack; std::vector m_globalMembers; std::vector*> m_currMembers; - - std::vector> m_consoleLog; - - using EvaluateError = std::string; - - void emmitDebugInfo(std::string_view message) { - this->m_consoleLog.emplace_back(ConsoleLogLevel::Debug, "[-] " + std::string(message)); - } - - void emmitInfo(std::string_view message) { - this->m_consoleLog.emplace_back(ConsoleLogLevel::Info, "[i] " + std::string(message)); - } - - void emmitWaring(std::string_view message) { - this->m_consoleLog.emplace_back(ConsoleLogLevel::Warning, "[*] " + std::string(message)); - } - - [[noreturn]] static void throwEvaluateError(std::string_view message) { - throw EvaluateError("[!] " + std::string(message)); - } + LogConsole m_console; [[nodiscard]] std::endian getCurrentEndian() const { return this->m_endianStack.back(); @@ -86,12 +92,12 @@ namespace hex::lang { if (auto evaluatedParam = dynamic_cast(param); evaluatedParam != nullptr) return evaluatedParam; else - throwEvaluateError("function got wrong type of parameter"); + this->m_console.abortEvaluation("function got wrong type of parameter"); } void registerBuiltinFunctions(); - #define BUILTIN_FUNCTION(name) ASTNodeIntegerLiteral* TOKEN_CONCAT(builtin_, name)(std::vector params) + #define BUILTIN_FUNCTION(name) ASTNodeIntegerLiteral* TOKEN_CONCAT(builtin_, name)(LogConsole &console, std::vector params) BUILTIN_FUNCTION(findSequence); BUILTIN_FUNCTION(readUnsigned); diff --git a/plugins/libimhex/source/api/content_registry.cpp b/plugins/libimhex/source/api/content_registry.cpp index 0834bf4d4..a62d5bf4a 100644 --- a/plugins/libimhex/source/api/content_registry.cpp +++ b/plugins/libimhex/source/api/content_registry.cpp @@ -76,7 +76,7 @@ namespace hex { /* Pattern Language Functions */ - void ContentRegistry::PatternLanguageFunctions::add(std::string_view name, u32 parameterCount, const std::function)> &func) { + void ContentRegistry::PatternLanguageFunctions::add(std::string_view name, u32 parameterCount, const std::function)> &func) { getEntries()[name.data()] = Function{ parameterCount, func }; } diff --git a/plugins/libimhex/source/lang/builtin_functions.cpp b/plugins/libimhex/source/lang/builtin_functions.cpp index 5775702f6..e7e7169f1 100644 --- a/plugins/libimhex/source/lang/builtin_functions.cpp +++ b/plugins/libimhex/source/lang/builtin_functions.cpp @@ -7,15 +7,15 @@ namespace hex::lang { void Evaluator::registerBuiltinFunctions() { /* findSequence */ - ContentRegistry::PatternLanguageFunctions::add("findSequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [this](auto params) { + ContentRegistry::PatternLanguageFunctions::add("findSequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [this](auto &console, auto params) { auto& occurrenceIndex = asType(params[0])->getValue(); std::vector sequence; for (u32 i = 1; i < params.size(); i++) { - sequence.push_back(std::visit([](auto &&value) -> u8 { + sequence.push_back(std::visit([&](auto &&value) -> u8 { if (value <= 0xFF) return value; else - throwEvaluateError("sequence bytes need to fit into 1 byte"); + console.abortEvaluation("sequence bytes need to fit into 1 byte"); }, asType(params[i])->getValue())); } @@ -34,20 +34,20 @@ namespace hex::lang { } } - throwEvaluateError("failed to find sequence"); + console.abortEvaluation("failed to find sequence"); }); /* assert */ - ContentRegistry::PatternLanguageFunctions::add("readUnsigned", 2, [this](auto params) { + ContentRegistry::PatternLanguageFunctions::add("readUnsigned", 2, [this](auto &console, auto params) { auto address = asType(params[0])->getValue(); auto size = asType(params[1])->getValue(); if (LITERAL_COMPARE(address, address >= this->m_provider->getActualSize())) - throwEvaluateError("address out of range"); + console.abortEvaluation("address out of range"); - return std::visit([this](auto &&address, auto &&size) { + return std::visit([&, this](auto &&address, auto &&size) { if (size <= 0 || size > 16) - throwEvaluateError("invalid read size"); + console.abortEvaluation("invalid read size"); u8 value[(u8)size]; this->m_provider->read(address, value, size); @@ -58,21 +58,21 @@ namespace hex::lang { case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, this->getCurrentEndian()) }); case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, this->getCurrentEndian()) }); case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, this->getCurrentEndian()) }); - default: throwEvaluateError("invalid read size"); + default: console.abortEvaluation("invalid read size"); } }, address, size); }); - ContentRegistry::PatternLanguageFunctions::add("readSigned", 2, [this](auto params) { + ContentRegistry::PatternLanguageFunctions::add("readSigned", 2, [this](auto &console, auto params) { auto address = asType(params[0])->getValue(); auto size = asType(params[1])->getValue(); if (LITERAL_COMPARE(address, address >= this->m_provider->getActualSize())) - throwEvaluateError("address out of range"); + console.abortEvaluation("address out of range"); - return std::visit([this](auto &&address, auto &&size) { + return std::visit([&, this](auto &&address, auto &&size) { if (size <= 0 || size > 16) - throwEvaluateError("invalid read size"); + console.abortEvaluation("invalid read size"); u8 value[(u8)size]; this->m_provider->read(address, value, size); @@ -83,32 +83,32 @@ namespace hex::lang { case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, this->getCurrentEndian()) }); case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, this->getCurrentEndian()) }); case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, this->getCurrentEndian()) }); - default: throwEvaluateError("invalid read size"); + default: console.abortEvaluation("invalid read size"); } }, address, size); }); - ContentRegistry::PatternLanguageFunctions::add("assert", 2, [this](auto params) { + ContentRegistry::PatternLanguageFunctions::add("assert", 2, [this](auto &console, auto params) { auto condition = asType(params[0])->getValue(); auto message = asType(params[1])->getString(); if (LITERAL_COMPARE(condition, condition == 0)) - throwEvaluateError(hex::format("assert failed \"%s\"", message.data())); + console.abortEvaluation(hex::format("assert failed \"%s\"", message.data())); return nullptr; }); - ContentRegistry::PatternLanguageFunctions::add("warnAssert", 2, [this](auto params) { + ContentRegistry::PatternLanguageFunctions::add("warnAssert", 2, [this](auto console, auto params) { auto condition = asType(params[0])->getValue(); auto message = asType(params[1])->getString(); if (LITERAL_COMPARE(condition, condition == 0)) - this->emmitWaring(hex::format("assert failed \"%s\"", message.data())); + console.log(LogConsole::Level::Warning, hex::format("assert failed \"%s\"", message.data())); return nullptr; }); - ContentRegistry::PatternLanguageFunctions::add("print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [this](auto params) { + ContentRegistry::PatternLanguageFunctions::add("print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](auto &console, auto params) { std::string message; for (auto& param : params) { if (auto integerLiteral = dynamic_cast(param); integerLiteral != nullptr) { @@ -134,12 +134,12 @@ namespace hex::lang { message += stringLiteral->getString(); } - this->emmitInfo(message); + console.log(LogConsole::Level::Info, message); return nullptr; }); - ContentRegistry::PatternLanguageFunctions::add("addressof", 1, [this](auto params) -> ASTNode* { + ContentRegistry::PatternLanguageFunctions::add("addressof", 1, [this](auto &console, auto params) -> ASTNode* { auto name = asType(params[0])->getString(); std::vector path = splitString(name, "."); @@ -148,7 +148,7 @@ namespace hex::lang { return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, pattern->getOffset() }); }); - ContentRegistry::PatternLanguageFunctions::add("sizeof", 1, [this](auto params) -> ASTNode* { + ContentRegistry::PatternLanguageFunctions::add("sizeof", 1, [this](auto &console, auto params) -> ASTNode* { auto name = asType(params[0])->getString(); std::vector path = splitString(name, "."); @@ -157,7 +157,7 @@ namespace hex::lang { return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, pattern->getSize() }); }); - ContentRegistry::PatternLanguageFunctions::add("nextAfter", 1, [this](auto params) -> ASTNode* { + ContentRegistry::PatternLanguageFunctions::add("nextAfter", 1, [this](auto &console, auto params) -> ASTNode* { auto name = asType(params[0])->getString(); std::vector path = splitString(name, "."); diff --git a/plugins/libimhex/source/lang/evaluator.cpp b/plugins/libimhex/source/lang/evaluator.cpp index 55e35d9fd..fbc73234e 100644 --- a/plugins/libimhex/source/lang/evaluator.cpp +++ b/plugins/libimhex/source/lang/evaluator.cpp @@ -33,7 +33,7 @@ namespace hex::lang { } } - throwEvaluateError("failed to find identifier"); + this->getConsole().abortEvaluation("failed to find identifier"); } PatternData* Evaluator::patternFromName(const std::vector &path) { @@ -58,7 +58,7 @@ namespace hex::lang { continue; } else if (currPattern != nullptr) - throwEvaluateError("tried to access member of a non-struct/union type"); + this->getConsole().abortEvaluation("tried to access member of a non-struct/union type"); auto candidate = std::find_if(currMembers.begin(), currMembers.end(), [&](auto member) { return member->getVariableName() == identifier; @@ -67,7 +67,7 @@ namespace hex::lang { if (candidate != currMembers.end()) currPattern = *candidate; else - throwEvaluateError(hex::format("could not find identifier '%s'", identifier.c_str())); + this->getConsole().abortEvaluation(hex::format("could not find identifier '%s'", identifier.c_str())); } if (auto pointerPattern = dynamic_cast(currPattern); pointerPattern != nullptr) @@ -78,7 +78,7 @@ namespace hex::lang { ASTNodeIntegerLiteral* Evaluator::evaluateRValue(ASTNodeRValue *node) { if (this->m_currMembers.empty() && this->m_globalMembers.empty()) - throwEvaluateError("no variables available"); + this->getConsole().abortEvaluation("no variables available"); if (node->getPath().size() == 1 && node->getPath()[0] == "$") return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, this->m_currOffset }); @@ -95,7 +95,7 @@ namespace hex::lang { case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, unsignedPattern->getEndian()) }); case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, unsignedPattern->getEndian()) }); case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, unsignedPattern->getEndian()) }); - default: throwEvaluateError("invalid rvalue size"); + default: this->getConsole().abortEvaluation("invalid rvalue size"); } } else if (auto signedPattern = dynamic_cast(currPattern); signedPattern != nullptr) { u8 value[unsignedPattern->getSize()]; @@ -107,7 +107,7 @@ namespace hex::lang { case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, signedPattern->getEndian()) }); case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, signedPattern->getEndian()) }); case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, signedPattern->getEndian()) }); - default: throwEvaluateError("invalid rvalue size"); + default: this->getConsole().abortEvaluation("invalid rvalue size"); } } else if (auto enumPattern = dynamic_cast(currPattern); enumPattern != nullptr) { u8 value[enumPattern->getSize()]; @@ -119,10 +119,10 @@ namespace hex::lang { case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, enumPattern->getEndian()) }); case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, enumPattern->getEndian()) }); case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, enumPattern->getEndian()) }); - default: throwEvaluateError("invalid rvalue size"); + default: this->getConsole().abortEvaluation("invalid rvalue size"); } } else - throwEvaluateError("tried to use non-integer value in numeric expression"); + this->getConsole().abortEvaluation("tried to use non-integer value in numeric expression"); } ASTNode* Evaluator::evaluateFunctionCall(ASTNodeFunctionCall *node) { @@ -140,7 +140,7 @@ namespace hex::lang { } if (!ContentRegistry::PatternLanguageFunctions::getEntries().contains(node->getFunctionName().data())) - throwEvaluateError(hex::format("no function named '%s' found", node->getFunctionName().data())); + this->getConsole().abortEvaluation(hex::format("no function named '%s' found", node->getFunctionName().data())); auto &function = ContentRegistry::PatternLanguageFunctions::getEntries()[node->getFunctionName().data()]; @@ -149,15 +149,15 @@ namespace hex::lang { } else if (function.parameterCount & ContentRegistry::PatternLanguageFunctions::LessParametersThan) { if (evaluatedParams.size() >= (function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::LessParametersThan)) - throwEvaluateError(hex::format("too many parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::LessParametersThan)); + this->getConsole().abortEvaluation(hex::format("too many parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::LessParametersThan)); } else if (function.parameterCount & ContentRegistry::PatternLanguageFunctions::MoreParametersThan) { if (evaluatedParams.size() <= (function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::MoreParametersThan)) - throwEvaluateError(hex::format("too few parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::MoreParametersThan)); + this->getConsole().abortEvaluation(hex::format("too few parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::MoreParametersThan)); } else if (function.parameterCount != evaluatedParams.size()) { - throwEvaluateError(hex::format("invalid number of parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount)); + this->getConsole().abortEvaluation(hex::format("invalid number of parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount)); } - return function.func(evaluatedParams); + return function.func(this->getConsole(), evaluatedParams); } #define FLOAT_BIT_OPERATION(name) \ @@ -274,12 +274,12 @@ namespace hex::lang { case Token::Operator::BoolNot: return new ASTNodeIntegerLiteral({ newType, !rightValue }); default: - throwEvaluateError("invalid operator used in mathematical expression"); + this->getConsole().abortEvaluation("invalid operator used in mathematical expression"); } }, left->getValue(), right->getValue()); } catch (std::runtime_error &e) { - throwEvaluateError("bitwise operations on floating point numbers are forbidden"); + this->getConsole().abortEvaluation("bitwise operations on floating point numbers are forbidden"); } } @@ -298,14 +298,14 @@ namespace hex::lang { auto returnValue = evaluateFunctionCall(exprFunctionCall); if (returnValue == nullptr) - throwEvaluateError("function returning void used in expression"); + this->getConsole().abortEvaluation("function returning void used in expression"); else if (auto integerNode = dynamic_cast(returnValue); integerNode != nullptr) return integerNode; else - throwEvaluateError("function not returning a numeric value used in expression"); + this->getConsole().abortEvaluation("function not returning a numeric value used in expression"); } else - throwEvaluateError("invalid operand"); + this->getConsole().abortEvaluation("invalid operand"); } ASTNodeIntegerLiteral* Evaluator::evaluateTernaryExpression(ASTNodeTernaryExpression *node) { @@ -320,7 +320,7 @@ namespace hex::lang { return this->evaluateOperand(node->getThirdOperand()); } default: - throwEvaluateError("invalid operator used in ternary expression"); + this->getConsole().abortEvaluation("invalid operator used in ternary expression"); } } @@ -348,7 +348,7 @@ namespace hex::lang { else if (Token::isFloatingPoint(type)) pattern = new PatternDataFloat(this->m_currOffset, typeSize); else - throwEvaluateError("invalid builtin type"); + this->getConsole().abortEvaluation("invalid builtin type"); this->m_currOffset += typeSize; @@ -383,7 +383,7 @@ namespace hex::lang { delete condition; } else - throwEvaluateError("invalid struct member"); + this->getConsole().abortEvaluation("invalid struct member"); if (!increaseOffset) this->m_currOffset = startOffset; @@ -431,7 +431,7 @@ namespace hex::lang { for (auto &[name, value] : node->getEntries()) { auto expression = dynamic_cast(value); if (expression == nullptr) - throwEvaluateError("invalid expression in enum value"); + this->getConsole().abortEvaluation("invalid expression in enum value"); auto valueNode = evaluateMathematicalExpression(expression); SCOPE_EXIT( delete valueNode; ); @@ -441,13 +441,13 @@ namespace hex::lang { auto underlyingType = dynamic_cast(node->getUnderlyingType()); if (underlyingType == nullptr) - throwEvaluateError("enum underlying type was not ASTNodeTypeDecl. This is a bug"); + this->getConsole().abortEvaluation("enum underlying type was not ASTNodeTypeDecl. This is a bug"); size_t size; if (auto builtinType = dynamic_cast(underlyingType->getType()); builtinType != nullptr) size = Token::getTypeSize(builtinType->getType()); else - throwEvaluateError("invalid enum underlying type"); + this->getConsole().abortEvaluation("invalid enum underlying type"); this->m_currOffset += size; @@ -462,19 +462,19 @@ namespace hex::lang { for (auto &[name, value] : node->getEntries()) { auto expression = dynamic_cast(value); if (expression == nullptr) - throwEvaluateError("invalid expression in bitfield field size"); + this->getConsole().abortEvaluation("invalid expression in bitfield field size"); auto valueNode = evaluateMathematicalExpression(expression); SCOPE_EXIT( delete valueNode; ); - auto fieldBits = std::visit([node, type = valueNode->getType()] (auto &&value) { + auto fieldBits = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) - throwEvaluateError("bitfield entry size must be an integer value"); + this->getConsole().abortEvaluation("bitfield entry size must be an integer value"); return static_cast(value); }, valueNode->getValue()); if (fieldBits > 64 || fieldBits <= 0) - throwEvaluateError("bitfield entry must occupy between 1 and 64 bits"); + this->getConsole().abortEvaluation("bitfield entry must occupy between 1 and 64 bits"); bits += fieldBits; @@ -507,7 +507,7 @@ namespace hex::lang { else if (auto bitfieldNode = dynamic_cast(type); bitfieldNode != nullptr) pattern = this->evaluateBitfield(bitfieldNode); else - throwEvaluateError("type could not be evaluated"); + this->getConsole().abortEvaluation("type could not be evaluated"); if (!node->getName().empty()) pattern->setTypeName(node->getName().data()); @@ -525,14 +525,14 @@ namespace hex::lang { auto valueNode = evaluateMathematicalExpression(offset); SCOPE_EXIT( delete valueNode; ); - this->m_currOffset = std::visit([node, type = valueNode->getType()] (auto &&value) { + this->m_currOffset = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) - throwEvaluateError("placement offset must be an integer value"); + this->getConsole().abortEvaluation("placement offset must be an integer value"); return static_cast(value); }, valueNode->getValue()); } if (this->m_currOffset >= this->m_provider->getActualSize()) - throwEvaluateError("variable placed out of range"); + this->getConsole().abortEvaluation("variable placed out of range"); PatternData *pattern; if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) @@ -540,7 +540,7 @@ namespace hex::lang { else if (auto builtinTypeDecl = dynamic_cast(node->getType()); builtinTypeDecl != nullptr) pattern = this->evaluateBuiltinType(builtinTypeDecl); else - throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!"); + this->getConsole().abortEvaluation("ASTNodeVariableDecl had an invalid type. This is a bug!"); pattern->setVariableName(node->getName().data()); @@ -553,9 +553,9 @@ namespace hex::lang { auto valueNode = evaluateMathematicalExpression(offset); SCOPE_EXIT( delete valueNode; ); - this->m_currOffset = std::visit([node, type = valueNode->getType()] (auto &&value) { + this->m_currOffset = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) - throwEvaluateError("placement offset must be an integer value"); + this->getConsole().abortEvaluation("placement offset must be an integer value"); return static_cast(value); }, valueNode->getValue()); } @@ -569,13 +569,13 @@ namespace hex::lang { if (auto sizeNumericExpression = dynamic_cast(node->getSize()); sizeNumericExpression != nullptr) valueNode = evaluateMathematicalExpression(sizeNumericExpression); else - throwEvaluateError("array size not a numeric expression"); + this->getConsole().abortEvaluation("array size not a numeric expression"); SCOPE_EXIT( delete valueNode; ); - arraySize = std::visit([node, type = valueNode->getType()] (auto &&value) { + arraySize = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) - throwEvaluateError("array size must be an integer value"); + this->getConsole().abortEvaluation("array size must be an integer value"); return static_cast(value); }, valueNode->getValue()); @@ -608,7 +608,7 @@ namespace hex::lang { entry = this->evaluateBuiltinType(builtinTypeDecl); } else - throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!"); + this->getConsole().abortEvaluation("ASTNodeVariableDecl had an invalid type. This is a bug!"); entry->setVariableName(hex::format("[%llu]", (u64)i)); entry->setEndian(this->getCurrentEndian()); @@ -620,7 +620,7 @@ namespace hex::lang { entries.push_back(entry); if (this->m_currOffset > this->m_provider->getActualSize()) - throwEvaluateError("array exceeds size of file"); + this->getConsole().abortEvaluation("array exceeds size of file"); } PatternData *pattern; @@ -631,7 +631,7 @@ namespace hex::lang { pattern = new PatternDataString(startOffset, (this->m_currOffset - startOffset), color.value_or(0)); else { if (node->getSize() == nullptr) - throwEvaluateError("no bounds provided for array"); + this->getConsole().abortEvaluation("no bounds provided for array"); pattern = new PatternDataArray(startOffset, (this->m_currOffset - startOffset), entries, color.value_or(0)); } @@ -646,9 +646,9 @@ namespace hex::lang { auto valueNode = evaluateMathematicalExpression(offset); SCOPE_EXIT( delete valueNode; ); - pointerOffset = std::visit([node, type = valueNode->getType()] (auto &&value) { + pointerOffset = std::visit([this, node, type = valueNode->getType()] (auto &&value) { if (Token::isFloatingPoint(type)) - throwEvaluateError("pointer offset must be an integer value"); + this->getConsole().abortEvaluation("pointer offset must be an integer value"); return static_cast(value); }, valueNode->getValue()); this->m_currOffset = pointerOffset; @@ -660,12 +660,12 @@ namespace hex::lang { auto underlyingType = dynamic_cast(node->getSizeType()); if (underlyingType == nullptr) - throwEvaluateError("underlying type is not ASTNodeTypeDecl. This is a bug"); + this->getConsole().abortEvaluation("underlying type is not ASTNodeTypeDecl. This is a bug"); if (auto builtinTypeNode = dynamic_cast(underlyingType->getType()); builtinTypeNode != nullptr) { sizeType = evaluateBuiltinType(builtinTypeNode); } else - throwEvaluateError("pointer size is not a builtin type"); + this->getConsole().abortEvaluation("pointer size is not a builtin type"); size_t pointerSize = sizeType->getSize(); @@ -677,7 +677,7 @@ namespace hex::lang { if (this->m_currOffset > this->m_provider->getActualSize()) - throwEvaluateError("pointer points past the end of the data"); + this->getConsole().abortEvaluation("pointer points past the end of the data"); PatternData *pointedAt; if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) @@ -685,7 +685,7 @@ namespace hex::lang { else if (auto builtinTypeDecl = dynamic_cast(node->getType()); builtinTypeDecl != nullptr) pointedAt = this->evaluateBuiltinType(builtinTypeDecl); else - throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!"); + this->getConsole().abortEvaluation("ASTNodeVariableDecl had an invalid type. This is a bug!"); this->m_currOffset = pointerOffset + pointerSize; @@ -718,8 +718,8 @@ namespace hex::lang { this->m_endianStack.clear(); } - } catch (EvaluateError &e) { - this->m_consoleLog.emplace_back(ConsoleLogLevel::Error, e); + } catch (LogConsole::EvaluateError &e) { + this->getConsole().log(LogConsole::Level::Error, e); this->m_endianStack.clear(); return { }; diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index ec5e87afb..15282ae49 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -237,16 +237,16 @@ namespace hex { if (ImGui::BeginChild("##console", consoleSize, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { for (auto &[level, message] : this->m_console) { switch (level) { - case lang::Evaluator::ConsoleLogLevel::Debug: + case lang::LogConsole::Level::Debug: ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Comment)]); break; - case lang::Evaluator::ConsoleLogLevel::Info: + case lang::LogConsole::Level::Info: ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Default)]); break; - case lang::Evaluator::ConsoleLogLevel::Warning: + case lang::LogConsole::Level::Warning: ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Preprocessor)]); break; - case lang::Evaluator::ConsoleLogLevel::Error: + case lang::LogConsole::Level::Error: ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::ErrorMarker)]); break; default: continue; @@ -383,12 +383,12 @@ namespace hex { hex::lang::Evaluator evaluator(provider, defaultDataEndianess); auto patternData = evaluator.evaluate(ast.value()); - this->m_console = evaluator.getConsoleLog(); + this->m_console = evaluator.getConsole().getLog(); if (!patternData.has_value()) return; this->m_patternData = patternData.value(); - this->postEvent(Events::PatternChanged); + View::postEvent(Events::PatternChanged); } } \ No newline at end of file