Improved logging and aborting from pattern language builtin functions
This commit is contained in:
parent
a641f27b7e
commit
22d75ed856
@ -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);
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 };
|
||||
}
|
||||
|
||||
|
@ -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, ".");
|
||||
|
@ -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 { };
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user