mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-01 21:17:44 -05:00
patterns: Rewrite evaluation engine (#306)
* patterns: Rewrite most of the evaluator to mainly use polymorphism instead of just RTTI * patterns: Fixed a couple of AST memory leaks * patterns: Parse string operations correctly * patterns: Various fixes and cleanup * patterns: Implement primitive function definitions Function parameters now need to provide their type in the definition * patterns: Added function variable definition and assignment * patterns: Added remaining function statements * patterns: Added unsized and while-sized arrays * patterns: Added multi variable declarations to functions * patterns: Added std::format built-in function * patterns: Allow passing custom types to functions * patterns: Added attributes and new "format" attribute * patterns: Use libfmt for std::print instead of custom version * patterns: Remove unnecessary string compare function * pattern: Fix preprocessor directives * patterns: Fix unit tests * patterns: Added cast expression * patterns: Handle endianess in function parameters * patterns: Added casting to different endian * patterns: Added 'str' type for functions
This commit is contained in:
@@ -9,10 +9,10 @@ namespace hex::test {
|
||||
TestPatternEnums() : TestPattern("Enums"){
|
||||
auto testEnum = create<PatternDataEnum>("TestEnum", "testEnum", 0x120, sizeof(u32));
|
||||
testEnum->setEnumValues({
|
||||
{ s32(0x0000), "A" },
|
||||
{ s32(0x1234), "B" },
|
||||
{ s32(0x1235), "C" },
|
||||
{ s32(0x1236), "D" },
|
||||
{ u128(0x0000), "A" },
|
||||
{ s128(0x1234), "B" },
|
||||
{ u128(0x1235), "C" },
|
||||
{ u128(0x1236), "D" },
|
||||
});
|
||||
|
||||
addPattern(testEnum);
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace hex::test {
|
||||
std::assert(255 == 0xFF, MSG);
|
||||
std::assert(0xAA == 0b10101010, MSG);
|
||||
std::assert(12345 != 67890, MSG);
|
||||
std::assert(100ULL == 0x64ULL, MSG);
|
||||
std::assert(100U == 0x64U, MSG);
|
||||
std::assert(-100 == -0x64, MSG);
|
||||
std::assert(3.14159F > 1.414D, MSG);
|
||||
std::assert('A' == 0x41, MSG);
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace hex::test {
|
||||
std::assert(0xFF00FF | 0x00AA00 == 0xFFAAFF, "| operator error");
|
||||
std::assert(0xFFFFFF & 0x00FF00 == 0x00FF00, "& operator error");
|
||||
std::assert(0xFFFFFF ^ 0x00AA00 == 0xFF55FF, "^ operator error");
|
||||
std::assert(~0xFFFFFFFF == 0x00, "~ operator error");
|
||||
std::assert(~0x00 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "~ operator error");
|
||||
std::assert(0xAA >> 4 == 0x0A, ">> operator error");
|
||||
std::assert(0xAA << 4 == 0xAA0, "<< operator error");
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace hex::test {
|
||||
|
||||
// Special operators
|
||||
std::assert($ == 0, "$ operator error");
|
||||
std::assert((10 == 20) ? 30 : 40 == 40, "?: operator error");
|
||||
std::assert(((10 == 20) ? 30 : 40) == 40, "?: operator error");
|
||||
|
||||
// Type operators
|
||||
struct TypeTest { u32 x, y, z; };
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace hex::test {
|
||||
auto testStruct = create<PatternDataStruct>("TestStruct", "testStruct", 0x100, sizeof(s32) + 20 + sizeof(u8[0x10]));
|
||||
|
||||
auto variable = create<PatternDataSigned>("s32", "variable", 0x100, sizeof(s32));
|
||||
auto padding = create<PatternDataPadding>("", "", 0x100 + sizeof(s32), 20);
|
||||
auto padding = create<PatternDataPadding>("padding", "", 0x100 + sizeof(s32), 20);
|
||||
auto array = create<PatternDataStaticArray>("u8", "array", 0x100 + sizeof(s32) + 20, sizeof(u8[0x10]));
|
||||
array->setEntries(create<PatternDataUnsigned>("u8", "", 0x100 + sizeof(s32) + 20, sizeof(u8)), 0x10);
|
||||
|
||||
|
||||
@@ -17,14 +17,14 @@ using namespace hex::test;
|
||||
|
||||
void addFunctions() {
|
||||
hex::ContentRegistry::PatternLanguageFunctions::Namespace nsStd = { "std" };
|
||||
hex::ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](auto &ctx, auto params) {
|
||||
auto condition = AS_TYPE(hex::pl::ASTNodeIntegerLiteral, params[0])->getValue();
|
||||
auto message = AS_TYPE(hex::pl::ASTNodeStringLiteral, params[1])->getString();
|
||||
hex::ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](Evaluator *ctx, auto params) -> Token::Literal {
|
||||
auto condition = Token::literalToBoolean(params[0]);
|
||||
auto message = Token::literalToString(params[1], false);
|
||||
|
||||
if (LITERAL_COMPARE(condition, condition == 0))
|
||||
ctx.getConsole().abortEvaluation(hex::format("assertion failed \"{0}\"", message.data()));
|
||||
if (!condition)
|
||||
LogConsole::abortEvaluation(hex::format("assertion failed \"{0}\"", message));
|
||||
|
||||
return nullptr;
|
||||
return { };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ int test(int argc, char **argv) {
|
||||
hex::log::fatal("Error during compilation!");
|
||||
|
||||
if (auto error = language.getError(); error.has_value())
|
||||
hex::log::info("Compile error: {}:{}", error->first, error->second);
|
||||
hex::log::info("Compile error: {} : {}", error->first, error->second);
|
||||
else
|
||||
for (auto &[level, message] : language.getConsoleLog())
|
||||
hex::log::info("Evaluate error: {}", message);
|
||||
@@ -93,10 +93,10 @@ int test(int argc, char **argv) {
|
||||
|
||||
// Check if the produced patterns are the ones expected
|
||||
for (u32 i = 0; i < currTest->getPatterns().size(); i++) {
|
||||
auto &left = *patterns->at(i);
|
||||
auto &right = *currTest->getPatterns().at(i);
|
||||
auto &evaluatedPattern = *patterns->at(i);
|
||||
auto &controlPattern = *currTest->getPatterns().at(i);
|
||||
|
||||
if (left != right) {
|
||||
if (evaluatedPattern != controlPattern) {
|
||||
hex::log::fatal("Pattern with name {}:{} didn't match template", patterns->at(i)->getTypeName(), patterns->at(i)->getVariableName());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user