1
0
mirror of synced 2024-11-24 07:40:17 +01:00

pattern: Fixed many code inconsistencies and bugs

This commit is contained in:
WerWolv 2022-01-31 14:37:12 +01:00
parent 8f8f3c5415
commit 61fc479c79
22 changed files with 303 additions and 246 deletions

View File

@ -31,7 +31,6 @@ add_subdirectory(main)
add_custom_target(imhex ALL DEPENDS main) add_custom_target(imhex ALL DEPENDS main)
# Add unit tests # Add unit tests
enable_testing()
add_subdirectory(tests EXCLUDE_FROM_ALL) add_subdirectory(tests EXCLUDE_FROM_ALL)
# Configure packaging # Configure packaging

View File

@ -159,3 +159,14 @@ namespace hex {
concept has_size = sizeof(T) == Size; concept has_size = sizeof(T) == Size;
} }
namespace hex {
template<typename T>
class Cloneable {
public:
[[nodiscard]] virtual T* clone() const = 0;
};
}

View File

@ -3,6 +3,7 @@
#include <hex/pattern_language/token.hpp> #include <hex/pattern_language/token.hpp>
#include <hex/pattern_language/evaluator.hpp> #include <hex/pattern_language/evaluator.hpp>
#include <hex/pattern_language/pattern_data.hpp> #include <hex/pattern_language/pattern_data.hpp>
#include <hex/helpers/concepts.hpp>
#include <algorithm> #include <algorithm>
#include <bit> #include <bit>
@ -18,14 +19,7 @@ namespace hex::pl {
class PatternData; class PatternData;
class Evaluator; class Evaluator;
class ASTNode; class ASTNode : public Cloneable<ASTNode> {
class Clonable {
public:
[[nodiscard]] virtual ASTNode *clone() const = 0;
};
class ASTNode : public Clonable {
public: public:
constexpr ASTNode() = default; constexpr ASTNode() = default;
@ -42,7 +36,7 @@ namespace hex::pl {
[[nodiscard]] virtual std::vector<PatternData *> createPatterns(Evaluator *evaluator) const { return {}; } [[nodiscard]] virtual std::vector<PatternData *> createPatterns(Evaluator *evaluator) const { return {}; }
using FunctionResult = std::optional<Token::Literal>; 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: private:
u32 m_lineNumber = 1; u32 m_lineNumber = 1;
@ -86,8 +80,12 @@ namespace hex::pl {
} }
Attributable(const Attributable &other) { Attributable(const Attributable &other) {
for (auto &attribute : other.m_attributes) for (auto &attribute : other.m_attributes) {
this->m_attributes.push_back(static_cast<ASTNodeAttribute *>(attribute->clone())); if (auto node = dynamic_cast<ASTNodeAttribute*>(attribute->clone()))
this->m_attributes.push_back(node);
else
delete node;
}
} }
public: 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](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](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](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, 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, 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, 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, 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, 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, const 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, 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](auto &&left, const std::string &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
[this](std::string left, auto &&right) -> ASTNode * { [this](const std::string &left, auto &&right) -> ASTNode * {
switch (this->getOperator()) { switch (this->getOperator()) {
case Token::Operator::Star: case Token::Operator::Star:
{ {
@ -226,7 +224,7 @@ namespace hex::pl {
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); 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()) { switch (this->getOperator()) {
case Token::Operator::Plus: case Token::Operator::Plus:
return new ASTNodeLiteral(left + right); return new ASTNodeLiteral(left + right);
@ -246,7 +244,7 @@ namespace hex::pl {
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); 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()) { switch (this->getOperator()) {
case Token::Operator::Plus: case Token::Operator::Plus:
return new ASTNodeLiteral(left + right); return new ASTNodeLiteral(left + right);
@ -254,7 +252,7 @@ namespace hex::pl {
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); 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()) { switch (this->getOperator()) {
case Token::Operator::Plus: case Token::Operator::Plus:
return new ASTNodeLiteral(left + right); return new ASTNodeLiteral(left + right);
@ -361,7 +359,7 @@ namespace hex::pl {
}; };
auto condition = std::visit(overloaded { 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); }, [this](PatternData *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
[](auto &&value) -> bool { return bool(value); } }, [](auto &&value) -> bool { return bool(value); } },
first->getValue()); first->getValue());
@ -456,8 +454,12 @@ namespace hex::pl {
auto type = this->m_type->evaluate(evaluator); auto type = this->m_type->evaluate(evaluator);
if (auto attributable = dynamic_cast<Attributable *>(type)) { if (auto attributable = dynamic_cast<Attributable *>(type)) {
for (auto &attribute : this->getAttributes()) for (auto &attribute : this->getAttributes()) {
attributable->addAttribute(static_cast<ASTNodeAttribute *>(attribute->clone())); if (auto node = dynamic_cast<ASTNodeAttribute*>(attribute->clone()))
attributable->addAttribute(node);
else
delete node;
}
} }
return type; return type;
@ -489,7 +491,7 @@ namespace hex::pl {
class ASTNodeCast : public ASTNode { class ASTNodeCast : public ASTNode {
public: public:
ASTNodeCast(ASTNode *value, ASTNode *type) : m_value(value), m_type(type) { } 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_value = other.m_value->clone();
this->m_type = other.m_type->clone(); this->m_type = other.m_type->clone();
} }
@ -623,7 +625,7 @@ namespace hex::pl {
auto parameterPack = evaluator->getScope(0).parameterPack; auto parameterPack = evaluator->getScope(0).parameterPack;
u32 startVariableCount = variables.size(); u32 startVariableCount = variables.size();
ON_SCOPE_EXIT { ON_SCOPE_EXIT {
i64 stackSize = evaluator->getStack().size(); ssize_t stackSize = evaluator->getStack().size();
for (u32 i = startVariableCount; i < variables.size(); i++) { for (u32 i = startVariableCount; i < variables.size(); i++) {
stackSize--; stackSize--;
delete variables[i]; delete variables[i];
@ -671,7 +673,7 @@ namespace hex::pl {
ON_SCOPE_EXIT { delete literal; }; ON_SCOPE_EXIT { delete literal; };
return std::visit(overloaded { 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); }, [this](PatternData *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
[](auto &&value) -> bool { return value != 0; } }, [](auto &&value) -> bool { return value != 0; } },
literal->getValue()); literal->getValue());
@ -784,6 +786,9 @@ namespace hex::pl {
this->m_placementOffset = other.m_placementOffset->clone(); this->m_placementOffset = other.m_placementOffset->clone();
else else
this->m_placementOffset = nullptr; this->m_placementOffset = nullptr;
this->m_inVariable = other.m_inVariable;
this->m_outVariable = other.m_outVariable;
} }
~ASTNodeVariableDecl() override { ~ASTNodeVariableDecl() override {
@ -808,7 +813,7 @@ namespace hex::pl {
ON_SCOPE_EXIT { delete offset; }; ON_SCOPE_EXIT { delete offset; };
evaluator->dataOffset() = std::visit(overloaded { 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); }, [this](PatternData *const &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
[](auto &&offset) -> u64 { return offset; } }, [](auto &&offset) -> u64 { return offset; } },
offset->getValue()); offset->getValue());
@ -833,7 +838,7 @@ namespace hex::pl {
ASTNode *m_type; ASTNode *m_type;
ASTNode *m_placementOffset; ASTNode *m_placementOffset;
bool m_inVariable, m_outVariable; bool m_inVariable = false, m_outVariable = false;
}; };
class ASTNodeArrayVariableDecl : public ASTNode, class ASTNodeArrayVariableDecl : public ASTNode,
@ -872,7 +877,7 @@ namespace hex::pl {
ON_SCOPE_EXIT { delete offset; }; ON_SCOPE_EXIT { delete offset; };
evaluator->dataOffset() = std::visit(overloaded { 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); }, [this](PatternData *const &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
[](auto &&offset) -> u64 { return offset; } }, [](auto &&offset) -> u64 { return offset; } },
offset->getValue()); offset->getValue());
@ -930,7 +935,7 @@ namespace hex::pl {
if (auto literal = dynamic_cast<ASTNodeLiteral *>(sizeNode)) { if (auto literal = dynamic_cast<ASTNodeLiteral *>(sizeNode)) {
entryCount = std::visit(overloaded { 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); }, [this](PatternData *) -> u128 { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
[](auto &&size) -> u128 { return size; } }, [](auto &&size) -> u128 { return size; } },
literal->getValue()); literal->getValue());
@ -1029,7 +1034,7 @@ namespace hex::pl {
if (auto literal = dynamic_cast<ASTNodeLiteral *>(sizeNode)) { if (auto literal = dynamic_cast<ASTNodeLiteral *>(sizeNode)) {
auto entryCount = std::visit(overloaded { 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); }, [this](PatternData *) -> u128 { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
[](auto &&size) -> u128 { return size; } }, [](auto &&size) -> u128 { return size; } },
literal->getValue()); literal->getValue());
@ -1176,7 +1181,7 @@ namespace hex::pl {
ON_SCOPE_EXIT { delete offset; }; ON_SCOPE_EXIT { delete offset; };
evaluator->dataOffset() = std::visit(overloaded { 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); }, [this](PatternData *) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
[](auto &&offset) -> u64 { return u64(offset); } }, [](auto &&offset) -> u64 { return u64(offset); } },
offset->getValue()); offset->getValue());
@ -1499,7 +1504,7 @@ namespace hex::pl {
ON_SCOPE_EXIT { delete literal; }; ON_SCOPE_EXIT { delete literal; };
u8 bitSize = std::visit(overloaded { 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); }, [this](PatternData *) -> u8 { LogConsole::abortEvaluation("bitfield field size cannot be a custom type", this); },
[](auto &&offset) -> u8 { return static_cast<u8>(offset); } }, [](auto &&offset) -> u8 { return static_cast<u8>(offset); } },
dynamic_cast<ASTNodeLiteral *>(literal)->getValue()); dynamic_cast<ASTNodeLiteral *>(literal)->getValue());
@ -1531,13 +1536,13 @@ namespace hex::pl {
class ASTNodeParameterPack : public ASTNode { class ASTNodeParameterPack : public ASTNode {
public: 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 { [[nodiscard]] ASTNode *clone() const override {
return new ASTNodeParameterPack(*this); return new ASTNodeParameterPack(*this);
} }
const std::vector<Token::Literal> &getValues() const { [[nodiscard]] const std::vector<Token::Literal> &getValues() const {
return this->m_values; return this->m_values;
} }
@ -1622,7 +1627,7 @@ namespace hex::pl {
std::visit(overloaded { std::visit(overloaded {
[&](char assignmentValue) { if (assignmentValue != 0x00) value = std::string({ assignmentValue }); }, [&](char assignmentValue) { if (assignmentValue != 0x00) value = std::string({ assignmentValue }); },
[&](std::string assignmentValue) { value = assignmentValue; }, [&](const std::string &assignmentValue) { value = assignmentValue; },
[&, this](PatternData *const &assignmentValue) { [&, this](PatternData *const &assignmentValue) {
if (!dynamic_cast<PatternDataString *>(assignmentValue) && !dynamic_cast<PatternDataCharacter *>(assignmentValue)) if (!dynamic_cast<PatternDataString *>(assignmentValue) && !dynamic_cast<PatternDataCharacter *>(assignmentValue))
LogConsole::abortEvaluation(hex::format("cannot assign '{}' to string", pattern->getTypeName()), this); LogConsole::abortEvaluation(hex::format("cannot assign '{}' to string", pattern->getTypeName()), this);
@ -1646,7 +1651,7 @@ namespace hex::pl {
literal = pattern->clone(); 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 }); auto result = transformFunc->func(evaluator, { literal });
if (!result.has_value()) if (!result.has_value())
@ -1730,8 +1735,8 @@ namespace hex::pl {
ON_SCOPE_EXIT { delete index; }; ON_SCOPE_EXIT { delete index; };
std::visit(overloaded { std::visit(overloaded {
[](std::string) { throw std::string("cannot use string to index array"); }, [this](const std::string &) { LogConsole::abortEvaluation("cannot use string to index array", this); },
[](PatternData *const &) { throw std::string("cannot use custom type to index array"); }, [this](PatternData *const &) { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
[&, this](auto &&index) { [&, this](auto &&index) {
if (auto dynamicArrayPattern = dynamic_cast<PatternDataDynamicArray *>(currPattern)) { if (auto dynamicArrayPattern = dynamic_cast<PatternDataDynamicArray *>(currPattern)) {
if (index >= searchScope.size() || index < 0) if (index >= searchScope.size() || index < 0)
@ -1825,7 +1830,7 @@ namespace hex::pl {
public: public:
explicit ASTNodeScopeResolution(ASTNode *type, std::string name) : ASTNode(), m_type(type), m_name(std::move(name)) { } 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_type = other.m_type->clone();
this->m_name = other.m_name; this->m_name = other.m_name;
} }
@ -1904,14 +1909,6 @@ namespace hex::pl {
return this->m_condition; 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 { FunctionResult execute(Evaluator *evaluator) const override {
auto &body = evaluateCondition(evaluator) ? this->m_trueBody : this->m_falseBody; auto &body = evaluateCondition(evaluator) ? this->m_trueBody : this->m_falseBody;
@ -1948,7 +1945,7 @@ namespace hex::pl {
ON_SCOPE_EXIT { delete literal; }; ON_SCOPE_EXIT { delete literal; };
return std::visit(overloaded { 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); }, [this](PatternData *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
[](auto &&value) -> bool { return value != 0; } }, [](auto &&value) -> bool { return value != 0; } },
literal->getValue()); literal->getValue());
@ -2308,9 +2305,9 @@ namespace hex::pl {
if (ctx->getCurrentControlFlowStatement() != ControlFlowStatement::None) { if (ctx->getCurrentControlFlowStatement() != ControlFlowStatement::None) {
switch (ctx->getCurrentControlFlowStatement()) { switch (ctx->getCurrentControlFlowStatement()) {
case ControlFlowStatement::Break: 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: case ControlFlowStatement::Continue:
ctx->getConsole().abortEvaluation("continue statement not within a loop", statement); LogConsole::abortEvaluation("continue statement not within a loop", statement);
default: default:
break; break;
} }
@ -2336,13 +2333,15 @@ namespace hex::pl {
class ASTNodeCompoundStatement : public ASTNode { class ASTNodeCompoundStatement : public ASTNode {
public: 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) { ASTNodeCompoundStatement(const ASTNodeCompoundStatement &other) : ASTNode(other) {
for (const auto &statement : other.m_statements) { for (const auto &statement : other.m_statements) {
this->m_statements.push_back(statement->clone()); this->m_statements.push_back(statement->clone());
} }
this->m_newScope = other.m_newScope;
} }
[[nodiscard]] ASTNode *clone() const override { [[nodiscard]] ASTNode *clone() const override {
@ -2410,7 +2409,7 @@ namespace hex::pl {
public: public:
std::vector<ASTNode *> m_statements; std::vector<ASTNode *> m_statements;
bool m_newScope; bool m_newScope = false;
}; };
}; };

View 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;
};
}

View File

@ -12,18 +12,16 @@ namespace hex::pl {
class Lexer { class Lexer {
public: public:
using LexerError = std::pair<u32, std::string>;
Lexer() = default; Lexer() = default;
std::optional<std::vector<Token>> lex(const std::string &code); 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: private:
std::optional<LexerError> m_error; std::optional<PatternLanguageError> m_error;
[[noreturn]] void throwLexerError(const std::string &error, u32 lineNumber) const { [[noreturn]] static void throwLexerError(const std::string &error, u32 lineNumber) {
throw LexerError(lineNumber, "Lexer: " + error); throw PatternLanguageError(lineNumber, "Lexer: " + error);
} }
}; };

View File

@ -8,6 +8,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <hex/pattern_language/error.hpp>
namespace hex::pl { namespace hex::pl {
class ASTNode; class ASTNode;
@ -23,8 +25,6 @@ namespace hex::pl {
[[nodiscard]] const auto &getLog() const { return this->m_consoleLog; } [[nodiscard]] const auto &getLog() const { return this->m_consoleLog; }
using EvaluateError = std::pair<u32, std::string>;
void log(Level level, const std::string &message); void log(Level level, const std::string &message);
[[noreturn]] static void abortEvaluation(const std::string &message); [[noreturn]] static void abortEvaluation(const std::string &message);
@ -33,13 +33,13 @@ namespace hex::pl {
void clear(); 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: private:
std::vector<std::pair<Level, std::string>> m_consoleLog; std::vector<std::pair<Level, std::string>> m_consoleLog;
std::optional<EvaluateError> m_lastHardError; std::optional<PatternLanguageError> m_lastHardError;
}; };
} }

View File

@ -3,6 +3,7 @@
#include <hex.hpp> #include <hex.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/pattern_language/error.hpp>
#include <hex/pattern_language/token.hpp> #include <hex/pattern_language/token.hpp>
#include <hex/pattern_language/ast_node.hpp> #include <hex/pattern_language/ast_node.hpp>
@ -16,16 +17,15 @@ namespace hex::pl {
class Parser { class Parser {
public: public:
using TokenIter = std::vector<Token>::const_iterator; using TokenIter = std::vector<Token>::const_iterator;
using ParseError = std::pair<u32, std::string>;
Parser() = default; Parser() = default;
~Parser() = default; ~Parser() = default;
std::optional<std::vector<ASTNode *>> parse(const std::vector<Token> &tokens); 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: private:
std::optional<ParseError> m_error; std::optional<PatternLanguageError> m_error;
TokenIter m_curr; TokenIter m_curr;
TokenIter m_originalPosition, m_partOriginalPosition; TokenIter m_originalPosition, m_partOriginalPosition;
@ -47,7 +47,7 @@ namespace hex::pl {
auto value = std::get_if<T>(&this->m_curr[index].value); auto value = std::get_if<T>(&this->m_curr[index].value);
if (value == nullptr) if (value == nullptr)
throwParseError("failed to decode token. Invalid type.", getLineNumber(index)); throwParserError("failed to decode token. Invalid type.", getLineNumber(index));
return *value; return *value;
} }
@ -143,8 +143,8 @@ namespace hex::pl {
return program; return program;
} }
[[noreturn]] void throwParseError(const std::string &error, i32 token = -1) const { [[noreturn]] void throwParserError(const std::string &error, i32 token = -1) const {
throw ParseError(this->m_curr[token].lineNumber, "Parser: " + error); throw PatternLanguageError(this->m_curr[token].lineNumber, "Parser: " + error);
} }
/* Token consuming */ /* Token consuming */

View File

@ -73,11 +73,16 @@ namespace hex::pl {
PatternCreationLimiter::s_evaluator->patternDestroyed(); PatternCreationLimiter::s_evaluator->patternDestroyed();
} }
[[nodiscard]]
static Evaluator *getEvaluator() {
return PatternCreationLimiter::s_evaluator;
}
public: public:
static Evaluator *s_evaluator; static Evaluator *s_evaluator;
}; };
class PatternData : public PatternCreationLimiter { class PatternData : public PatternCreationLimiter, public Cloneable<PatternData> {
public: public:
PatternData(u64 offset, size_t size, u32 color = 0) PatternData(u64 offset, size_t size, u32 color = 0)
: PatternCreationLimiter(), m_offset(offset), m_size(size), m_color(color) { : PatternCreationLimiter(), m_offset(offset), m_size(size), m_color(color) {
@ -95,9 +100,7 @@ namespace hex::pl {
PatternData(const PatternData &other) = default; PatternData(const PatternData &other) = default;
virtual ~PatternData() = default; ~PatternData() override = default;
virtual PatternData *clone() = 0;
[[nodiscard]] u64 getOffset() const { return this->m_offset; } [[nodiscard]] u64 getOffset() const { return this->m_offset; }
virtual void setOffset(u64 offset) { this->m_offset = 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]] bool hasOverriddenColor() const { return this->m_manualColor; }
[[nodiscard]] std::endian getEndian() const { [[nodiscard]] std::endian getEndian() const {
if (this->getEvaluator() == nullptr) return std::endian::native; if (PatternData::getEvaluator() == nullptr) return std::endian::native;
else return this->m_endian.value_or(this->getEvaluator()->getDefaultEndian()); else return this->m_endian.value_or(PatternData::getEvaluator()->getDefaultEndian());
} }
virtual void setEndian(std::endian endian) { this->m_endian = endian; } virtual void setEndian(std::endian endian) { this->m_endian = endian; }
[[nodiscard]] bool hasOverriddenEndian() const { return this->m_endian.has_value(); } [[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); } [[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 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; } [[nodiscard]] const auto &getTransformFunction() const { return this->m_transformFunction; }
void setTransformFunction(const ContentRegistry::PatternLanguage::Function &function) { this->m_transformFunction = function; } void setTransformFunction(const ContentRegistry::PatternLanguage::Function &function) { this->m_transformFunction = function; }
[[nodiscard]] const auto &getFormatterFunction() const { return this->m_formatterFunction; } [[nodiscard]] const auto &getFormatterFunction() const { return this->m_formatterFunction; }
@ -154,7 +155,7 @@ namespace hex::pl {
for (u64 i = 0; i < this->getSize(); i++) for (u64 i = 0; i < this->getSize(); i++)
highlight.insert({ this->getOffset() + i, this->getColor() }); highlight.insert({ this->getOffset() + i, this->getColor() });
this->getEvaluator()->handleAbort(); PatternData::getEvaluator()->handleAbort();
} }
virtual void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) { } virtual void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) { }
@ -255,7 +256,7 @@ namespace hex::pl {
return value; return value;
else { else {
try { try {
auto result = this->m_formatterFunction->func(this->getEvaluator(), { literal }); auto result = this->m_formatterFunction->func(PatternData::getEvaluator(), { literal });
if (result.has_value()) { if (result.has_value()) {
if (auto displayValue = std::get_if<std::string>(&result.value()); displayValue != nullptr) if (auto displayValue = std::get_if<std::string>(&result.value()); displayValue != nullptr)
@ -265,8 +266,8 @@ namespace hex::pl {
} else { } else {
return "???"; return "???";
} }
} catch (LogConsole::EvaluateError &error) { } catch (PatternLanguageError &error) {
return "Error: " + error.second; return "Error: "s + error.what();
} }
} }
} }
@ -307,10 +308,10 @@ namespace hex::pl {
bool m_hidden = false; bool m_hidden = false;
private: private:
u64 m_offset; u64 m_offset = 0x00;
size_t m_size; size_t m_size = 0x00;
u32 m_color; u32 m_color = 0x00;
std::optional<std::string> m_displayName; std::optional<std::string> m_displayName;
std::string m_variableName; std::string m_variableName;
std::optional<std::string> m_comment; std::optional<std::string> m_comment;
@ -327,7 +328,8 @@ namespace hex::pl {
public: public:
PatternDataPadding(u64 offset, size_t size) : PatternData(offset, size, 0xFF000000) { } PatternDataPadding(u64 offset, size_t size) : PatternData(offset, size, 0xFF000000) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataPadding(*this); return new PatternDataPadding(*this);
} }
@ -355,7 +357,8 @@ namespace hex::pl {
delete this->m_pointedAt; delete this->m_pointedAt;
} }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataPointer(*this); return new PatternDataPointer(*this);
} }
@ -476,7 +479,8 @@ namespace hex::pl {
PatternDataUnsigned(u64 offset, size_t size, u32 color = 0) PatternDataUnsigned(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { } : PatternData(offset, size, color) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataUnsigned(*this); return new PatternDataUnsigned(*this);
} }
@ -513,7 +517,8 @@ namespace hex::pl {
PatternDataSigned(u64 offset, size_t size, u32 color = 0) PatternDataSigned(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { } : PatternData(offset, size, color) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataSigned(*this); return new PatternDataSigned(*this);
} }
@ -551,7 +556,8 @@ namespace hex::pl {
PatternDataFloat(u64 offset, size_t size, u32 color = 0) PatternDataFloat(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { } : PatternData(offset, size, color) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataFloat(*this); return new PatternDataFloat(*this);
} }
@ -590,7 +596,8 @@ namespace hex::pl {
explicit PatternDataBoolean(u64 offset, u32 color = 0) explicit PatternDataBoolean(u64 offset, u32 color = 0)
: PatternData(offset, 1, color) { } : PatternData(offset, 1, color) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataBoolean(*this); return new PatternDataBoolean(*this);
} }
@ -618,7 +625,8 @@ namespace hex::pl {
explicit PatternDataCharacter(u64 offset, u32 color = 0) explicit PatternDataCharacter(u64 offset, u32 color = 0)
: PatternData(offset, 1, color) { } : PatternData(offset, 1, color) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataCharacter(*this); return new PatternDataCharacter(*this);
} }
@ -641,7 +649,8 @@ namespace hex::pl {
explicit PatternDataCharacter16(u64 offset, u32 color = 0) explicit PatternDataCharacter16(u64 offset, u32 color = 0)
: PatternData(offset, 2, color) { } : PatternData(offset, 2, color) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataCharacter16(*this); return new PatternDataCharacter16(*this);
} }
@ -674,7 +683,8 @@ namespace hex::pl {
PatternDataString(u64 offset, size_t size, u32 color = 0) PatternDataString(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { } : PatternData(offset, size, color) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataString(*this); return new PatternDataString(*this);
} }
@ -714,7 +724,8 @@ namespace hex::pl {
PatternDataString16(u64 offset, size_t size, u32 color = 0) PatternDataString16(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { } : PatternData(offset, size, color) { }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataString16(*this); return new PatternDataString16(*this);
} }
@ -780,7 +791,8 @@ namespace hex::pl {
delete entry; delete entry;
} }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataDynamicArray(*this); return new PatternDataDynamicArray(*this);
} }
@ -893,7 +905,7 @@ namespace hex::pl {
[[nodiscard]] const PatternData *getPattern(u64 offset) const override { [[nodiscard]] const PatternData *getPattern(u64 offset) const override {
if (this->isHidden()) return nullptr; 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()); return offset >= pattern->getOffset() && offset < (pattern->getOffset() + pattern->getSize());
}); });
@ -932,7 +944,8 @@ namespace hex::pl {
delete this->m_highlightTemplate; delete this->m_highlightTemplate;
} }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataStaticArray(*this); return new PatternDataStaticArray(*this);
} }
@ -1067,9 +1080,9 @@ namespace hex::pl {
} }
private: private:
PatternData *m_template; PatternData *m_template = nullptr;
mutable PatternData *m_highlightTemplate; mutable PatternData *m_highlightTemplate = nullptr;
size_t m_entryCount; size_t m_entryCount = 0;
u64 m_displayEnd = 50; u64 m_displayEnd = 50;
}; };
@ -1091,7 +1104,8 @@ namespace hex::pl {
delete member; delete member;
} }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataStruct(*this); return new PatternDataStruct(*this);
} }
@ -1238,7 +1252,8 @@ namespace hex::pl {
delete member; delete member;
} }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataUnion(*this); return new PatternDataUnion(*this);
} }
@ -1375,7 +1390,8 @@ namespace hex::pl {
: PatternData(offset, size, color) { : PatternData(offset, size, color) {
} }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataEnum(*this); return new PatternDataEnum(*this);
} }
@ -1398,7 +1414,7 @@ namespace hex::pl {
return false; return false;
}, },
[](std::string) { return false; }, [](std::string&) { return false; },
[](PatternData *) { return false; } }, [](PatternData *) { return false; } },
entryValueLiteral); entryValueLiteral);
if (matches) if (matches)
@ -1470,7 +1486,8 @@ namespace hex::pl {
: m_bitOffset(bitOffset), m_bitSize(bitSize), m_bitField(bitField), PatternData(offset, 0, color) { : 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); return new PatternDataBitfieldField(*this);
} }
@ -1549,7 +1566,8 @@ namespace hex::pl {
delete field; delete field;
} }
PatternData *clone() override { [[nodiscard]]
PatternData *clone() const override {
return new PatternDataBitfield(*this); return new PatternDataBitfield(*this);
} }

