Improved logging and aborting from pattern language builtin functions

This commit is contained in:
WerWolv 2021-01-21 11:36:58 +01:00
parent a641f27b7e
commit 22d75ed856
7 changed files with 114 additions and 107 deletions

View file

@ -28,7 +28,7 @@ namespace hex {
std::filesystem::path m_possiblePatternFile;
TextEditor m_textEditor;
std::vector<std::pair<lang::Evaluator::ConsoleLogLevel, std::string>> m_console;
std::vector<std::pair<lang::LogConsole::Level, std::string>> m_console;
imgui_addons::ImGuiFileBrowser m_fileBrowser;
void loadPatternFile(std::string path);

View file

@ -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<hex::lang::ASTNode*(std::vector<hex::lang::ASTNode*>)> func;
std::function<hex::lang::ASTNode*(hex::lang::LogConsole&, std::vector<hex::lang::ASTNode*>)> func;
};
static void add(std::string_view name, u32 parameterCount, const std::function<hex::lang::ASTNode*(std::vector<hex::lang::ASTNode*>)> &func);
static void add(std::string_view name, u32 parameterCount, const std::function<hex::lang::ASTNode*(hex::lang::LogConsole&, std::vector<hex::lang::ASTNode*>)> &func);
static std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function>& getEntries();
};

View file

@ -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<std::pair<Level, std::string>> m_consoleLog;
};
class Evaluator {
public:
Evaluator(prv::Provider* &provider, std::endian defaultDataEndian);
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
const auto& getConsoleLog() { return this->m_consoleLog; }
auto& getConsole() { return this->m_console; }
private:
std::map<std::string, ASTNode*> m_types;
@ -36,26 +61,7 @@ namespace hex::lang {
std::vector<std::endian> m_endianStack;
std::vector<PatternData*> m_globalMembers;
std::vector<std::vector<PatternData*>*> m_currMembers;
std::vector<std::pair<ConsoleLogLevel, std::string>> 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<T*>(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<ASTNode*> params)
#define BUILTIN_FUNCTION(name) ASTNodeIntegerLiteral* TOKEN_CONCAT(builtin_, name)(LogConsole &console, std::vector<ASTNode*> params)
BUILTIN_FUNCTION(findSequence);
BUILTIN_FUNCTION(readUnsigned);

View file

@ -76,7 +76,7 @@ namespace hex {
/* Pattern Language Functions */
void ContentRegistry::PatternLanguageFunctions::add(std::string_view name, u32 parameterCount, const std::function<hex::lang::ASTNode*(std::vector<hex::lang::ASTNode*>)> &func) {
void ContentRegistry::PatternLanguageFunctions::add(std::string_view name, u32 parameterCount, const std::function<hex::lang::ASTNode*(hex::lang::LogConsole&, std::vector<hex::lang::ASTNode*>)> &func) {
getEntries()[name.data()] = Function{ parameterCount, func };
}

View file

@ -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<ASTNodeIntegerLiteral>(params[0])->getValue();
std::vector<u8> 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<ASTNodeIntegerLiteral>(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<ASTNodeIntegerLiteral>(params[0])->getValue();
auto size = asType<ASTNodeIntegerLiteral>(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<u32*>(value), 4, this->getCurrentEndian()) });
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast<u64*>(value), 8, this->getCurrentEndian()) });
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast<u128*>(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<ASTNodeIntegerLiteral>(params[0])->getValue();
auto size = asType<ASTNodeIntegerLiteral>(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<s32*>(value), 4, this->getCurrentEndian()) });
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast<s64*>(value), 8, this->getCurrentEndian()) });
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast<s128*>(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<ASTNodeIntegerLiteral>(params[0])->getValue();
auto message = asType<ASTNodeStringLiteral>(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<ASTNodeIntegerLiteral>(params[0])->getValue();
auto message = asType<ASTNodeStringLiteral>(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<ASTNodeIntegerLiteral*>(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<ASTNodeStringLiteral>(params[0])->getString();
std::vector<std::string> 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<ASTNodeStringLiteral>(params[0])->getString();
std::vector<std::string> 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<ASTNodeStringLiteral>(params[0])->getString();
std::vector<std::string> path = splitString(name, ".");

View file

@ -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<std::string> &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<PatternDataPointer*>(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<u32*>(value), 4, unsignedPattern->getEndian()) });
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast<u64*>(value), 8, unsignedPattern->getEndian()) });
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast<u128*>(value), 16, unsignedPattern->getEndian()) });
default: throwEvaluateError("invalid rvalue size");
default: this->getConsole().abortEvaluation("invalid rvalue size");
}
} else if (auto signedPattern = dynamic_cast<PatternDataSigned*>(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<s32*>(value), 4, signedPattern->getEndian()) });
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast<s64*>(value), 8, signedPattern->getEndian()) });
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast<s128*>(value), 16, signedPattern->getEndian()) });
default: throwEvaluateError("invalid rvalue size");
default: this->getConsole().abortEvaluation("invalid rvalue size");
}
} else if (auto enumPattern = dynamic_cast<PatternDataEnum*>(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<u32*>(value), 4, enumPattern->getEndian()) });
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast<u64*>(value), 8, enumPattern->getEndian()) });
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast<u128*>(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<ASTNodeIntegerLiteral*>(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<ASTNodeNumericExpression*>(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<ASTNodeTypeDecl*>(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<ASTNodeBuiltinType*>(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<ASTNodeNumericExpression*>(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<s128>(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<ASTNodeBitfield*>(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<u64>(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<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr)
@ -540,7 +540,7 @@ namespace hex::lang {
else if (auto builtinTypeDecl = dynamic_cast<ASTNodeBuiltinType*>(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<u64>(value);
}, valueNode->getValue());
}
@ -569,13 +569,13 @@ namespace hex::lang {
if (auto sizeNumericExpression = dynamic_cast<ASTNodeNumericExpression*>(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<u64>(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<s128>(value);
}, valueNode->getValue());
this->m_currOffset = pointerOffset;
@ -660,12 +660,12 @@ namespace hex::lang {
auto underlyingType = dynamic_cast<ASTNodeTypeDecl*>(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<ASTNodeBuiltinType*>(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<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr)
@ -685,7 +685,7 @@ namespace hex::lang {
else if (auto builtinTypeDecl = dynamic_cast<ASTNodeBuiltinType*>(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 { };

View file

@ -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);
}
}