mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 05:27:41 -05:00
patterns: Huge refactor of Pattern Language runtime to use smart pointers (#458)
* patterns: Initial work to refactor pattern language to use smart pointers * patterns: Fixed remaining issues, moved patterns to unique files * sys: Added missing includes for macOS
This commit is contained in:
@@ -1,6 +1,19 @@
|
||||
#include <hex/pattern_language/evaluator.hpp>
|
||||
#include <hex/pattern_language/ast_node.hpp>
|
||||
#include <hex/pattern_language/pattern_data.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_type_decl.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_variable_decl.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_function_call.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_function_definition.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_unsigned.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_signed.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_float.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_boolean.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_character.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_string.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_enum.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
@@ -19,34 +32,37 @@ namespace hex::pl {
|
||||
}
|
||||
}
|
||||
|
||||
auto startOffset = this->dataOffset();
|
||||
auto pattern = type == nullptr ? nullptr : type->createPatterns(this).front();
|
||||
auto startOffset = this->dataOffset();
|
||||
|
||||
std::unique_ptr<Pattern> pattern;
|
||||
this->dataOffset() = startOffset;
|
||||
|
||||
bool referenceType = false;
|
||||
|
||||
if (pattern == nullptr) {
|
||||
if (type == nullptr) {
|
||||
// Handle auto variables
|
||||
if (!value.has_value())
|
||||
LogConsole::abortEvaluation("cannot determine type of auto variable", type);
|
||||
|
||||
if (std::get_if<u128>(&value.value()) != nullptr)
|
||||
pattern = new PatternDataUnsigned(this, 0, sizeof(u128));
|
||||
pattern = std::unique_ptr<Pattern>(new PatternUnsigned(this, 0, sizeof(u128)));
|
||||
else if (std::get_if<i128>(&value.value()) != nullptr)
|
||||
pattern = new PatternDataSigned(this, 0, sizeof(i128));
|
||||
pattern = std::unique_ptr<Pattern>(new PatternSigned(this, 0, sizeof(i128)));
|
||||
else if (std::get_if<double>(&value.value()) != nullptr)
|
||||
pattern = new PatternDataFloat(this, 0, sizeof(double));
|
||||
pattern = std::unique_ptr<Pattern>(new PatternFloat(this, 0, sizeof(double)));
|
||||
else if (std::get_if<bool>(&value.value()) != nullptr)
|
||||
pattern = new PatternDataBoolean(this, 0);
|
||||
pattern = std::unique_ptr<Pattern>(new PatternBoolean(this, 0));
|
||||
else if (std::get_if<char>(&value.value()) != nullptr)
|
||||
pattern = new PatternDataCharacter(this, 0);
|
||||
pattern = std::unique_ptr<Pattern>(new PatternCharacter(this, 0));
|
||||
else if (std::get_if<std::string>(&value.value()) != nullptr)
|
||||
pattern = new PatternDataString(this, 0, 1);
|
||||
else if (std::get_if<PatternData *>(&value.value()) != nullptr) {
|
||||
pattern = std::get<PatternData *>(value.value())->clone();
|
||||
pattern = std::unique_ptr<Pattern>(new PatternString(this, 0, 1));
|
||||
else if (auto patternValue = std::get_if<std::shared_ptr<Pattern>>(&value.value()); patternValue != nullptr) {
|
||||
pattern = (*patternValue)->clone();
|
||||
referenceType = true;
|
||||
} else
|
||||
LogConsole::abortEvaluation("cannot determine type of auto variable", type);
|
||||
} else {
|
||||
pattern = std::move(type->createPatterns(this).front());
|
||||
}
|
||||
|
||||
pattern->setVariableName(name);
|
||||
@@ -57,20 +73,20 @@ namespace hex::pl {
|
||||
this->getStack().emplace_back();
|
||||
}
|
||||
|
||||
variables.push_back(pattern);
|
||||
|
||||
if (outVariable)
|
||||
this->m_outVariables[name] = pattern->getOffset();
|
||||
|
||||
variables.push_back(std::move(pattern));
|
||||
}
|
||||
|
||||
void Evaluator::setVariable(const std::string &name, const Token::Literal &value) {
|
||||
PatternData *pattern = nullptr;
|
||||
std::unique_ptr<Pattern> pattern = nullptr;
|
||||
|
||||
{
|
||||
auto &variables = *this->getScope(0).scope;
|
||||
for (auto &variable : variables) {
|
||||
if (variable->getVariableName() == name) {
|
||||
pattern = variable;
|
||||
pattern = variable->clone();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +99,7 @@ namespace hex::pl {
|
||||
if (!variable->isLocal())
|
||||
LogConsole::abortEvaluation(hex::format("cannot modify global variable '{}' which has been placed in memory", name));
|
||||
|
||||
pattern = variable;
|
||||
pattern = variable->clone();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -96,37 +112,37 @@ namespace hex::pl {
|
||||
|
||||
Token::Literal castedLiteral = std::visit(overloaded {
|
||||
[&](double &value) -> Token::Literal {
|
||||
if (dynamic_cast<PatternDataUnsigned *>(pattern))
|
||||
if (dynamic_cast<PatternUnsigned *>(pattern.get()))
|
||||
return u128(value) & bitmask(pattern->getSize() * 8);
|
||||
else if (dynamic_cast<PatternDataSigned *>(pattern))
|
||||
else if (dynamic_cast<PatternSigned *>(pattern.get()))
|
||||
return i128(value) & bitmask(pattern->getSize() * 8);
|
||||
else if (dynamic_cast<PatternDataFloat *>(pattern))
|
||||
else if (dynamic_cast<PatternFloat *>(pattern.get()))
|
||||
return pattern->getSize() == sizeof(float) ? double(float(value)) : value;
|
||||
else
|
||||
LogConsole::abortEvaluation(hex::format("cannot cast type 'double' to type '{}'", pattern->getTypeName()));
|
||||
},
|
||||
[&](const std::string &value) -> Token::Literal {
|
||||
if (dynamic_cast<PatternDataString *>(pattern))
|
||||
if (dynamic_cast<PatternString *>(pattern.get()))
|
||||
return value;
|
||||
else
|
||||
LogConsole::abortEvaluation(hex::format("cannot cast type 'string' to type '{}'", pattern->getTypeName()));
|
||||
},
|
||||
[&](PatternData *const &value) -> Token::Literal {
|
||||
[&](const std::shared_ptr<Pattern> &value) -> Token::Literal {
|
||||
if (value->getTypeName() == pattern->getTypeName())
|
||||
return value;
|
||||
else
|
||||
LogConsole::abortEvaluation(hex::format("cannot cast type '{}' to type '{}'", value->getTypeName(), pattern->getTypeName()));
|
||||
},
|
||||
[&](auto &&value) -> Token::Literal {
|
||||
if (dynamic_cast<PatternDataUnsigned *>(pattern) || dynamic_cast<PatternDataEnum *>(pattern))
|
||||
if (dynamic_cast<PatternUnsigned *>(pattern.get()) || dynamic_cast<PatternEnum *>(pattern.get()))
|
||||
return u128(value) & bitmask(pattern->getSize() * 8);
|
||||
else if (dynamic_cast<PatternDataSigned *>(pattern))
|
||||
else if (dynamic_cast<PatternSigned *>(pattern.get()))
|
||||
return i128(value) & bitmask(pattern->getSize() * 8);
|
||||
else if (dynamic_cast<PatternDataCharacter *>(pattern))
|
||||
else if (dynamic_cast<PatternCharacter *>(pattern.get()))
|
||||
return char(value);
|
||||
else if (dynamic_cast<PatternDataBoolean *>(pattern))
|
||||
else if (dynamic_cast<PatternBoolean *>(pattern.get()))
|
||||
return bool(value);
|
||||
else if (dynamic_cast<PatternDataFloat *>(pattern))
|
||||
else if (dynamic_cast<PatternFloat *>(pattern.get()))
|
||||
return pattern->getSize() == sizeof(float) ? double(float(value)) : value;
|
||||
else
|
||||
LogConsole::abortEvaluation(hex::format("cannot cast integer literal to type '{}'", pattern->getTypeName()));
|
||||
@@ -136,7 +152,7 @@ namespace hex::pl {
|
||||
this->getStack()[pattern->getOffset()] = castedLiteral;
|
||||
}
|
||||
|
||||
std::optional<std::vector<PatternData *>> Evaluator::evaluate(const std::vector<ASTNode *> &ast) {
|
||||
std::optional<std::vector<std::shared_ptr<Pattern>>> Evaluator::evaluate(const std::vector<std::shared_ptr<ASTNode>> &ast) {
|
||||
this->m_stack.clear();
|
||||
this->m_customFunctions.clear();
|
||||
this->m_scopes.clear();
|
||||
@@ -155,11 +171,9 @@ namespace hex::pl {
|
||||
this->dataOffset() = 0x00;
|
||||
this->m_currPatternCount = 0;
|
||||
|
||||
for (auto &func : this->m_customFunctionDefinitions)
|
||||
delete func;
|
||||
this->m_customFunctionDefinitions.clear();
|
||||
|
||||
std::vector<PatternData *> patterns;
|
||||
std::vector<std::shared_ptr<Pattern>> patterns;
|
||||
|
||||
try {
|
||||
this->setCurrentControlFlowStatement(ControlFlowStatement::None);
|
||||
@@ -168,33 +182,30 @@ namespace hex::pl {
|
||||
popScope();
|
||||
};
|
||||
|
||||
for (auto node : ast) {
|
||||
if (dynamic_cast<ASTNodeTypeDecl *>(node)) {
|
||||
for (auto &node : ast) {
|
||||
if (dynamic_cast<ASTNodeTypeDecl *>(node.get())) {
|
||||
; // Don't create patterns from type declarations
|
||||
} else if (dynamic_cast<ASTNodeFunctionCall *>(node)) {
|
||||
delete node->evaluate(this);
|
||||
} else if (dynamic_cast<ASTNodeFunctionDefinition *>(node)) {
|
||||
} else if (dynamic_cast<ASTNodeFunctionCall *>(node.get())) {
|
||||
(void)node->evaluate(this);
|
||||
} else if (dynamic_cast<ASTNodeFunctionDefinition *>(node.get())) {
|
||||
this->m_customFunctionDefinitions.push_back(node->evaluate(this));
|
||||
} else if (auto varDeclNode = dynamic_cast<ASTNodeVariableDecl *>(node)) {
|
||||
auto pattern = node->createPatterns(this).front();
|
||||
} else if (auto varDeclNode = dynamic_cast<ASTNodeVariableDecl *>(node.get())) {
|
||||
for (auto &pattern : node->createPatterns(this)) {
|
||||
if (varDeclNode->getPlacementOffset() == nullptr) {
|
||||
auto type = varDeclNode->getType()->evaluate(this);
|
||||
|
||||
if (varDeclNode->getPlacementOffset() == nullptr) {
|
||||
auto type = varDeclNode->getType()->evaluate(this);
|
||||
ON_SCOPE_EXIT { delete type; };
|
||||
auto &name = pattern->getVariableName();
|
||||
this->createVariable(name, type.get(), std::nullopt, varDeclNode->isOutVariable());
|
||||
|
||||
auto &name = pattern->getVariableName();
|
||||
this->createVariable(name, type, std::nullopt, varDeclNode->isOutVariable());
|
||||
|
||||
if (varDeclNode->isInVariable() && this->m_inVariables.contains(name))
|
||||
this->setVariable(name, this->m_inVariables[name]);
|
||||
|
||||
delete pattern;
|
||||
} else {
|
||||
patterns.push_back(pattern);
|
||||
if (varDeclNode->isInVariable() && this->m_inVariables.contains(name))
|
||||
this->setVariable(name, this->m_inVariables[name]);
|
||||
} else {
|
||||
patterns.push_back(std::move(pattern));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto newPatterns = node->createPatterns(this);
|
||||
std::copy(newPatterns.begin(), newPatterns.end(), std::back_inserter(patterns));
|
||||
std::move(newPatterns.begin(), newPatterns.end(), std::back_inserter(patterns));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,8 +223,6 @@ namespace hex::pl {
|
||||
if (error.getLineNumber() != 0)
|
||||
this->m_console.setHardError(error);
|
||||
|
||||
for (auto &pattern : patterns)
|
||||
delete pattern;
|
||||
patterns.clear();
|
||||
|
||||
this->m_currPatternCount = 0;
|
||||
@@ -222,7 +231,7 @@ namespace hex::pl {
|
||||
}
|
||||
|
||||
// Remove global local variables
|
||||
std::erase_if(patterns, [](PatternData *pattern) {
|
||||
std::erase_if(patterns, [](const std::shared_ptr<Pattern> &pattern) {
|
||||
return pattern->isLocal();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#include <hex/pattern_language/log_console.hpp>
|
||||
|
||||
#include <hex/pattern_language/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
void LogConsole::log(Level level, const std::string &message) {
|
||||
this->m_consoleLog.emplace_back(level, message);
|
||||
}
|
||||
|
||||
[[noreturn]] void LogConsole::abortEvaluation(const std::string &message, const ASTNode *node) {
|
||||
if (node == nullptr)
|
||||
throw PatternLanguageError(0, "Evaluator: " + message);
|
||||
@@ -15,9 +11,4 @@ namespace hex::pl {
|
||||
throw PatternLanguageError(node->getLineNumber(), "Evaluator: " + message);
|
||||
}
|
||||
|
||||
void LogConsole::clear() {
|
||||
this->m_consoleLog.clear();
|
||||
this->m_lastHardError = {};
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternData;
|
||||
class Pattern;
|
||||
|
||||
PatternLanguage::PatternLanguage() {
|
||||
this->m_preprocessor = new Preprocessor();
|
||||
@@ -92,7 +92,7 @@ namespace hex::pl {
|
||||
delete this->m_validator;
|
||||
}
|
||||
|
||||
std::optional<std::vector<ASTNode *>> PatternLanguage::parseString(const std::string &code) {
|
||||
std::optional<std::vector<std::shared_ptr<ASTNode>>> PatternLanguage::parseString(const std::string &code) {
|
||||
auto preprocessedCode = this->m_preprocessor->preprocess(code);
|
||||
if (!preprocessedCode.has_value()) {
|
||||
this->m_currError = this->m_preprocessor->getError();
|
||||
@@ -114,9 +114,6 @@ namespace hex::pl {
|
||||
if (!this->m_validator->validate(*ast)) {
|
||||
this->m_currError = this->m_validator->getError();
|
||||
|
||||
for (auto &node : *ast)
|
||||
delete node;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -140,17 +137,18 @@ namespace hex::pl {
|
||||
for (const auto &[name, value] : envVars)
|
||||
this->m_evaluator->setEnvVariable(name, value);
|
||||
|
||||
for (auto &node : this->m_currAST)
|
||||
delete node;
|
||||
this->m_currAST.clear();
|
||||
|
||||
auto ast = this->parseString(code);
|
||||
if (!ast)
|
||||
return false;
|
||||
{
|
||||
auto ast = this->parseString(code);
|
||||
if (!ast)
|
||||
return false;
|
||||
|
||||
this->m_currAST = ast.value();
|
||||
this->m_currAST = std::move(ast.value());
|
||||
}
|
||||
|
||||
auto patterns = this->m_evaluator->evaluate(ast.value());
|
||||
|
||||
auto patterns = this->m_evaluator->evaluate(this->m_currAST);
|
||||
if (!patterns.has_value()) {
|
||||
this->m_currError = this->m_evaluator->getConsole().getLastHardError();
|
||||
return false;
|
||||
@@ -187,14 +185,14 @@ namespace hex::pl {
|
||||
auto success = this->executeString(provider, functionContent, {}, {}, false);
|
||||
auto result = this->m_evaluator->getMainResult();
|
||||
|
||||
return { success, result };
|
||||
return { success, std::move(result) };
|
||||
}
|
||||
|
||||
void PatternLanguage::abort() {
|
||||
this->m_evaluator->abort();
|
||||
}
|
||||
|
||||
const std::vector<ASTNode *> &PatternLanguage::getCurrentAST() const {
|
||||
const std::vector<std::shared_ptr<ASTNode>> &PatternLanguage::getCurrentAST() const {
|
||||
return this->m_currAST;
|
||||
}
|
||||
|
||||
@@ -229,8 +227,6 @@ namespace hex::pl {
|
||||
}
|
||||
|
||||
void PatternLanguage::reset() {
|
||||
for (auto &pattern : this->m_patterns)
|
||||
delete pattern;
|
||||
this->m_patterns.clear();
|
||||
|
||||
this->m_currAST.clear();
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#include <hex/pattern_language/validator.hpp>
|
||||
|
||||
#include <hex/pattern_language/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_variable_decl.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_type_decl.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_struct.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_union.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_enum.hpp>
|
||||
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
@@ -9,7 +14,7 @@
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
bool Validator::validate(const std::vector<ASTNode *> &ast) {
|
||||
bool Validator::validate(const std::vector<std::shared_ptr<ASTNode>> &ast) {
|
||||
std::unordered_set<std::string> identifiers;
|
||||
std::unordered_set<std::string> types;
|
||||
|
||||
@@ -19,21 +24,21 @@ namespace hex::pl {
|
||||
if (node == nullptr)
|
||||
throwValidatorError("nullptr in AST. This is a bug!", 1);
|
||||
|
||||
if (auto variableDeclNode = dynamic_cast<ASTNodeVariableDecl *>(node); variableDeclNode != nullptr) {
|
||||
if (auto variableDeclNode = dynamic_cast<ASTNodeVariableDecl *>(node.get()); variableDeclNode != nullptr) {
|
||||
if (!identifiers.insert(variableDeclNode->getName().data()).second)
|
||||
throwValidatorError(hex::format("redefinition of identifier '{0}'", variableDeclNode->getName().data()), variableDeclNode->getLineNumber());
|
||||
|
||||
this->validate({ variableDeclNode->getType() });
|
||||
} else if (auto typeDeclNode = dynamic_cast<ASTNodeTypeDecl *>(node); typeDeclNode != nullptr) {
|
||||
this->validate(hex::moveToVector<std::shared_ptr<ASTNode>>(variableDeclNode->getType()->clone()));
|
||||
} else if (auto typeDeclNode = dynamic_cast<ASTNodeTypeDecl *>(node.get()); typeDeclNode != nullptr) {
|
||||
if (!types.insert(typeDeclNode->getName().data()).second)
|
||||
throwValidatorError(hex::format("redefinition of type '{0}'", typeDeclNode->getName().data()), typeDeclNode->getLineNumber());
|
||||
|
||||
this->validate({ typeDeclNode->getType() });
|
||||
} else if (auto structNode = dynamic_cast<ASTNodeStruct *>(node); structNode != nullptr) {
|
||||
this->validate(hex::moveToVector<std::shared_ptr<ASTNode>>(typeDeclNode->getType()->clone()));
|
||||
} else if (auto structNode = dynamic_cast<ASTNodeStruct *>(node.get()); structNode != nullptr) {
|
||||
this->validate(structNode->getMembers());
|
||||
} else if (auto unionNode = dynamic_cast<ASTNodeUnion *>(node); unionNode != nullptr) {
|
||||
} else if (auto unionNode = dynamic_cast<ASTNodeUnion *>(node.get()); unionNode != nullptr) {
|
||||
this->validate(unionNode->getMembers());
|
||||
} else if (auto enumNode = dynamic_cast<ASTNodeEnum *>(node); enumNode != nullptr) {
|
||||
} else if (auto enumNode = dynamic_cast<ASTNodeEnum *>(node.get()); enumNode != nullptr) {
|
||||
std::unordered_set<std::string> enumIdentifiers;
|
||||
for (auto &[name, value] : enumNode->getEntries()) {
|
||||
if (!enumIdentifiers.insert(name).second)
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/pattern_language/pattern_data.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
#include <hex/pattern_language/pattern_language.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
@@ -14,6 +17,7 @@ namespace hex::prv {
|
||||
|
||||
Provider::Provider() {
|
||||
this->m_patches.emplace_back();
|
||||
this->m_patternLanguageRuntime = std::make_unique<pl::PatternLanguage>();
|
||||
|
||||
if (this->hasLoadInterface())
|
||||
EventManager::post<RequestOpenPopup>(View::toWindowName("hex.builtin.view.provider_settings.load_popup"));
|
||||
|
||||
Reference in New Issue
Block a user