View File

@ -40,7 +40,7 @@ namespace hex::pl {
void abort(); void abort();
[[nodiscard]] const std::vector<std::pair<LogConsole::Level, std::string>> &getConsoleLog(); [[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]] std::map<std::string, Token::Literal> getOutVariables() const;
[[nodiscard]] u32 getCreatedPatternCount(); [[nodiscard]] u32 getCreatedPatternCount();
@ -58,7 +58,7 @@ namespace hex::pl {
std::vector<ASTNode *> m_currAST; std::vector<ASTNode *> m_currAST;
std::optional<std::pair<u32, std::string>> m_currError; std::optional<PatternLanguageError> m_currError;
}; };
} }

View File

@ -11,24 +11,24 @@
#include <hex/helpers/paths.hpp> #include <hex/helpers/paths.hpp>
#include <hex/pattern_language/error.hpp>
namespace hex::pl { namespace hex::pl {
class Preprocessor { class Preprocessor {
public: public:
Preprocessor(); Preprocessor() = default;
std::optional<std::string> preprocess(const std::string &code, bool initialRun = true); 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 addPragmaHandler(const std::string &pragmaType, const std::function<bool(const std::string &)> &function);
void addDefaultPragmaHandlers(); void addDefaultPragmaHandlers();
const std::pair<u32, std::string> &getError() { return this->m_error; } const std::optional<PatternLanguageError> &getError() { return this->m_error; }
private: private:
using PreprocessorError = std::pair<u32, std::string>; [[noreturn]] static void throwPreprocessorError(const std::string &error, u32 lineNumber) {
throw PatternLanguageError(lineNumber, "Preprocessor: " + error);
[[noreturn]] void throwPreprocessorError(const std::string &error, u32 lineNumber) const {
throw PreprocessorError(lineNumber, "Preprocessor: " + error);
} }
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers; 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::set<fs::path> m_onceIncludedFiles;
std::pair<u32, std::string> m_error; std::optional<PatternLanguageError> m_error;
}; };
} }

