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:
WerWolv
2022-02-27 23:25:39 +01:00
committed by GitHub
parent b28eaf2dbf
commit 66d1b3fd2f
85 changed files with 4990 additions and 5146 deletions

View File

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

View File

@@ -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

View File

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

View File

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

View File

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