mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 13:37:42 -05:00
pattern: Fixed many code inconsistencies and bugs
This commit is contained in:
@@ -159,3 +159,14 @@ namespace hex {
|
||||
concept has_size = sizeof(T) == Size;
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
class Cloneable {
|
||||
public:
|
||||
[[nodiscard]] virtual T* clone() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
#include <hex/pattern_language/evaluator.hpp>
|
||||
#include <hex/pattern_language/pattern_data.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
@@ -18,14 +19,7 @@ namespace hex::pl {
|
||||
class PatternData;
|
||||
class Evaluator;
|
||||
|
||||
class ASTNode;
|
||||
|
||||
class Clonable {
|
||||
public:
|
||||
[[nodiscard]] virtual ASTNode *clone() const = 0;
|
||||
};
|
||||
|
||||
class ASTNode : public Clonable {
|
||||
class ASTNode : public Cloneable<ASTNode> {
|
||||
public:
|
||||
constexpr ASTNode() = default;
|
||||
|
||||
@@ -42,7 +36,7 @@ namespace hex::pl {
|
||||
[[nodiscard]] virtual std::vector<PatternData *> createPatterns(Evaluator *evaluator) const { return {}; }
|
||||
|
||||
using FunctionResult = std::optional<Token::Literal>;
|
||||
virtual FunctionResult execute(Evaluator *evaluator) const { evaluator->getConsole().abortEvaluation("cannot execute non-function statement", this); }
|
||||
virtual FunctionResult execute(Evaluator *evaluator) const { LogConsole::abortEvaluation("cannot execute non-function statement", this); }
|
||||
|
||||
private:
|
||||
u32 m_lineNumber = 1;
|
||||
@@ -86,8 +80,12 @@ namespace hex::pl {
|
||||
}
|
||||
|
||||
Attributable(const Attributable &other) {
|
||||
for (auto &attribute : other.m_attributes)
|
||||
this->m_attributes.push_back(static_cast<ASTNodeAttribute *>(attribute->clone()));
|
||||
for (auto &attribute : other.m_attributes) {
|
||||
if (auto node = dynamic_cast<ASTNodeAttribute*>(attribute->clone()))
|
||||
this->m_attributes.push_back(node);
|
||||
else
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -203,17 +201,17 @@ namespace hex::pl {
|
||||
[this](double left, PatternData *const &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](char left, PatternData *const &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](bool left, PatternData *const &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](std::string left, PatternData *const &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::string &left, PatternData *const &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, u128 right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, i128 right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, double right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, char right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, bool right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, std::string right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, PatternData *right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, const std::string &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](PatternData *const &left, PatternData *const &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
|
||||
[this](auto &&left, std::string right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](std::string left, auto &&right) -> ASTNode * {
|
||||
[this](auto &&left, const std::string &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::string &left, auto &&right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Star:
|
||||
{
|
||||
@@ -226,7 +224,7 @@ namespace hex::pl {
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
},
|
||||
[this](std::string left, std::string right) -> ASTNode * {
|
||||
[this](const std::string &left, const std::string &right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Plus:
|
||||
return new ASTNodeLiteral(left + right);
|
||||
@@ -246,7 +244,7 @@ namespace hex::pl {
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
},
|
||||
[this](std::string left, char right) -> ASTNode * {
|
||||
[this](const std::string &left, char right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Plus:
|
||||
return new ASTNodeLiteral(left + right);
|
||||
@@ -254,7 +252,7 @@ namespace hex::pl {
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
},
|
||||
[this](char left, std::string right) -> ASTNode * {
|
||||
[this](char left, const std::string &right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Plus:
|
||||
return new ASTNodeLiteral(left + right);
|
||||
@@ -361,7 +359,7 @@ namespace hex::pl {
|
||||
};
|
||||
|
||||
auto condition = std::visit(overloaded {
|
||||
[this](std::string value) -> bool { return !value.empty(); },
|
||||
[](const std::string &value) -> bool { return !value.empty(); },
|
||||
[this](PatternData *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
|
||||
[](auto &&value) -> bool { return bool(value); } },
|
||||
first->getValue());
|
||||
@@ -456,8 +454,12 @@ namespace hex::pl {
|
||||
auto type = this->m_type->evaluate(evaluator);
|
||||
|
||||
if (auto attributable = dynamic_cast<Attributable *>(type)) {
|
||||
for (auto &attribute : this->getAttributes())
|
||||
attributable->addAttribute(static_cast<ASTNodeAttribute *>(attribute->clone()));
|
||||
for (auto &attribute : this->getAttributes()) {
|
||||
if (auto node = dynamic_cast<ASTNodeAttribute*>(attribute->clone()))
|
||||
attributable->addAttribute(node);
|
||||
else
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
@@ -489,7 +491,7 @@ namespace hex::pl {
|
||||
class ASTNodeCast : public ASTNode {
|
||||
public:
|
||||
ASTNodeCast(ASTNode *value, ASTNode *type) : m_value(value), m_type(type) { }
|
||||
ASTNodeCast(const ASTNodeCast &other) {
|
||||
ASTNodeCast(const ASTNodeCast &other) : ASTNode(other) {
|
||||
this->m_value = other.m_value->clone();
|
||||
this->m_type = other.m_type->clone();
|
||||
}
|
||||
@@ -623,7 +625,7 @@ namespace hex::pl {
|
||||
auto parameterPack = evaluator->getScope(0).parameterPack;
|
||||
u32 startVariableCount = variables.size();
|
||||
ON_SCOPE_EXIT {
|
||||
i64 stackSize = evaluator->getStack().size();
|
||||
ssize_t stackSize = evaluator->getStack().size();
|
||||
for (u32 i = startVariableCount; i < variables.size(); i++) {
|
||||
stackSize--;
|
||||
delete variables[i];
|
||||
@@ -671,7 +673,7 @@ namespace hex::pl {
|
||||
ON_SCOPE_EXIT { delete literal; };
|
||||
|
||||
return std::visit(overloaded {
|
||||
[](std::string value) -> bool { return !value.empty(); },
|
||||
[](const std::string &value) -> bool { return !value.empty(); },
|
||||
[this](PatternData *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
|
||||
[](auto &&value) -> bool { return value != 0; } },
|
||||
literal->getValue());
|
||||
@@ -784,6 +786,9 @@ namespace hex::pl {
|
||||
this->m_placementOffset = other.m_placementOffset->clone();
|
||||
else
|
||||
this->m_placementOffset = nullptr;
|
||||
|
||||
this->m_inVariable = other.m_inVariable;
|
||||
this->m_outVariable = other.m_outVariable;
|
||||
}
|
||||
|
||||
~ASTNodeVariableDecl() override {
|
||||
@@ -808,7 +813,7 @@ namespace hex::pl {
|
||||
ON_SCOPE_EXIT { delete offset; };
|
||||
|
||||
evaluator->dataOffset() = std::visit(overloaded {
|
||||
[this](std::string) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](PatternData *const &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
|
||||
[](auto &&offset) -> u64 { return offset; } },
|
||||
offset->getValue());
|
||||
@@ -833,7 +838,7 @@ namespace hex::pl {
|
||||
ASTNode *m_type;
|
||||
ASTNode *m_placementOffset;
|
||||
|
||||
bool m_inVariable, m_outVariable;
|
||||
bool m_inVariable = false, m_outVariable = false;
|
||||
};
|
||||
|
||||
class ASTNodeArrayVariableDecl : public ASTNode,
|
||||
@@ -872,7 +877,7 @@ namespace hex::pl {
|
||||
ON_SCOPE_EXIT { delete offset; };
|
||||
|
||||
evaluator->dataOffset() = std::visit(overloaded {
|
||||
[this](std::string) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](PatternData *const &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
|
||||
[](auto &&offset) -> u64 { return offset; } },
|
||||
offset->getValue());
|
||||
@@ -930,7 +935,7 @@ namespace hex::pl {
|
||||
|
||||
if (auto literal = dynamic_cast<ASTNodeLiteral *>(sizeNode)) {
|
||||
entryCount = std::visit(overloaded {
|
||||
[this](std::string) -> u128 { LogConsole::abortEvaluation("cannot use string to index array", this); },
|
||||
[this](const std::string &) -> u128 { LogConsole::abortEvaluation("cannot use string to index array", this); },
|
||||
[this](PatternData *) -> u128 { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
|
||||
[](auto &&size) -> u128 { return size; } },
|
||||
literal->getValue());
|
||||
@@ -1029,7 +1034,7 @@ namespace hex::pl {
|
||||
|
||||
if (auto literal = dynamic_cast<ASTNodeLiteral *>(sizeNode)) {
|
||||
auto entryCount = std::visit(overloaded {
|
||||
[this](std::string) -> u128 { LogConsole::abortEvaluation("cannot use string to index array", this); },
|
||||
[this](const std::string &) -> u128 { LogConsole::abortEvaluation("cannot use string to index array", this); },
|
||||
[this](PatternData *) -> u128 { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
|
||||
[](auto &&size) -> u128 { return size; } },
|
||||
literal->getValue());
|
||||
@@ -1176,7 +1181,7 @@ namespace hex::pl {
|
||||
ON_SCOPE_EXIT { delete offset; };
|
||||
|
||||
evaluator->dataOffset() = std::visit(overloaded {
|
||||
[this](std::string) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](PatternData *) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
|
||||
[](auto &&offset) -> u64 { return u64(offset); } },
|
||||
offset->getValue());
|
||||
@@ -1499,7 +1504,7 @@ namespace hex::pl {
|
||||
ON_SCOPE_EXIT { delete literal; };
|
||||
|
||||
u8 bitSize = std::visit(overloaded {
|
||||
[this](std::string) -> u8 { LogConsole::abortEvaluation("bitfield field size cannot be a string", this); },
|
||||
[this](const std::string &) -> u8 { LogConsole::abortEvaluation("bitfield field size cannot be a string", this); },
|
||||
[this](PatternData *) -> u8 { LogConsole::abortEvaluation("bitfield field size cannot be a custom type", this); },
|
||||
[](auto &&offset) -> u8 { return static_cast<u8>(offset); } },
|
||||
dynamic_cast<ASTNodeLiteral *>(literal)->getValue());
|
||||
@@ -1531,13 +1536,13 @@ namespace hex::pl {
|
||||
|
||||
class ASTNodeParameterPack : public ASTNode {
|
||||
public:
|
||||
ASTNodeParameterPack(const std::vector<Token::Literal> &values) : m_values(values) {}
|
||||
explicit ASTNodeParameterPack(std::vector<Token::Literal> values) : m_values(std::move(values)) {}
|
||||
|
||||
[[nodiscard]] ASTNode *clone() const override {
|
||||
return new ASTNodeParameterPack(*this);
|
||||
}
|
||||
|
||||
const std::vector<Token::Literal> &getValues() const {
|
||||
[[nodiscard]] const std::vector<Token::Literal> &getValues() const {
|
||||
return this->m_values;
|
||||
}
|
||||
|
||||
@@ -1622,7 +1627,7 @@ namespace hex::pl {
|
||||
|
||||
std::visit(overloaded {
|
||||
[&](char assignmentValue) { if (assignmentValue != 0x00) value = std::string({ assignmentValue }); },
|
||||
[&](std::string assignmentValue) { value = assignmentValue; },
|
||||
[&](const std::string &assignmentValue) { value = assignmentValue; },
|
||||
[&, this](PatternData *const &assignmentValue) {
|
||||
if (!dynamic_cast<PatternDataString *>(assignmentValue) && !dynamic_cast<PatternDataCharacter *>(assignmentValue))
|
||||
LogConsole::abortEvaluation(hex::format("cannot assign '{}' to string", pattern->getTypeName()), this);
|
||||
@@ -1646,7 +1651,7 @@ namespace hex::pl {
|
||||
literal = pattern->clone();
|
||||
}
|
||||
|
||||
if (auto transformFunc = pattern->getTransformFunction(); transformFunc.has_value() && pattern->getEvaluator() != nullptr) {
|
||||
if (auto transformFunc = pattern->getTransformFunction(); transformFunc.has_value()) {
|
||||
auto result = transformFunc->func(evaluator, { literal });
|
||||
|
||||
if (!result.has_value())
|
||||
@@ -1730,8 +1735,8 @@ namespace hex::pl {
|
||||
ON_SCOPE_EXIT { delete index; };
|
||||
|
||||
std::visit(overloaded {
|
||||
[](std::string) { throw std::string("cannot use string to index array"); },
|
||||
[](PatternData *const &) { throw std::string("cannot use custom type to index array"); },
|
||||
[this](const std::string &) { LogConsole::abortEvaluation("cannot use string to index array", this); },
|
||||
[this](PatternData *const &) { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
|
||||
[&, this](auto &&index) {
|
||||
if (auto dynamicArrayPattern = dynamic_cast<PatternDataDynamicArray *>(currPattern)) {
|
||||
if (index >= searchScope.size() || index < 0)
|
||||
@@ -1825,7 +1830,7 @@ namespace hex::pl {
|
||||
public:
|
||||
explicit ASTNodeScopeResolution(ASTNode *type, std::string name) : ASTNode(), m_type(type), m_name(std::move(name)) { }
|
||||
|
||||
ASTNodeScopeResolution(const ASTNodeScopeResolution &other) {
|
||||
ASTNodeScopeResolution(const ASTNodeScopeResolution &other) : ASTNode(other) {
|
||||
this->m_type = other.m_type->clone();
|
||||
this->m_name = other.m_name;
|
||||
}
|
||||
@@ -1904,14 +1909,6 @@ namespace hex::pl {
|
||||
return this->m_condition;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<ASTNode *> &getTrueBody() const {
|
||||
return this->m_trueBody;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<ASTNode *> &getFalseBody() const {
|
||||
return this->m_falseBody;
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
auto &body = evaluateCondition(evaluator) ? this->m_trueBody : this->m_falseBody;
|
||||
|
||||
@@ -1948,7 +1945,7 @@ namespace hex::pl {
|
||||
ON_SCOPE_EXIT { delete literal; };
|
||||
|
||||
return std::visit(overloaded {
|
||||
[](std::string value) -> bool { return !value.empty(); },
|
||||
[](const std::string &value) -> bool { return !value.empty(); },
|
||||
[this](PatternData *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
|
||||
[](auto &&value) -> bool { return value != 0; } },
|
||||
literal->getValue());
|
||||
@@ -2308,9 +2305,9 @@ namespace hex::pl {
|
||||
if (ctx->getCurrentControlFlowStatement() != ControlFlowStatement::None) {
|
||||
switch (ctx->getCurrentControlFlowStatement()) {
|
||||
case ControlFlowStatement::Break:
|
||||
ctx->getConsole().abortEvaluation("break statement not within a loop", statement);
|
||||
LogConsole::abortEvaluation("break statement not within a loop", statement);
|
||||
case ControlFlowStatement::Continue:
|
||||
ctx->getConsole().abortEvaluation("continue statement not within a loop", statement);
|
||||
LogConsole::abortEvaluation("continue statement not within a loop", statement);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2336,13 +2333,15 @@ namespace hex::pl {
|
||||
|
||||
class ASTNodeCompoundStatement : public ASTNode {
|
||||
public:
|
||||
ASTNodeCompoundStatement(std::vector<ASTNode *> statements, bool newScope = false) : m_statements(std::move(statements)), m_newScope(newScope) {
|
||||
explicit ASTNodeCompoundStatement(std::vector<ASTNode *> statements, bool newScope = false) : m_statements(std::move(statements)), m_newScope(newScope) {
|
||||
}
|
||||
|
||||
ASTNodeCompoundStatement(const ASTNodeCompoundStatement &other) : ASTNode(other) {
|
||||
for (const auto &statement : other.m_statements) {
|
||||
this->m_statements.push_back(statement->clone());
|
||||
}
|
||||
|
||||
this->m_newScope = other.m_newScope;
|
||||
}
|
||||
|
||||
[[nodiscard]] ASTNode *clone() const override {
|
||||
@@ -2410,7 +2409,7 @@ namespace hex::pl {
|
||||
|
||||
public:
|
||||
std::vector<ASTNode *> m_statements;
|
||||
bool m_newScope;
|
||||
bool m_newScope = false;
|
||||
};
|
||||
|
||||
};
|
||||
27
lib/libimhex/include/hex/pattern_language/error.hpp
Normal file
27
lib/libimhex/include/hex/pattern_language/error.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternLanguageError : public std::exception {
|
||||
public:
|
||||
PatternLanguageError(u32 lineNumber, std::string message) : m_lineNumber(lineNumber), m_message(std::move(message)) { }
|
||||
|
||||
[[nodiscard]] const char *what() const noexcept override {
|
||||
return this->m_message.c_str();
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 getLineNumber() const {
|
||||
return this->m_lineNumber;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_lineNumber;
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -12,18 +12,16 @@ namespace hex::pl {
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
using LexerError = std::pair<u32, std::string>;
|
||||
|
||||
Lexer() = default;
|
||||
|
||||
std::optional<std::vector<Token>> lex(const std::string &code);
|
||||
const std::optional<LexerError> &getError() { return this->m_error; }
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
private:
|
||||
std::optional<LexerError> m_error;
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
|
||||
[[noreturn]] void throwLexerError(const std::string &error, u32 lineNumber) const {
|
||||
throw LexerError(lineNumber, "Lexer: " + error);
|
||||
[[noreturn]] static void throwLexerError(const std::string &error, u32 lineNumber) {
|
||||
throw PatternLanguageError(lineNumber, "Lexer: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNode;
|
||||
@@ -23,8 +25,6 @@ namespace hex::pl {
|
||||
|
||||
[[nodiscard]] const auto &getLog() const { return this->m_consoleLog; }
|
||||
|
||||
using EvaluateError = std::pair<u32, std::string>;
|
||||
|
||||
void log(Level level, const std::string &message);
|
||||
|
||||
[[noreturn]] static void abortEvaluation(const std::string &message);
|
||||
@@ -33,13 +33,13 @@ namespace hex::pl {
|
||||
|
||||
void clear();
|
||||
|
||||
void setHardError(const EvaluateError &error) { this->m_lastHardError = error; }
|
||||
void setHardError(const PatternLanguageError &error) { this->m_lastHardError = error; }
|
||||
|
||||
[[nodiscard]] const std::optional<EvaluateError> &getLastHardError() { return this->m_lastHardError; };
|
||||
[[nodiscard]] const std::optional<PatternLanguageError> &getLastHardError() { return this->m_lastHardError; };
|
||||
|
||||
private:
|
||||
std::vector<std::pair<Level, std::string>> m_consoleLog;
|
||||
std::optional<EvaluateError> m_lastHardError;
|
||||
std::optional<PatternLanguageError> m_lastHardError;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <hex.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
#include <hex/pattern_language/ast_node.hpp>
|
||||
|
||||
@@ -16,16 +17,15 @@ namespace hex::pl {
|
||||
class Parser {
|
||||
public:
|
||||
using TokenIter = std::vector<Token>::const_iterator;
|
||||
using ParseError = std::pair<u32, std::string>;
|
||||
|
||||
Parser() = default;
|
||||
~Parser() = default;
|
||||
|
||||
std::optional<std::vector<ASTNode *>> parse(const std::vector<Token> &tokens);
|
||||
const std::optional<ParseError> &getError() { return this->m_error; }
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
private:
|
||||
std::optional<ParseError> m_error;
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
TokenIter m_curr;
|
||||
TokenIter m_originalPosition, m_partOriginalPosition;
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace hex::pl {
|
||||
auto value = std::get_if<T>(&this->m_curr[index].value);
|
||||
|
||||
if (value == nullptr)
|
||||
throwParseError("failed to decode token. Invalid type.", getLineNumber(index));
|
||||
throwParserError("failed to decode token. Invalid type.", getLineNumber(index));
|
||||
|
||||
return *value;
|
||||
}
|
||||
@@ -143,8 +143,8 @@ namespace hex::pl {
|
||||
return program;
|
||||
}
|
||||
|
||||
[[noreturn]] void throwParseError(const std::string &error, i32 token = -1) const {
|
||||
throw ParseError(this->m_curr[token].lineNumber, "Parser: " + error);
|
||||
[[noreturn]] void throwParserError(const std::string &error, i32 token = -1) const {
|
||||
throw PatternLanguageError(this->m_curr[token].lineNumber, "Parser: " + error);
|
||||
}
|
||||
|
||||
/* Token consuming */
|
||||
|
||||
@@ -73,11 +73,16 @@ namespace hex::pl {
|
||||
PatternCreationLimiter::s_evaluator->patternDestroyed();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static Evaluator *getEvaluator() {
|
||||
return PatternCreationLimiter::s_evaluator;
|
||||
}
|
||||
|
||||
public:
|
||||
static Evaluator *s_evaluator;
|
||||
};
|
||||
|
||||
class PatternData : public PatternCreationLimiter {
|
||||
class PatternData : public PatternCreationLimiter, public Cloneable<PatternData> {
|
||||
public:
|
||||
PatternData(u64 offset, size_t size, u32 color = 0)
|
||||
: PatternCreationLimiter(), m_offset(offset), m_size(size), m_color(color) {
|
||||
@@ -95,9 +100,7 @@ namespace hex::pl {
|
||||
|
||||
PatternData(const PatternData &other) = default;
|
||||
|
||||
virtual ~PatternData() = default;
|
||||
|
||||
virtual PatternData *clone() = 0;
|
||||
~PatternData() override = default;
|
||||
|
||||
[[nodiscard]] u64 getOffset() const { return this->m_offset; }
|
||||
virtual void setOffset(u64 offset) { this->m_offset = offset; }
|
||||
@@ -122,8 +125,8 @@ namespace hex::pl {
|
||||
[[nodiscard]] bool hasOverriddenColor() const { return this->m_manualColor; }
|
||||
|
||||
[[nodiscard]] std::endian getEndian() const {
|
||||
if (this->getEvaluator() == nullptr) return std::endian::native;
|
||||
else return this->m_endian.value_or(this->getEvaluator()->getDefaultEndian());
|
||||
if (PatternData::getEvaluator() == nullptr) return std::endian::native;
|
||||
else return this->m_endian.value_or(PatternData::getEvaluator()->getDefaultEndian());
|
||||
}
|
||||
virtual void setEndian(std::endian endian) { this->m_endian = endian; }
|
||||
[[nodiscard]] bool hasOverriddenEndian() const { return this->m_endian.has_value(); }
|
||||
@@ -131,8 +134,6 @@ 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; }
|
||||
|
||||
[[nodiscard]] Evaluator *getEvaluator() const { return PatternCreationLimiter::s_evaluator; }
|
||||
|
||||
[[nodiscard]] const auto &getTransformFunction() const { return this->m_transformFunction; }
|
||||
void setTransformFunction(const ContentRegistry::PatternLanguage::Function &function) { this->m_transformFunction = function; }
|
||||
[[nodiscard]] const auto &getFormatterFunction() const { return this->m_formatterFunction; }
|
||||
@@ -154,7 +155,7 @@ namespace hex::pl {
|
||||
for (u64 i = 0; i < this->getSize(); i++)
|
||||
highlight.insert({ this->getOffset() + i, this->getColor() });
|
||||
|
||||
this->getEvaluator()->handleAbort();
|
||||
PatternData::getEvaluator()->handleAbort();
|
||||
}
|
||||
|
||||
virtual void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) { }
|
||||
@@ -255,7 +256,7 @@ namespace hex::pl {
|
||||
return value;
|
||||
else {
|
||||
try {
|
||||
auto result = this->m_formatterFunction->func(this->getEvaluator(), { literal });
|
||||
auto result = this->m_formatterFunction->func(PatternData::getEvaluator(), { literal });
|
||||
|
||||
if (result.has_value()) {
|
||||
if (auto displayValue = std::get_if<std::string>(&result.value()); displayValue != nullptr)
|
||||
@@ -265,8 +266,8 @@ namespace hex::pl {
|
||||
} else {
|
||||
return "???";
|
||||
}
|
||||
} catch (LogConsole::EvaluateError &error) {
|
||||
return "Error: " + error.second;
|
||||
} catch (PatternLanguageError &error) {
|
||||
return "Error: "s + error.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,10 +308,10 @@ namespace hex::pl {
|
||||
bool m_hidden = false;
|
||||
|
||||
private:
|
||||
u64 m_offset;
|
||||
size_t m_size;
|
||||
u64 m_offset = 0x00;
|
||||
size_t m_size = 0x00;
|
||||
|
||||
u32 m_color;
|
||||
u32 m_color = 0x00;
|
||||
std::optional<std::string> m_displayName;
|
||||
std::string m_variableName;
|
||||
std::optional<std::string> m_comment;
|
||||
@@ -327,7 +328,8 @@ namespace hex::pl {
|
||||
public:
|
||||
PatternDataPadding(u64 offset, size_t size) : PatternData(offset, size, 0xFF000000) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataPadding(*this);
|
||||
}
|
||||
|
||||
@@ -355,7 +357,8 @@ namespace hex::pl {
|
||||
delete this->m_pointedAt;
|
||||
}
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataPointer(*this);
|
||||
}
|
||||
|
||||
@@ -476,7 +479,8 @@ namespace hex::pl {
|
||||
PatternDataUnsigned(u64 offset, size_t size, u32 color = 0)
|
||||
: PatternData(offset, size, color) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataUnsigned(*this);
|
||||
}
|
||||
|
||||
@@ -513,7 +517,8 @@ namespace hex::pl {
|
||||
PatternDataSigned(u64 offset, size_t size, u32 color = 0)
|
||||
: PatternData(offset, size, color) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataSigned(*this);
|
||||
}
|
||||
|
||||
@@ -551,7 +556,8 @@ namespace hex::pl {
|
||||
PatternDataFloat(u64 offset, size_t size, u32 color = 0)
|
||||
: PatternData(offset, size, color) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataFloat(*this);
|
||||
}
|
||||
|
||||
@@ -590,7 +596,8 @@ namespace hex::pl {
|
||||
explicit PatternDataBoolean(u64 offset, u32 color = 0)
|
||||
: PatternData(offset, 1, color) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataBoolean(*this);
|
||||
}
|
||||
|
||||
@@ -618,7 +625,8 @@ namespace hex::pl {
|
||||
explicit PatternDataCharacter(u64 offset, u32 color = 0)
|
||||
: PatternData(offset, 1, color) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataCharacter(*this);
|
||||
}
|
||||
|
||||
@@ -641,7 +649,8 @@ namespace hex::pl {
|
||||
explicit PatternDataCharacter16(u64 offset, u32 color = 0)
|
||||
: PatternData(offset, 2, color) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataCharacter16(*this);
|
||||
}
|
||||
|
||||
@@ -674,7 +683,8 @@ namespace hex::pl {
|
||||
PatternDataString(u64 offset, size_t size, u32 color = 0)
|
||||
: PatternData(offset, size, color) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataString(*this);
|
||||
}
|
||||
|
||||
@@ -714,7 +724,8 @@ namespace hex::pl {
|
||||
PatternDataString16(u64 offset, size_t size, u32 color = 0)
|
||||
: PatternData(offset, size, color) { }
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataString16(*this);
|
||||
}
|
||||
|
||||
@@ -780,7 +791,8 @@ namespace hex::pl {
|
||||
delete entry;
|
||||
}
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataDynamicArray(*this);
|
||||
}
|
||||
|
||||
@@ -893,7 +905,7 @@ namespace hex::pl {
|
||||
[[nodiscard]] const PatternData *getPattern(u64 offset) const override {
|
||||
if (this->isHidden()) return nullptr;
|
||||
|
||||
auto iter = std::find_if(this->m_entries.begin(), this->m_entries.end(), [this, offset](PatternData *pattern) {
|
||||
auto iter = std::find_if(this->m_entries.begin(), this->m_entries.end(), [offset](PatternData *pattern) {
|
||||
return offset >= pattern->getOffset() && offset < (pattern->getOffset() + pattern->getSize());
|
||||
});
|
||||
|
||||
@@ -932,7 +944,8 @@ namespace hex::pl {
|
||||
delete this->m_highlightTemplate;
|
||||
}
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataStaticArray(*this);
|
||||
}
|
||||
|
||||
@@ -1067,9 +1080,9 @@ namespace hex::pl {
|
||||
}
|
||||
|
||||
private:
|
||||
PatternData *m_template;
|
||||
mutable PatternData *m_highlightTemplate;
|
||||
size_t m_entryCount;
|
||||
PatternData *m_template = nullptr;
|
||||
mutable PatternData *m_highlightTemplate = nullptr;
|
||||
size_t m_entryCount = 0;
|
||||
u64 m_displayEnd = 50;
|
||||
};
|
||||
|
||||
@@ -1091,7 +1104,8 @@ namespace hex::pl {
|
||||
delete member;
|
||||
}
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataStruct(*this);
|
||||
}
|
||||
|
||||
@@ -1238,7 +1252,8 @@ namespace hex::pl {
|
||||
delete member;
|
||||
}
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataUnion(*this);
|
||||
}
|
||||
|
||||
@@ -1375,7 +1390,8 @@ namespace hex::pl {
|
||||
: PatternData(offset, size, color) {
|
||||
}
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataEnum(*this);
|
||||
}
|
||||
|
||||
@@ -1398,7 +1414,7 @@ namespace hex::pl {
|
||||
|
||||
return false;
|
||||
},
|
||||
[](std::string) { return false; },
|
||||
[](std::string&) { return false; },
|
||||
[](PatternData *) { return false; } },
|
||||
entryValueLiteral);
|
||||
if (matches)
|
||||
@@ -1470,7 +1486,8 @@ namespace hex::pl {
|
||||
: m_bitOffset(bitOffset), m_bitSize(bitSize), m_bitField(bitField), PatternData(offset, 0, color) {
|
||||
}
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataBitfieldField(*this);
|
||||
}
|
||||
|
||||
@@ -1549,7 +1566,8 @@ namespace hex::pl {
|
||||
delete field;
|
||||
}
|
||||
|
||||
PatternData *clone() override {
|
||||
[[nodiscard]]
|
||||
PatternData *clone() const override {
|
||||
return new PatternDataBitfield(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace hex::pl {
|
||||
void abort();
|
||||
|
||||
[[nodiscard]] const std::vector<std::pair<LogConsole::Level, std::string>> &getConsoleLog();
|
||||
[[nodiscard]] const std::optional<std::pair<u32, std::string>> &getError();
|
||||
[[nodiscard]] const std::optional<PatternLanguageError> &getError();
|
||||
[[nodiscard]] std::map<std::string, Token::Literal> getOutVariables() const;
|
||||
|
||||
[[nodiscard]] u32 getCreatedPatternCount();
|
||||
@@ -58,7 +58,7 @@ namespace hex::pl {
|
||||
|
||||
std::vector<ASTNode *> m_currAST;
|
||||
|
||||
std::optional<std::pair<u32, std::string>> m_currError;
|
||||
std::optional<PatternLanguageError> m_currError;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -11,24 +11,24 @@
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Preprocessor {
|
||||
public:
|
||||
Preprocessor();
|
||||
Preprocessor() = default;
|
||||
|
||||
std::optional<std::string> preprocess(const std::string &code, bool initialRun = true);
|
||||
|
||||
void addPragmaHandler(const std::string &pragmaType, const std::function<bool(const std::string &)> &function);
|
||||
void addDefaultPragmaHandlers();
|
||||
|
||||
const std::pair<u32, std::string> &getError() { return this->m_error; }
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
private:
|
||||
using PreprocessorError = std::pair<u32, std::string>;
|
||||
|
||||
[[noreturn]] void throwPreprocessorError(const std::string &error, u32 lineNumber) const {
|
||||
throw PreprocessorError(lineNumber, "Preprocessor: " + error);
|
||||
[[noreturn]] static void throwPreprocessorError(const std::string &error, u32 lineNumber) {
|
||||
throw PatternLanguageError(lineNumber, "Preprocessor: " + error);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers;
|
||||
@@ -38,7 +38,7 @@ namespace hex::pl {
|
||||
|
||||
std::set<fs::path> m_onceIncludedFiles;
|
||||
|
||||
std::pair<u32, std::string> m_error;
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <variant>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/pattern_language/log_console.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
@@ -156,48 +157,48 @@ namespace hex::pl {
|
||||
|
||||
static u128 literalToUnsigned(const pl::Token::Literal &literal) {
|
||||
return std::visit(overloaded {
|
||||
[](std::string) -> u128 { throw std::string("expected integral type, got string"); },
|
||||
[](PatternData *) -> u128 { throw std::string("expected integral type, got custom type"); },
|
||||
[](auto &&value) -> u128 { return value; } },
|
||||
[](const std::string &) -> u128 { LogConsole::abortEvaluation("expected integral type, got string"); },
|
||||
[](PatternData *) -> u128 { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> u128 { return result; } },
|
||||
literal);
|
||||
}
|
||||
|
||||
static i128 literalToSigned(const pl::Token::Literal &literal) {
|
||||
return std::visit(overloaded {
|
||||
[](std::string) -> i128 { throw std::string("expected integral type, got string"); },
|
||||
[](PatternData *) -> i128 { throw std::string("expected integral type, got custom type"); },
|
||||
[](auto &&value) -> i128 { return value; } },
|
||||
[](const std::string &) -> i128 { LogConsole::abortEvaluation("expected integral type, got string"); },
|
||||
[](PatternData *) -> i128 { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> i128 { return result; } },
|
||||
literal);
|
||||
}
|
||||
|
||||
static double literalToFloatingPoint(const pl::Token::Literal &literal) {
|
||||
return std::visit(overloaded {
|
||||
[](std::string) -> double { throw std::string("expected integral type, got string"); },
|
||||
[](PatternData *) -> double { throw std::string("expected integral type, got custom type"); },
|
||||
[](auto &&value) -> double { return value; } },
|
||||
[](const std::string &) -> double { LogConsole::abortEvaluation("expected integral type, got string"); },
|
||||
[](PatternData *) -> double { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> double { return result; } },
|
||||
literal);
|
||||
}
|
||||
|
||||
static bool literalToBoolean(const pl::Token::Literal &literal) {
|
||||
return std::visit(overloaded {
|
||||
[](std::string) -> bool { throw std::string("expected integral type, got string"); },
|
||||
[](PatternData *) -> bool { throw std::string("expected integral type, got custom type"); },
|
||||
[](auto &&value) -> bool { return value != 0; } },
|
||||
[](const std::string &) -> bool { LogConsole::abortEvaluation("expected integral type, got string"); },
|
||||
[](PatternData *) -> bool { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> bool { return result != 0; } },
|
||||
literal);
|
||||
}
|
||||
|
||||
static std::string literalToString(const pl::Token::Literal &literal, bool cast) {
|
||||
if (!cast && std::get_if<std::string>(&literal) == nullptr)
|
||||
throw std::string("expected string type, got integral");
|
||||
LogConsole::abortEvaluation("expected string type, got integral");
|
||||
|
||||
return std::visit(overloaded {
|
||||
[](std::string value) -> std::string { return value; },
|
||||
[](u128 value) -> std::string { return std::to_string(u64(value)); },
|
||||
[](i128 value) -> std::string { return std::to_string(i64(value)); },
|
||||
[](bool value) -> std::string { return value ? "true" : "false"; },
|
||||
[](char value) -> std::string { return std::string() + value; },
|
||||
[](PatternData *) -> std::string { throw std::string("expected integral type, got custom type"); },
|
||||
[](auto &&value) -> std::string { return std::to_string(value); } },
|
||||
[](std::string result) -> std::string { return result; },
|
||||
[](u128 result) -> std::string { return hex::to_string(result); },
|
||||
[](i128 result) -> std::string { return hex::to_string(result); },
|
||||
[](bool result) -> std::string { return result ? "true" : "false"; },
|
||||
[](char result) -> std::string { return { 1, result }; },
|
||||
[](PatternData *) -> std::string { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> std::string { return std::to_string(result); } },
|
||||
literal);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,28 +2,29 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNode;
|
||||
|
||||
class Validator {
|
||||
public:
|
||||
Validator();
|
||||
Validator() = default;
|
||||
|
||||
bool validate(const std::vector<ASTNode *> &ast);
|
||||
|
||||
const std::pair<u32, std::string> &getError() { return this->m_error; }
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
private:
|
||||
std::pair<u32, std::string> m_error;
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
|
||||
using ValidatorError = std::pair<u32, std::string>;
|
||||
|
||||
[[noreturn]] void throwValidateError(std::string_view error, u32 lineNumber) const {
|
||||
throw ValidatorError(lineNumber, error);
|
||||
[[noreturn]] static void throwValidatorError(const std::string &error, u32 lineNumber) {
|
||||
throw PatternLanguageError(lineNumber, "Validator: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user