View File

@ -7,6 +7,7 @@
#include <variant> #include <variant>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/pattern_language/log_console.hpp>
namespace hex::pl { namespace hex::pl {
@ -156,48 +157,48 @@ namespace hex::pl {
static u128 literalToUnsigned(const pl::Token::Literal &literal) { static u128 literalToUnsigned(const pl::Token::Literal &literal) {
return std::visit(overloaded { return std::visit(overloaded {
[](std::string) -> u128 { throw std::string("expected integral type, got string"); }, [](const std::string &) -> u128 { LogConsole::abortEvaluation("expected integral type, got string"); },
[](PatternData *) -> u128 { throw std::string("expected integral type, got custom type"); }, [](PatternData *) -> u128 { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&value) -> u128 { return value; } }, [](auto &&result) -> u128 { return result; } },
literal); literal);
} }
static i128 literalToSigned(const pl::Token::Literal &literal) { static i128 literalToSigned(const pl::Token::Literal &literal) {
return std::visit(overloaded { return std::visit(overloaded {
[](std::string) -> i128 { throw std::string("expected integral type, got string"); }, [](const std::string &) -> i128 { LogConsole::abortEvaluation("expected integral type, got string"); },
[](PatternData *) -> i128 { throw std::string("expected integral type, got custom type"); }, [](PatternData *) -> i128 { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&value) -> i128 { return value; } }, [](auto &&result) -> i128 { return result; } },
literal); literal);
} }
static double literalToFloatingPoint(const pl::Token::Literal &literal) { static double literalToFloatingPoint(const pl::Token::Literal &literal) {
return std::visit(overloaded { return std::visit(overloaded {
[](std::string) -> double { throw std::string("expected integral type, got string"); }, [](const std::string &) -> double { LogConsole::abortEvaluation("expected integral type, got string"); },
[](PatternData *) -> double { throw std::string("expected integral type, got custom type"); }, [](PatternData *) -> double { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&value) -> double { return value; } }, [](auto &&result) -> double { return result; } },
literal); literal);
} }
static bool literalToBoolean(const pl::Token::Literal &literal) { static bool literalToBoolean(const pl::Token::Literal &literal) {
return std::visit(overloaded { return std::visit(overloaded {
[](std::string) -> bool { throw std::string("expected integral type, got string"); }, [](const std::string &) -> bool { LogConsole::abortEvaluation("expected integral type, got string"); },
[](PatternData *) -> bool { throw std::string("expected integral type, got custom type"); }, [](PatternData *) -> bool { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&value) -> bool { return value != 0; } }, [](auto &&result) -> bool { return result != 0; } },
literal); literal);
} }
static std::string literalToString(const pl::Token::Literal &literal, bool cast) { static std::string literalToString(const pl::Token::Literal &literal, bool cast) {
if (!cast && std::get_if<std::string>(&literal) == nullptr) 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 { return std::visit(overloaded {
[](std::string value) -> std::string { return value; }, [](std::string result) -> std::string { return result; },
[](u128 value) -> std::string { return std::to_string(u64(value)); }, [](u128 result) -> std::string { return hex::to_string(result); },
[](i128 value) -> std::string { return std::to_string(i64(value)); }, [](i128 result) -> std::string { return hex::to_string(result); },
[](bool value) -> std::string { return value ? "true" : "false"; }, [](bool result) -> std::string { return result ? "true" : "false"; },
[](char value) -> std::string { return std::string() + value; }, [](char result) -> std::string { return { 1, result }; },
[](PatternData *) -> std::string { throw std::string("expected integral type, got custom type"); }, [](PatternData *) -> std::string { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&value) -> std::string { return std::to_string(value); } }, [](auto &&result) -> std::string { return std::to_string(result); } },
literal); literal);
} }

View File

@ -2,28 +2,29 @@
#include <hex.hpp> #include <hex.hpp>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <hex/pattern_language/error.hpp>
namespace hex::pl { namespace hex::pl {
class ASTNode; class ASTNode;
class Validator { class Validator {
public: public:
Validator(); Validator() = default;
bool validate(const std::vector<ASTNode *> &ast); 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: private:
std::pair<u32, std::string> m_error; std::optional<PatternLanguageError> m_error;
using ValidatorError = std::pair<u32, std::string>; [[noreturn]] static void throwValidatorError(const std::string &error, u32 lineNumber) {
throw PatternLanguageError(lineNumber, "Validator: " + error);
[[noreturn]] void throwValidateError(std::string_view error, u32 lineNumber) const {
throw ValidatorError(lineNumber, error);
} }
}; };

View File

@ -206,10 +206,10 @@ namespace hex::pl {
} }
popScope(); popScope();
} catch (const LogConsole::EvaluateError &error) { } catch (PatternLanguageError &error) {
this->m_console.log(LogConsole::Level::Error, error.second); this->m_console.log(LogConsole::Level::Error, error.what());
if (error.first != 0) if (error.getLineNumber() != 0)
this->m_console.setHardError(error); this->m_console.setHardError(error);
for (auto &pattern : patterns) for (auto &pattern : patterns)

View File

@ -10,7 +10,7 @@ namespace hex::pl {
#define TOKEN(type, value) Token::Type::type, Token::type::value, lineNumber #define TOKEN(type, value) Token::Type::type, Token::type::value, lineNumber
#define VALUE_TOKEN(type, value) Token::Type::type, value, lineNumber #define VALUE_TOKEN(type, value) Token::Type::type, value, lineNumber
std::string matchTillInvalid(const char *characters, std::function<bool(char)> predicate) { std::string matchTillInvalid(const char *characters, const std::function<bool(char)> &predicate) {
std::string ret; std::string ret;
while (*characters != 0x00) { while (*characters != 0x00) {
@ -403,14 +403,14 @@ namespace hex::pl {
tokens.emplace_back(TOKEN(Operator, SizeOf)); tokens.emplace_back(TOKEN(Operator, SizeOf));
offset += 6; offset += 6;
} else if (c == '\'') { } else if (c == '\'') {
auto character = getCharacterLiteral(code.substr(offset)); auto lexedCharacter = getCharacterLiteral(code.substr(offset));
if (!character.has_value()) if (!lexedCharacter.has_value())
throwLexerError("invalid character literal", lineNumber); throwLexerError("invalid character literal", lineNumber);
auto [c, charSize] = character.value(); auto [character, charSize] = lexedCharacter.value();
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(c))); tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(character)));
offset += charSize; offset += charSize;
} else if (c == '\"') { } else if (c == '\"') {
auto string = getStringLiteral(code.substr(offset)); auto string = getStringLiteral(code.substr(offset));
@ -530,9 +530,10 @@ namespace hex::pl {
} }
tokens.emplace_back(TOKEN(Separator, EndOfProgram)); tokens.emplace_back(TOKEN(Separator, EndOfProgram));
} catch (LexerError &e) { } catch (PatternLanguageError &e) {
this->m_error = e; this->m_error = e;
return {};
return std::nullopt;
} }

View File

@ -9,14 +9,14 @@ namespace hex::pl {
} }
[[noreturn]] void LogConsole::abortEvaluation(const std::string &message) { [[noreturn]] void LogConsole::abortEvaluation(const std::string &message) {
throw EvaluateError(0, message); throw PatternLanguageError(0, message);
} }
[[noreturn]] void LogConsole::abortEvaluation(const std::string &message, const ASTNode *node) { [[noreturn]] void LogConsole::abortEvaluation(const std::string &message, const ASTNode *node) {
if (node == nullptr) if (node == nullptr)
abortEvaluation(message); abortEvaluation(message);
else else
throw EvaluateError(node->getLineNumber(), message); throw PatternLanguageError(node->getLineNumber(), message);
} }
void LogConsole::clear() { void LogConsole::clear() {

View File

@ -20,7 +20,7 @@ namespace hex::pl {
std::string functionName = parseNamespaceResolution(); std::string functionName = parseNamespaceResolution();
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN))) if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN)))
throwParseError("expected '(' after function name"); throwParserError("expected '(' after function name");
std::vector<ASTNode *> params; std::vector<ASTNode *> params;
auto paramCleanup = SCOPE_GUARD { auto paramCleanup = SCOPE_GUARD {
@ -32,11 +32,11 @@ namespace hex::pl {
params.push_back(parseMathematicalExpression()); params.push_back(parseMathematicalExpression());
if (MATCHES(sequence(SEPARATOR_COMMA, SEPARATOR_ROUNDBRACKETCLOSE))) if (MATCHES(sequence(SEPARATOR_COMMA, SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("unexpected ',' at end of function parameter list", -1); throwParserError("unexpected ',' at end of function parameter list", -1);
else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
break; break;
else if (!MATCHES(sequence(SEPARATOR_COMMA))) else if (!MATCHES(sequence(SEPARATOR_COMMA)))
throwParseError("missing ',' between parameters", -1); throwParserError("missing ',' between parameters", -1);
} }
paramCleanup.release(); paramCleanup.release();
@ -76,7 +76,7 @@ namespace hex::pl {
continue; continue;
} else { } else {
if (!this->m_types.contains(typeName)) if (!this->m_types.contains(typeName))
throwParseError(hex::format("cannot access scope of invalid type '{}'", typeName), -1); throwParserError(hex::format("cannot access scope of invalid type '{}'", typeName), -1);
return create(new ASTNodeScopeResolution(this->m_types[typeName]->clone(), getValue<Token::Identifier>(-1).get())); return create(new ASTNodeScopeResolution(this->m_types[typeName]->clone(), getValue<Token::Identifier>(-1).get()));
} }
@ -84,7 +84,7 @@ namespace hex::pl {
break; break;
} }
throwParseError("failed to parse scope resolution. Expected 'TypeName::Identifier'"); throwParserError("failed to parse scope resolution. Expected 'TypeName::Identifier'");
} }
ASTNode *Parser::parseRValue() { ASTNode *Parser::parseRValue() {
@ -104,14 +104,14 @@ namespace hex::pl {
if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN))) { if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN))) {
path.push_back(parseMathematicalExpression()); path.push_back(parseMathematicalExpression());
if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE)))
throwParseError("expected closing ']' at end of array indexing"); throwParserError("expected closing ']' at end of array indexing");
} }
if (MATCHES(sequence(SEPARATOR_DOT))) { if (MATCHES(sequence(SEPARATOR_DOT))) {
if (MATCHES(oneOf(IDENTIFIER, KEYWORD_PARENT))) if (MATCHES(oneOf(IDENTIFIER, KEYWORD_PARENT)))
return this->parseRValue(path); return this->parseRValue(path);
else else
throwParseError("expected member name or 'parent' keyword", -1); throwParserError("expected member name or 'parent' keyword", -1);
} else } else
return create(new ASTNodeRValue(path)); return create(new ASTNodeRValue(path));
} }
@ -126,7 +126,7 @@ namespace hex::pl {
auto node = this->parseMathematicalExpression(); auto node = this->parseMathematicalExpression();
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) { if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
delete node; delete node;
throwParseError("expected closing parenthesis"); throwParserError("expected closing parenthesis");
} }
return node; return node;
} else if (MATCHES(sequence(IDENTIFIER))) { } else if (MATCHES(sequence(IDENTIFIER))) {
@ -159,17 +159,17 @@ namespace hex::pl {
result = new ASTNodeLiteral(u128(Token::getTypeSize(type))); result = new ASTNodeLiteral(u128(Token::getTypeSize(type)));
} else { } else {
throwParseError("expected rvalue identifier or built-in type"); throwParserError("expected rvalue identifier or built-in type");
} }
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) { if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
delete result; delete result;
throwParseError("expected closing parenthesis"); throwParserError("expected closing parenthesis");
} }
return result; return result;
} else } else
throwParseError("expected value or parenthesis"); throwParserError("expected value or parenthesis");
} }
ASTNode *Parser::parseCastExpression() { ASTNode *Parser::parseCastExpression() {
@ -178,10 +178,10 @@ namespace hex::pl {
auto builtinType = dynamic_cast<ASTNodeBuiltinType *>(type->getType()); auto builtinType = dynamic_cast<ASTNodeBuiltinType *>(type->getType());
if (builtinType == nullptr) if (builtinType == nullptr)
throwParseError("invalid type used for pointer size", -1); throwParserError("invalid type used for pointer size", -1);
if (!peek(SEPARATOR_ROUNDBRACKETOPEN)) if (!peek(SEPARATOR_ROUNDBRACKETOPEN))
throwParseError("expected '(' before cast expression", -1); throwParserError("expected '(' before cast expression", -1);
auto node = parseFactor(); auto node = parseFactor();
@ -382,7 +382,7 @@ namespace hex::pl {
auto second = this->parseBooleanOr(); auto second = this->parseBooleanOr();
if (!MATCHES(sequence(OPERATOR_INHERIT))) if (!MATCHES(sequence(OPERATOR_INHERIT)))
throwParseError("expected ':' in ternary expression"); throwParserError("expected ':' in ternary expression");
auto third = this->parseBooleanOr(); auto third = this->parseBooleanOr();
node = create(new ASTNodeTernaryExpression(node, second, third, Token::Operator::TernaryConditional)); node = create(new ASTNodeTernaryExpression(node, second, third, Token::Operator::TernaryConditional));
@ -401,11 +401,11 @@ namespace hex::pl {
// [[ <Identifier[( (parseStringLiteral) )], ...> ]] // [[ <Identifier[( (parseStringLiteral) )], ...> ]]
void Parser::parseAttribute(Attributable *currNode) { void Parser::parseAttribute(Attributable *currNode) {
if (currNode == nullptr) if (currNode == nullptr)
throwParseError("tried to apply attribute to invalid statement"); throwParserError("tried to apply attribute to invalid statement");
do { do {
if (!MATCHES(sequence(IDENTIFIER))) if (!MATCHES(sequence(IDENTIFIER)))
throwParseError("expected attribute expression"); throwParserError("expected attribute expression");
auto attribute = getValue<Token::Identifier>(-1).get(); auto attribute = getValue<Token::Identifier>(-1).get();
@ -414,7 +414,7 @@ namespace hex::pl {
auto string = std::get_if<std::string>(&value); auto string = std::get_if<std::string>(&value);
if (string == nullptr) if (string == nullptr)
throwParseError("expected string attribute argument"); throwParserError("expected string attribute argument");
currNode->addAttribute(create(new ASTNodeAttribute(attribute, *string))); currNode->addAttribute(create(new ASTNodeAttribute(attribute, *string)));
} else } else
@ -423,7 +423,7 @@ namespace hex::pl {
} while (MATCHES(sequence(SEPARATOR_COMMA))); } while (MATCHES(sequence(SEPARATOR_COMMA)));
if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE, SEPARATOR_SQUAREBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE, SEPARATOR_SQUAREBRACKETCLOSE)))
throwParseError("unfinished attribute. Expected ']]'"); throwParserError("unfinished attribute. Expected ']]'");
} }
/* Functions */ /* Functions */
@ -441,7 +441,7 @@ namespace hex::pl {
parameterPack = getValue<Token::Identifier>(-1).get(); parameterPack = getValue<Token::Identifier>(-1).get();
if (MATCHES(sequence(SEPARATOR_COMMA))) if (MATCHES(sequence(SEPARATOR_COMMA)))
throwParseError("parameter pack can only appear at end of parameter list"); throwParserError("parameter pack can only appear at end of parameter list");
break; break;
} else { } else {
@ -461,10 +461,10 @@ namespace hex::pl {
} }
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("expected closing ')' after parameter list"); throwParserError("expected closing ')' after parameter list");
if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN)))
throwParseError("expected opening '{' after function definition"); throwParserError("expected opening '{' after function definition");
// Parse function body // Parse function body
@ -496,7 +496,7 @@ namespace hex::pl {
statement = create(new ASTNodeCompoundStatement({ statement, create(new ASTNodeAssignment(identifier, expression)) })); statement = create(new ASTNodeCompoundStatement({ statement, create(new ASTNodeAssignment(identifier, expression)) }));
} }
} else } else
throwParseError("invalid variable declaration"); throwParserError("invalid variable declaration");
return statement; return statement;
} }
@ -539,11 +539,11 @@ namespace hex::pl {
} else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY)) { } else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY)) {
statement = parseFunctionVariableDecl(); statement = parseFunctionVariableDecl();
} else } else
throwParseError("invalid sequence", 0); throwParserError("invalid sequence", 0);
if (needsSemicolon && !MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) { if (needsSemicolon && !MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) {
delete statement; delete statement;
throwParseError("missing ';' at end of expression", -1); throwParserError("missing ';' at end of expression", -1);
} }
// Consume superfluous semicolons // Consume superfluous semicolons
@ -576,7 +576,7 @@ namespace hex::pl {
else if (peek(KEYWORD_CONTINUE, -1)) else if (peek(KEYWORD_CONTINUE, -1))
type = ControlFlowStatement::Continue; type = ControlFlowStatement::Continue;
else else
throwParseError("invalid control flow statement. Expected 'return', 'break' or 'continue'"); throwParserError("invalid control flow statement. Expected 'return', 'break' or 'continue'");
if (peek(SEPARATOR_ENDOFEXPRESSION)) if (peek(SEPARATOR_ENDOFEXPRESSION))
return create(new ASTNodeControlFlowStatement(type, nullptr)); return create(new ASTNodeControlFlowStatement(type, nullptr));
@ -618,7 +618,7 @@ namespace hex::pl {
}; };
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("expected closing ')' after statement head"); throwParserError("expected closing ')' after statement head");
trueBody = parseStatementBody(); trueBody = parseStatementBody();
@ -641,7 +641,7 @@ namespace hex::pl {
}; };
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("expected closing ')' after statement head"); throwParserError("expected closing ')' after statement head");
body = parseStatementBody(); body = parseStatementBody();
@ -655,16 +655,16 @@ namespace hex::pl {
auto variableCleanup = SCOPE_GUARD { delete variable; }; auto variableCleanup = SCOPE_GUARD { delete variable; };
if (!MATCHES(sequence(SEPARATOR_COMMA))) if (!MATCHES(sequence(SEPARATOR_COMMA)))
throwParseError("expected ',' after for loop variable declaration"); throwParserError("expected ',' after for loop variable declaration");
auto condition = parseMathematicalExpression(); auto condition = parseMathematicalExpression();
auto conditionCleanup = SCOPE_GUARD { delete condition; }; auto conditionCleanup = SCOPE_GUARD { delete condition; };
if (!MATCHES(sequence(SEPARATOR_COMMA))) if (!MATCHES(sequence(SEPARATOR_COMMA)))
throwParseError("expected ',' after for loop condition"); throwParserError("expected ',' after for loop condition");
if (!MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) if (!MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT)))
throwParseError("expected for loop variable assignment"); throwParserError("expected for loop variable assignment");
auto postExpression = parseFunctionVariableAssignment(getValue<Token::Identifier>(-2).get()); auto postExpression = parseFunctionVariableAssignment(getValue<Token::Identifier>(-2).get());
auto postExpressionCleanup = SCOPE_GUARD { delete postExpression; }; auto postExpressionCleanup = SCOPE_GUARD { delete postExpression; };
@ -677,7 +677,7 @@ namespace hex::pl {
}; };
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("expected closing ')' after statement head"); throwParserError("expected closing ')' after statement head");
body = parseStatementBody(); body = parseStatementBody();
@ -711,7 +711,7 @@ namespace hex::pl {
} else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) { } else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
trueBody.push_back(parseMember()); trueBody.push_back(parseMember());
} else } else
throwParseError("expected body of conditional statement"); throwParserError("expected body of conditional statement");
if (MATCHES(sequence(KEYWORD_ELSE, SEPARATOR_CURLYBRACKETOPEN))) { if (MATCHES(sequence(KEYWORD_ELSE, SEPARATOR_CURLYBRACKETOPEN))) {
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
@ -735,7 +735,7 @@ namespace hex::pl {
}; };
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("expected closing ')' after while head"); throwParserError("expected closing ')' after while head");
cleanup.release(); cleanup.release();
@ -761,18 +761,18 @@ namespace hex::pl {
else if (this->m_types.contains(getNamespacePrefixedName(typeName))) else if (this->m_types.contains(getNamespacePrefixedName(typeName)))
return create(new ASTNodeTypeDecl({}, this->m_types[getNamespacePrefixedName(typeName)]->clone(), endian)); return create(new ASTNodeTypeDecl({}, this->m_types[getNamespacePrefixedName(typeName)]->clone(), endian));
else else
throwParseError(hex::format("unknown type '{}'", typeName)); throwParserError(hex::format("unknown type '{}'", typeName));
} else if (MATCHES(sequence(VALUETYPE_ANY))) { // Builtin type } else if (MATCHES(sequence(VALUETYPE_ANY))) { // Builtin type
auto type = getValue<Token::ValueType>(-1); auto type = getValue<Token::ValueType>(-1);
if (!allowFunctionTypes) { if (!allowFunctionTypes) {
if (type == Token::ValueType::String) if (type == Token::ValueType::String)
throwParseError("cannot use 'str' in this context. Use a character array instead"); throwParserError("cannot use 'str' in this context. Use a character array instead");
else if (type == Token::ValueType::Auto) else if (type == Token::ValueType::Auto)
throwParseError("cannot use 'auto' in this context"); throwParserError("cannot use 'auto' in this context");
} }
return create(new ASTNodeTypeDecl({}, new ASTNodeBuiltinType(type), endian)); return create(new ASTNodeTypeDecl({}, new ASTNodeBuiltinType(type), endian));
} else throwParseError("failed to parse type. Expected identifier or builtin type"); } else throwParserError("failed to parse type. Expected identifier or builtin type");
} }
// using Identifier = (parseType) // using Identifier = (parseType)
@ -780,10 +780,10 @@ namespace hex::pl {
auto name = parseNamespaceResolution(); auto name = parseNamespaceResolution();
if (!MATCHES(sequence(OPERATOR_ASSIGNMENT))) if (!MATCHES(sequence(OPERATOR_ASSIGNMENT)))
throwParseError("expected '=' after type name of using declaration"); throwParserError("expected '=' after type name of using declaration");
auto *type = dynamic_cast<ASTNodeTypeDecl *>(parseType()); auto *type = dynamic_cast<ASTNodeTypeDecl *>(parseType());
if (type == nullptr) throwParseError("invalid type used in variable declaration", -1); if (type == nullptr) throwParserError("invalid type used in variable declaration", -1);
return addType(name, type, type->getEndian()); return addType(name, type, type->getEndian());
} }
@ -794,7 +794,7 @@ namespace hex::pl {
if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) { if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) {
delete size; delete size;
throwParseError("expected closing ']' at end of array declaration", -1); throwParserError("expected closing ']' at end of array declaration", -1);
} }
return create(new ASTNodeArrayVariableDecl({}, new ASTNodeTypeDecl({}, new ASTNodeBuiltinType(Token::ValueType::Padding)), size)); return create(new ASTNodeArrayVariableDecl({}, new ASTNodeTypeDecl({}, new ASTNodeBuiltinType(Token::ValueType::Padding)), size));
@ -835,7 +835,7 @@ namespace hex::pl {
size = parseMathematicalExpression(); size = parseMathematicalExpression();
if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE)))
throwParseError("expected closing ']' at end of array declaration", -1); throwParserError("expected closing ']' at end of array declaration", -1);
} }
sizeCleanup.release(); sizeCleanup.release();
@ -853,7 +853,7 @@ namespace hex::pl {
auto builtinType = dynamic_cast<ASTNodeBuiltinType *>(sizeType->getType()); auto builtinType = dynamic_cast<ASTNodeBuiltinType *>(sizeType->getType());
if (builtinType == nullptr || !Token::isUnsigned(builtinType->getType())) if (builtinType == nullptr || !Token::isUnsigned(builtinType->getType()))
throwParseError("invalid type used for pointer size", -1); throwParserError("invalid type used for pointer size", -1);
} }
return create(new ASTNodePointerVariableDecl(name, type, sizeType)); return create(new ASTNodePointerVariableDecl(name, type, sizeType));
@ -893,14 +893,14 @@ namespace hex::pl {
else if (MATCHES(sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) else if (MATCHES(sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT)))
member = parseMemberPointerVariable(type); member = parseMemberPointerVariable(type);
else else
throwParseError("invalid variable declaration"); throwParserError("invalid variable declaration");
} }
} else if (MATCHES(sequence(VALUETYPE_PADDING, SEPARATOR_SQUAREBRACKETOPEN))) } else if (MATCHES(sequence(VALUETYPE_PADDING, SEPARATOR_SQUAREBRACKETOPEN)))
member = parsePadding(); member = parsePadding();
else if (MATCHES(sequence(KEYWORD_IF, SEPARATOR_ROUNDBRACKETOPEN))) else if (MATCHES(sequence(KEYWORD_IF, SEPARATOR_ROUNDBRACKETOPEN)))
return parseConditional(); return parseConditional();
else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM)))
throwParseError("unexpected end of program", -2); throwParserError("unexpected end of program", -2);
else if (MATCHES(sequence(KEYWORD_BREAK))) else if (MATCHES(sequence(KEYWORD_BREAK)))
member = new ASTNodeControlFlowStatement(ControlFlowStatement::Break, nullptr); member = new ASTNodeControlFlowStatement(ControlFlowStatement::Break, nullptr);
else if (MATCHES(sequence(KEYWORD_CONTINUE))) else if (MATCHES(sequence(KEYWORD_CONTINUE)))
@ -910,13 +910,13 @@ namespace hex::pl {
else if (MATCHES(oneOf(OPERATOR_DOLLAR) && oneOf(OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_STAR, OPERATOR_SLASH, OPERATOR_PERCENT, OPERATOR_SHIFTLEFT, OPERATOR_SHIFTRIGHT, OPERATOR_BITOR, OPERATOR_BITAND, OPERATOR_BITXOR) && sequence(OPERATOR_ASSIGNMENT))) else if (MATCHES(oneOf(OPERATOR_DOLLAR) && oneOf(OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_STAR, OPERATOR_SLASH, OPERATOR_PERCENT, OPERATOR_SHIFTLEFT, OPERATOR_SHIFTRIGHT, OPERATOR_BITOR, OPERATOR_BITAND, OPERATOR_BITXOR) && sequence(OPERATOR_ASSIGNMENT)))
member = parseFunctionVariableCompoundAssignment("$"); member = parseFunctionVariableCompoundAssignment("$");
else else
throwParseError("invalid struct member", 0); throwParserError("invalid struct member", 0);
if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN))) if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN)))
parseAttribute(dynamic_cast<Attributable *>(member)); parseAttribute(dynamic_cast<Attributable *>(member));
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
throwParseError("missing ';' at end of expression", -1); throwParserError("missing ';' at end of expression", -1);
// Consume superfluous semicolons // Consume superfluous semicolons
while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
@ -942,17 +942,17 @@ namespace hex::pl {
do { do {
auto inheritedTypeName = getValue<Token::Identifier>(-1).get(); auto inheritedTypeName = getValue<Token::Identifier>(-1).get();
if (!this->m_types.contains(inheritedTypeName)) if (!this->m_types.contains(inheritedTypeName))
throwParseError(hex::format("cannot inherit from unknown type '{}'", inheritedTypeName), -1); throwParserError(hex::format("cannot inherit from unknown type '{}'", inheritedTypeName), -1);
structNode->addInheritance(this->m_types[inheritedTypeName]->clone()); structNode->addInheritance(this->m_types[inheritedTypeName]->clone());
} while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER))); } while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER)));
} else if (MATCHES(sequence(OPERATOR_INHERIT, VALUETYPE_ANY))) { } else if (MATCHES(sequence(OPERATOR_INHERIT, VALUETYPE_ANY))) {
throwParseError("cannot inherit from builtin type"); throwParserError("cannot inherit from builtin type");
} }
if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN)))
throwParseError("expected '{' after struct definition", -1); throwParserError("expected '{' after struct definition", -1);
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
structNode->addMember(parseMember()); structNode->addMember(parseMember());
@ -988,7 +988,7 @@ namespace hex::pl {
auto typeName = getValue<Token::Identifier>(-2).get(); auto typeName = getValue<Token::Identifier>(-2).get();
auto underlyingType = parseType(); auto underlyingType = parseType();
if (underlyingType->getEndian().has_value()) throwParseError("underlying type may not have an endian specification", -2); if (underlyingType->getEndian().has_value()) throwParserError("underlying type may not have an endian specification", -2);
const auto enumNode = create(new ASTNodeEnum(underlyingType)); const auto enumNode = create(new ASTNodeEnum(underlyingType));
const auto typeDecl = addType(typeName, enumNode); const auto typeDecl = addType(typeName, enumNode);
@ -998,7 +998,7 @@ namespace hex::pl {
}; };
if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN)))
throwParseError("expected '{' after enum definition", -1); throwParserError("expected '{' after enum definition", -1);
ASTNode *lastEntry = nullptr; ASTNode *lastEntry = nullptr;
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
@ -1018,15 +1018,15 @@ namespace hex::pl {
enumNode->addEntry(name, valueExpr); enumNode->addEntry(name, valueExpr);
} else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) } else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM)))
throwParseError("unexpected end of program", -2); throwParserError("unexpected end of program", -2);
else else
throwParseError("invalid enum entry", -1); throwParserError("invalid enum entry", -1);
if (!MATCHES(sequence(SEPARATOR_COMMA))) { if (!MATCHES(sequence(SEPARATOR_COMMA))) {
if (MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) if (MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE)))
break; break;
else else
throwParseError("missing ',' between enum entries", -1); throwParserError("missing ',' between enum entries", -1);
} }
} }
@ -1054,12 +1054,12 @@ namespace hex::pl {
} else if (MATCHES(sequence(VALUETYPE_PADDING, OPERATOR_INHERIT))) { } else if (MATCHES(sequence(VALUETYPE_PADDING, OPERATOR_INHERIT))) {
bitfieldNode->addEntry("padding", parseMathematicalExpression()); bitfieldNode->addEntry("padding", parseMathematicalExpression());
} else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) } else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM)))
throwParseError("unexpected end of program", -2); throwParserError("unexpected end of program", -2);
else else
throwParseError("invalid bitfield member", 0); throwParserError("invalid bitfield member", 0);
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
throwParseError("missing ';' at end of expression", -1); throwParserError("missing ';' at end of expression", -1);
// Consume superfluous semicolons // Consume superfluous semicolons
while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
@ -1104,11 +1104,11 @@ namespace hex::pl {
size = parseMathematicalExpression(); size = parseMathematicalExpression();
if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE)))
throwParseError("expected closing ']' at end of array declaration", -1); throwParserError("expected closing ']' at end of array declaration", -1);
} }
if (!MATCHES(sequence(OPERATOR_AT))) if (!MATCHES(sequence(OPERATOR_AT)))
throwParseError("expected placement instruction", -1); throwParserError("expected placement instruction", -1);
auto placementOffset = parseMathematicalExpression(); auto placementOffset = parseMathematicalExpression();
@ -1128,11 +1128,11 @@ namespace hex::pl {
auto builtinType = dynamic_cast<ASTNodeBuiltinType *>(sizeType->getType()); auto builtinType = dynamic_cast<ASTNodeBuiltinType *>(sizeType->getType());
if (builtinType == nullptr || !Token::isUnsigned(builtinType->getType())) if (builtinType == nullptr || !Token::isUnsigned(builtinType->getType()))
throwParseError("invalid type used for pointer size", -1); throwParserError("invalid type used for pointer size", -1);
} }
if (!MATCHES(sequence(OPERATOR_AT))) if (!MATCHES(sequence(OPERATOR_AT)))
throwParseError("expected placement instruction", -1); throwParserError("expected placement instruction", -1);
auto placementOffset = parseMathematicalExpression(); auto placementOffset = parseMathematicalExpression();
@ -1145,7 +1145,7 @@ namespace hex::pl {
std::vector<ASTNode *> statements; std::vector<ASTNode *> statements;
if (!MATCHES(sequence(IDENTIFIER))) if (!MATCHES(sequence(IDENTIFIER)))
throwParseError("expected namespace identifier"); throwParserError("expected namespace identifier");
this->m_currNamespace.push_back(this->m_currNamespace.back()); this->m_currNamespace.push_back(this->m_currNamespace.back());
@ -1159,7 +1159,7 @@ namespace hex::pl {
} }
if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN)))
throwParseError("expected '{' at start of namespace"); throwParserError("expected '{' at start of namespace");
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
auto newStatements = parseStatements(); auto newStatements = parseStatements();
@ -1181,7 +1181,7 @@ namespace hex::pl {
return parseVariablePlacement(type); return parseVariablePlacement(type);
else if (MATCHES(sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) else if (MATCHES(sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT)))
return parsePointerVariablePlacement(type); return parsePointerVariablePlacement(type);
else throwParseError("invalid sequence", 0); else throwParserError("invalid sequence", 0);
} }
/* Program */ /* Program */
@ -1221,13 +1221,13 @@ namespace hex::pl {
statement = parseFunctionDefinition(); statement = parseFunctionDefinition();
else if (MATCHES(sequence(KEYWORD_NAMESPACE))) else if (MATCHES(sequence(KEYWORD_NAMESPACE)))
return parseNamespace(); return parseNamespace();
else throwParseError("invalid sequence", 0); else throwParserError("invalid sequence", 0);
if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN))) if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN)))
parseAttribute(dynamic_cast<Attributable *>(statement)); parseAttribute(dynamic_cast<Attributable *>(statement));
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
throwParseError("missing ';' at end of expression", -1); throwParserError("missing ';' at end of expression", -1);
// Consume superfluous semicolons // Consume superfluous semicolons
while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
@ -1242,7 +1242,7 @@ namespace hex::pl {
auto typeName = getNamespacePrefixedName(name); auto typeName = getNamespacePrefixedName(name);
if (this->m_types.contains(typeName)) if (this->m_types.contains(typeName))
throwParseError(hex::format("redefinition of type '{}'", typeName)); throwParserError(hex::format("redefinition of type '{}'", typeName));
auto typeDecl = create(new ASTNodeTypeDecl(typeName, node, endian)); auto typeDecl = create(new ASTNodeTypeDecl(typeName, node, endian));
this->m_types.insert({ typeName, typeDecl }); this->m_types.insert({ typeName, typeDecl });
@ -1263,14 +1263,14 @@ namespace hex::pl {
auto program = parseTillToken(SEPARATOR_ENDOFPROGRAM); auto program = parseTillToken(SEPARATOR_ENDOFPROGRAM);
if (program.empty() || this->m_curr != tokens.end()) if (program.empty() || this->m_curr != tokens.end())
throwParseError("program is empty!", -1); throwParserError("program is empty!", -1);
return program; return program;
} catch (ParseError &e) { } catch (PatternLanguageError &e) {
this->m_error = e; this->m_error = e;
}
return {}; return std::nullopt;
}
} }
} }

