mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 05:27:41 -05:00
Huge refactoring of builtin features into an external plugin
This commit is contained in:
@@ -16,7 +16,7 @@ namespace hex {
|
||||
|
||||
class View;
|
||||
namespace lang { class ASTNode; }
|
||||
namespace lang { class LogConsole; }
|
||||
namespace lang { class Evaluator; }
|
||||
|
||||
/*
|
||||
The Content Registry is the heart of all features in ImHex that are in some way extendable by Plugins.
|
||||
@@ -83,10 +83,10 @@ namespace hex {
|
||||
|
||||
struct Function {
|
||||
u32 parameterCount;
|
||||
std::function<hex::lang::ASTNode*(hex::lang::LogConsole&, std::vector<hex::lang::ASTNode*>)> func;
|
||||
std::function<hex::lang::ASTNode*(hex::lang::Evaluator&, std::vector<hex::lang::ASTNode*>)> func;
|
||||
};
|
||||
|
||||
static void add(std::string_view name, u32 parameterCount, const std::function<hex::lang::ASTNode*(hex::lang::LogConsole&, std::vector<hex::lang::ASTNode*>)> &func);
|
||||
static void add(std::string_view name, u32 parameterCount, const std::function<hex::lang::ASTNode*(hex::lang::Evaluator&, std::vector<hex::lang::ASTNode*>)> &func);
|
||||
static std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function>& getEntries();
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/lang/pattern_data.hpp>
|
||||
#include <hex/lang/ast_node.hpp>
|
||||
#include <hex/lang/log_console.hpp>
|
||||
|
||||
#include <bit>
|
||||
#include <string>
|
||||
@@ -14,45 +15,27 @@
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
class LogConsole {
|
||||
public:
|
||||
enum Level {
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
};
|
||||
|
||||
const auto& getLog() { return this->m_consoleLog; }
|
||||
|
||||
using EvaluateError = std::string;
|
||||
|
||||
void log(Level level, std::string_view message) {
|
||||
switch (level) {
|
||||
default:
|
||||
case Level::Debug: this->m_consoleLog.emplace_back(level, "[-] " + std::string(message)); break;
|
||||
case Level::Info: this->m_consoleLog.emplace_back(level, "[i] " + std::string(message)); break;
|
||||
case Level::Warning: this->m_consoleLog.emplace_back(level, "[*] " + std::string(message)); break;
|
||||
case Level::Error: this->m_consoleLog.emplace_back(level, "[!] " + std::string(message)); break;
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void abortEvaluation(std::string_view message) {
|
||||
throw EvaluateError(message);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<Level, std::string>> m_consoleLog;
|
||||
};
|
||||
|
||||
class Evaluator {
|
||||
public:
|
||||
Evaluator(prv::Provider* &provider, std::endian defaultDataEndian);
|
||||
Evaluator(prv::Provider* &provider, std::endian defaultDataEndian = std::endian::native);
|
||||
|
||||
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
|
||||
|
||||
LogConsole& getConsole() { return this->m_console; }
|
||||
|
||||
void setDefaultEndian(std::endian endian) { this->m_defaultDataEndian = endian; }
|
||||
[[nodiscard]] std::endian getCurrentEndian() const { return this->m_endianStack.back(); }
|
||||
|
||||
PatternData* patternFromName(const std::vector<std::string> &name);
|
||||
|
||||
template<typename T>
|
||||
T* asType(ASTNode *param) {
|
||||
if (auto evaluatedParam = dynamic_cast<T*>(param); evaluatedParam != nullptr)
|
||||
return evaluatedParam;
|
||||
else
|
||||
this->getConsole().abortEvaluation("function got wrong type of parameter");
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, ASTNode*> m_types;
|
||||
prv::Provider* &m_provider;
|
||||
@@ -63,9 +46,7 @@ namespace hex::lang {
|
||||
std::vector<std::vector<PatternData*>*> m_currMembers;
|
||||
LogConsole m_console;
|
||||
|
||||
[[nodiscard]] std::endian getCurrentEndian() const {
|
||||
return this->m_endianStack.back();
|
||||
}
|
||||
|
||||
|
||||
ASTNodeIntegerLiteral* evaluateScopeResolution(ASTNodeScopeResolution *node);
|
||||
ASTNodeIntegerLiteral* evaluateRValue(ASTNodeRValue *node);
|
||||
@@ -75,7 +56,6 @@ namespace hex::lang {
|
||||
ASTNodeIntegerLiteral* evaluateTernaryExpression(ASTNodeTernaryExpression *node);
|
||||
ASTNodeIntegerLiteral* evaluateMathematicalExpression(ASTNodeNumericExpression *node);
|
||||
|
||||
PatternData* patternFromName(const std::vector<std::string> &name);
|
||||
PatternData* evaluateAttributes(ASTNode *currNode, PatternData *currPattern);
|
||||
PatternData* evaluateBuiltinType(ASTNodeBuiltinType *node);
|
||||
void evaluateMember(ASTNode *node, std::vector<PatternData*> &currMembers, bool increaseOffset);
|
||||
@@ -87,28 +67,6 @@ namespace hex::lang {
|
||||
PatternData* evaluateVariable(ASTNodeVariableDecl *node);
|
||||
PatternData* evaluateArray(ASTNodeArrayVariableDecl *node);
|
||||
PatternData* evaluatePointer(ASTNodePointerVariableDecl *node);
|
||||
|
||||
template<typename T>
|
||||
T* asType(ASTNode *param) {
|
||||
if (auto evaluatedParam = dynamic_cast<T*>(param); evaluatedParam != nullptr)
|
||||
return evaluatedParam;
|
||||
else
|
||||
this->m_console.abortEvaluation("function got wrong type of parameter");
|
||||
}
|
||||
|
||||
void registerBuiltinFunctions();
|
||||
|
||||
#define BUILTIN_FUNCTION(name) ASTNodeIntegerLiteral* TOKEN_CONCAT(builtin_, name)(LogConsole &console, std::vector<ASTNode*> params)
|
||||
|
||||
BUILTIN_FUNCTION(findSequence);
|
||||
BUILTIN_FUNCTION(readUnsigned);
|
||||
BUILTIN_FUNCTION(readSigned);
|
||||
|
||||
BUILTIN_FUNCTION(assert);
|
||||
BUILTIN_FUNCTION(warnAssert);
|
||||
BUILTIN_FUNCTION(print);
|
||||
|
||||
#undef BUILTIN_FUNCTION
|
||||
};
|
||||
|
||||
}
|
||||
47
plugins/libimhex/include/hex/lang/log_console.hpp
Normal file
47
plugins/libimhex/include/hex/lang/log_console.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
class LogConsole {
|
||||
public:
|
||||
enum Level {
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
};
|
||||
|
||||
const auto& getLog() { return this->m_consoleLog; }
|
||||
|
||||
using EvaluateError = std::string;
|
||||
|
||||
void log(Level level, std::string_view message) {
|
||||
switch (level) {
|
||||
default:
|
||||
case Level::Debug: this->m_consoleLog.emplace_back(level, "[-] " + std::string(message)); break;
|
||||
case Level::Info: this->m_consoleLog.emplace_back(level, "[i] " + std::string(message)); break;
|
||||
case Level::Warning: this->m_consoleLog.emplace_back(level, "[*] " + std::string(message)); break;
|
||||
case Level::Error: this->m_consoleLog.emplace_back(level, "[!] " + std::string(message)); break;
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void abortEvaluation(std::string_view message) {
|
||||
throw EvaluateError(message);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
this->m_consoleLog.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<Level, std::string>> m_consoleLog;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -110,6 +110,10 @@ namespace hex::lang {
|
||||
|
||||
/* Token consuming */
|
||||
|
||||
enum class Setting{ };
|
||||
constexpr static auto Normal = static_cast<Setting>(0);
|
||||
constexpr static auto Not = static_cast<Setting>(1);
|
||||
|
||||
bool begin() {
|
||||
this->m_originalPosition = this->m_curr;
|
||||
this->m_matchedOptionals.clear();
|
||||
@@ -117,41 +121,65 @@ namespace hex::lang {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool none(bool result) {
|
||||
if (result) {
|
||||
this->m_curr = this->m_originalPosition;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool sequence() {
|
||||
return true;
|
||||
if constexpr (S == Normal)
|
||||
return true;
|
||||
else if constexpr (S == Not)
|
||||
return false;
|
||||
else
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool sequence(Token::Type type, auto value, auto ... args) {
|
||||
if (!peek(type, value)) {
|
||||
if constexpr (S == Normal) {
|
||||
if (!peek(type, value)) {
|
||||
this->m_curr = this->m_originalPosition;
|
||||
return false;
|
||||
}
|
||||
|
||||
this->m_curr++;
|
||||
|
||||
if (!sequence<Normal>(args...)) {
|
||||
this->m_curr = this->m_originalPosition;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if constexpr (S == Not) {
|
||||
if (!peek(type, value))
|
||||
return true;
|
||||
|
||||
this->m_curr++;
|
||||
|
||||
if (!sequence<Normal>(args...))
|
||||
return true;
|
||||
|
||||
this->m_curr = this->m_originalPosition;
|
||||
return false;
|
||||
}
|
||||
|
||||
this->m_curr++;
|
||||
|
||||
if (!sequence(args...)) {
|
||||
this->m_curr = this->m_originalPosition;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool oneOf() {
|
||||
return false;
|
||||
if constexpr (S == Normal)
|
||||
return false;
|
||||
else if constexpr (S == Not)
|
||||
return true;
|
||||
else
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool oneOf(Token::Type type, auto value, auto ... args) {
|
||||
return sequence(type, value) || oneOf(args...);
|
||||
if constexpr (S == Normal)
|
||||
return sequence<Normal>(type, value) || oneOf(args...);
|
||||
else if constexpr (S == Not)
|
||||
return sequence<Not>(type, value) && oneOf(args...);
|
||||
else
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
bool variant(Token::Type type1, auto value1, Token::Type type2, auto value2) {
|
||||
|
||||
48
plugins/libimhex/include/hex/lang/pattern_language.hpp
Normal file
48
plugins/libimhex/include/hex/lang/pattern_language.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <bit>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/lang/pattern_data.hpp>
|
||||
#include <hex/lang/log_console.hpp>
|
||||
|
||||
namespace hex::prv { class Provider; }
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
class Preprocessor;
|
||||
class Lexer;
|
||||
class Parser;
|
||||
class Validator;
|
||||
class Evaluator;
|
||||
|
||||
class PatternLanguage {
|
||||
public:
|
||||
PatternLanguage(prv::Provider *provider);
|
||||
~PatternLanguage();
|
||||
|
||||
std::optional<std::vector<PatternData*>> executeString(std::string_view string);
|
||||
std::optional<std::vector<PatternData*>> executeFile(std::string_view path);
|
||||
|
||||
std::vector<std::pair<LogConsole::Level, std::string>> getConsoleLog();
|
||||
std::optional<std::pair<u32, std::string>> getError();
|
||||
|
||||
private:
|
||||
Preprocessor *m_preprocessor;
|
||||
Lexer *m_lexer;
|
||||
Parser *m_parser;
|
||||
Validator *m_validator;
|
||||
Evaluator *m_evaluator;
|
||||
|
||||
prv::Provider *m_provider;
|
||||
std::endian m_defaultEndian;
|
||||
|
||||
std::optional<std::pair<u32, std::string>> m_currError;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user