diff --git a/plugins/libimhex/include/hex/pattern_language/ast_node.hpp b/plugins/libimhex/include/hex/pattern_language/ast_node.hpp index 78222664a..8c7715d81 100644 --- a/plugins/libimhex/include/hex/pattern_language/ast_node.hpp +++ b/plugins/libimhex/include/hex/pattern_language/ast_node.hpp @@ -589,7 +589,41 @@ namespace hex::pl { if (function.parameterCount != 1) LogConsole::abortEvaluation("formatter function needs exactly one parameter", node); - pattern->setFormatterFunction(function, evaluator); + pattern->setEvaluator(evaluator); + pattern->setFormatterFunction(function); + } else if (name == "transform" && requiresValue()) { + auto functions = evaluator->getCustomFunctions(); + if (!functions.contains(*value)) + LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node); + + const auto &function = functions[*value]; + if (function.parameterCount != 1) + LogConsole::abortEvaluation("transform function needs exactly one parameter", node); + + pattern->setEvaluator(evaluator); + pattern->setTransformFunction(function); + } else if (name == "pointer_base" && requiresValue()) { + auto functions = evaluator->getCustomFunctions(); + if (!functions.contains(*value)) + LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node); + + const auto &function = functions[*value]; + if (function.parameterCount != 1) + LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node); + + if (auto pointerPattern = dynamic_cast(pattern)) { + u128 value = 0; + evaluator->getProvider()->read(pattern->getOffset(), &value, pattern->getSize()); + + auto result = function.func(evaluator, { value }); + + if (!result.has_value()) + LogConsole::abortEvaluation("pointer base function did not return a value", node); + + pointerPattern->rebase(Token::literalToUnsigned(result.value())); + } else { + LogConsole::abortEvaluation("pointer_base attribute may only be applied to a pointer"); + } } } } @@ -957,6 +991,7 @@ namespace hex::pl { { auto pointedAtPattern = this->m_type->createPatterns(evaluator).front(); + u128 pointerAddress = 0; evaluator->getProvider()->read(pattern->getOffset(), &pointerAddress, pattern->getSize()); pointedAtPattern->setOffset(pointerAddress); @@ -964,12 +999,12 @@ namespace hex::pl { pattern->setPointedAtPattern(pointedAtPattern); } + evaluator->dataOffset() = offset; + pattern->setVariableName(this->m_name); applyVariableAttributes(evaluator, this, pattern); - evaluator->dataOffset() = offset; - return { pattern }; } @@ -1357,6 +1392,14 @@ namespace hex::pl { literal = pattern->clone(); } + if (auto transformFunc = pattern->getTransformFunction(); transformFunc.has_value()) { + auto result = transformFunc->func(evaluator, { literal }); + + if (!result.has_value()) + LogConsole::abortEvaluation("transform function did not return a value", this); + literal = result.value(); + } + return new ASTNodeLiteral(literal); } @@ -1375,7 +1418,13 @@ namespace hex::pl { if (name == "parent") { scopeIndex--; searchScope = *evaluator->getScope(scopeIndex).scope; - currPattern = searchScope.front()->getParent(); + auto currParent = evaluator->getScope(scopeIndex).parent; + + if (currParent == nullptr) + LogConsole::abortEvaluation("no parent available", this); + + currPattern = currParent->clone(); + continue; } else if (name == "this") { searchScope = *evaluator->getScope(scopeIndex).scope; diff --git a/plugins/libimhex/include/hex/pattern_language/pattern_data.hpp b/plugins/libimhex/include/hex/pattern_language/pattern_data.hpp index 02e0f6ed6..74414488f 100644 --- a/plugins/libimhex/include/hex/pattern_language/pattern_data.hpp +++ b/plugins/libimhex/include/hex/pattern_language/pattern_data.hpp @@ -99,9 +99,13 @@ namespace hex::pl { [[nodiscard]] std::string getDisplayName() const { return this->m_displayName.value_or(this->m_variableName); } void setDisplayName(const std::string &name) { this->m_displayName = name; } - void setFormatterFunction(const ContentRegistry::PatternLanguageFunctions::Function &function, Evaluator *evaluator) { - this->m_formatterFunction = { function, evaluator }; - } + [[nodiscard]] Evaluator* getEvaluator() const { return this->m_evaluator; } + void setEvaluator(Evaluator *evaluator) { this->m_evaluator = evaluator; } + + [[nodiscard]] const auto& getTransformFunction() const { return this->m_transformFunction; } + void setTransformFunction(const ContentRegistry::PatternLanguageFunctions::Function &function) { this->m_transformFunction = function; } + [[nodiscard]] const auto& getFormatterFunction() const { return this->m_formatterFunction; } + void setFormatterFunction(const ContentRegistry::PatternLanguageFunctions::Function &function) { this->m_formatterFunction = function; } virtual void createEntry(prv::Provider* &provider) = 0; [[nodiscard]] virtual std::string getFormattedName() const = 0; @@ -247,8 +251,7 @@ namespace hex::pl { if (!this->m_formatterFunction.has_value()) ImGui::Text("%s", value.c_str()); else { - auto &[func, evaluator] = this->m_formatterFunction.value(); - auto result = func.func(evaluator, { literal }); + auto result = this->m_formatterFunction->func(this->getEvaluator(), { literal }); if (result.has_value()) { if (auto displayValue = std::get_if(&result.value()); displayValue != nullptr) @@ -282,7 +285,9 @@ namespace hex::pl { std::optional m_comment; std::string m_typeName; - std::optional> m_formatterFunction; + Evaluator *m_evaluator = nullptr; + std::optional m_formatterFunction; + std::optional m_transformFunction; PatternData *m_parent; bool m_local = false; @@ -397,8 +402,14 @@ namespace hex::pl { *static_cast(&other)->m_pointedAt == *this->m_pointedAt; } + void rebase(u64 base) { + this->m_pointedAt->setOffset((this->m_pointedAt->getOffset() - this->m_pointerBase) + base); + this->m_pointerBase = base; + } + private: PatternData *m_pointedAt; + u64 m_pointerBase = 0; }; class PatternDataUnsigned : public PatternData { diff --git a/plugins/libimhex/source/pattern_language/evaluator.cpp b/plugins/libimhex/source/pattern_language/evaluator.cpp index 3a24418ca..77488d0f6 100644 --- a/plugins/libimhex/source/pattern_language/evaluator.cpp +++ b/plugins/libimhex/source/pattern_language/evaluator.cpp @@ -11,7 +11,9 @@ namespace hex::pl { } } + auto startOffset = this->dataOffset(); auto pattern = type->createPatterns(this).front(); + this->dataOffset() = startOffset; if (pattern == nullptr) { // Handle auto variables