View File

@ -10,8 +10,6 @@
#include <hex/pattern_language/validator.hpp> #include <hex/pattern_language/validator.hpp>
#include <hex/pattern_language/evaluator.hpp> #include <hex/pattern_language/evaluator.hpp>
#include <unistd.h>
namespace hex::pl { namespace hex::pl {
class PatternData; class PatternData;
@ -113,6 +111,15 @@ namespace hex::pl {
return std::nullopt; return std::nullopt;
} }
if (!this->m_validator->validate(*ast)) {
this->m_currError = this->m_validator->getError();
for (auto &node : *ast)
delete node;
return std::nullopt;
}
return ast; return ast;
} }
@ -172,7 +179,7 @@ namespace hex::pl {
return this->m_evaluator->getConsole().getLog(); return this->m_evaluator->getConsole().getLog();
} }
const std::optional<std::pair<u32, std::string>> &PatternLanguage::getError() { const std::optional<PatternLanguageError> &PatternLanguage::getError() {
return this->m_currError; return this->m_currError;
} }

View File

@ -8,9 +8,6 @@
namespace hex::pl { namespace hex::pl {
Preprocessor::Preprocessor() {
}
std::optional<std::string> Preprocessor::preprocess(const std::string &code, bool initialRun) { std::optional<std::string> Preprocessor::preprocess(const std::string &code, bool initialRun) {
u32 offset = 0; u32 offset = 0;
u32 lineNumber = 1; u32 lineNumber = 1;
@ -220,8 +217,9 @@ namespace hex::pl {
throwPreprocessorError(hex::format("no #pragma handler registered for type {0}", type.c_str()), pragmaLine); throwPreprocessorError(hex::format("no #pragma handler registered for type {0}", type.c_str()), pragmaLine);
} }
} }
} catch (PreprocessorError &e) { } catch (PatternLanguageError &e) {
this->m_error = e; this->m_error = e;
return std::nullopt; return std::nullopt;
} }

View File

@ -9,9 +9,6 @@
namespace hex::pl { namespace hex::pl {
Validator::Validator() {
}
bool Validator::validate(const std::vector<ASTNode *> &ast) { bool Validator::validate(const std::vector<ASTNode *> &ast) {
std::unordered_set<std::string> identifiers; std::unordered_set<std::string> identifiers;
@ -19,16 +16,16 @@ namespace hex::pl {
for (const auto &node : ast) { for (const auto &node : ast) {
if (node == nullptr) if (node == nullptr)
throwValidateError("nullptr in AST. This is a bug!", 1); 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); variableDeclNode != nullptr) {
if (!identifiers.insert(variableDeclNode->getName().data()).second) if (!identifiers.insert(variableDeclNode->getName().data()).second)
throwValidateError(hex::format("redefinition of identifier '{0}'", variableDeclNode->getName().data()), variableDeclNode->getLineNumber()); throwValidatorError(hex::format("redefinition of identifier '{0}'", variableDeclNode->getName().data()), variableDeclNode->getLineNumber());
this->validate({ variableDeclNode->getType() }); this->validate({ variableDeclNode->getType() });
} else if (auto typeDeclNode = dynamic_cast<ASTNodeTypeDecl *>(node); typeDeclNode != nullptr) { } else if (auto typeDeclNode = dynamic_cast<ASTNodeTypeDecl *>(node); typeDeclNode != nullptr) {
if (!identifiers.insert(typeDeclNode->getName().data()).second) if (!identifiers.insert(typeDeclNode->getName().data()).second)
throwValidateError(hex::format("redefinition of identifier '{0}'", typeDeclNode->getName().data()), typeDeclNode->getLineNumber()); throwValidatorError(hex::format("redefinition of identifier '{0}'", typeDeclNode->getName().data()), typeDeclNode->getLineNumber());
this->validate({ typeDeclNode->getType() }); this->validate({ typeDeclNode->getType() });
} else if (auto structNode = dynamic_cast<ASTNodeStruct *>(node); structNode != nullptr) { } else if (auto structNode = dynamic_cast<ASTNodeStruct *>(node); structNode != nullptr) {
@ -39,12 +36,12 @@ namespace hex::pl {
std::unordered_set<std::string> enumIdentifiers; std::unordered_set<std::string> enumIdentifiers;
for (auto &[name, value] : enumNode->getEntries()) { for (auto &[name, value] : enumNode->getEntries()) {
if (!enumIdentifiers.insert(name).second) if (!enumIdentifiers.insert(name).second)
throwValidateError(hex::format("redefinition of enum constant '{0}'", name.c_str()), value->getLineNumber()); throwValidatorError(hex::format("redefinition of enum constant '{0}'", name.c_str()), value->getLineNumber());
} }
} }
} }
} catch (ValidatorError &e) { } catch (PatternLanguageError &e) {
this->m_error = e; this->m_error = e;
return false; return false;
} }

View File

@ -9,9 +9,6 @@
#include <hex/helpers/file.hpp> #include <hex/helpers/file.hpp>
#include <hex/helpers/magic.hpp> #include <hex/helpers/magic.hpp>
#include <hex/helpers/literals.hpp>
#include <nlohmann/json.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -640,7 +637,8 @@ namespace hex::plugin::builtin {
auto error = this->m_evaluatorRuntime->getError(); auto error = this->m_evaluatorRuntime->getError();
if (error.has_value()) { if (error.has_value()) {
this->m_textEditor.SetErrorMarkers({ error.value() }); TextEditor::ErrorMarkers errorMarkers = { { error->getLineNumber(), error->what() } };
this->m_textEditor.SetErrorMarkers(errorMarkers);
} }
this->m_console = this->m_evaluatorRuntime->getConsoleLog(); this->m_console = this->m_evaluatorRuntime->getConsoleLog();

View File

@ -1,5 +1,7 @@
project(unit_tests) project(unit_tests)
enable_testing()
add_custom_target(unit_tests) add_custom_target(unit_tests)
add_subdirectory(common) add_subdirectory(common)

View File

@ -63,7 +63,7 @@ int test(int argc, char **argv) {
hex::log::fatal("Error during compilation!"); hex::log::fatal("Error during compilation!");
if (auto error = language.getError(); error.has_value()) if (auto error = language.getError(); error.has_value())
hex::log::info("Compile error: {} : {}", error->first, error->second); hex::log::info("Compile error: {} : {}", error->getLineNumber(), error->what());
for (auto &[level, message] : language.getConsoleLog()) for (auto &[level, message] : language.getConsoleLog())
hex::log::info("Evaluate error: {}", message); hex::log::info("Evaluate error: {}", message);