2020-11-19 11:36:52 +01:00
|
|
|
#pragma once
|
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
#include <atomic>
|
2020-11-22 16:22:02 +01:00
|
|
|
#include <bit>
|
2021-08-29 22:15:18 +02:00
|
|
|
#include <map>
|
2021-09-21 21:29:18 +02:00
|
|
|
#include <optional>
|
2020-11-19 11:36:52 +01:00
|
|
|
#include <vector>
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
#include <hex/pattern_language/log_console.hpp>
|
2022-01-11 19:35:28 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
#include <hex/api/content_registry.hpp>
|
2021-09-11 23:14:22 +02:00
|
|
|
|
2021-09-22 00:45:04 +02:00
|
|
|
#include <hex/helpers/fmt.hpp>
|
2022-01-11 19:35:28 +01:00
|
|
|
#include <hex/helpers/concepts.hpp>
|
2021-09-22 00:45:04 +02:00
|
|
|
|
2021-08-29 22:15:18 +02:00
|
|
|
namespace hex::prv { class Provider; }
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
namespace hex::pl {
|
2020-11-19 11:36:52 +01:00
|
|
|
|
2021-12-19 12:32:15 +01:00
|
|
|
enum class DangerousFunctionPermission {
|
|
|
|
Ask,
|
|
|
|
Deny,
|
|
|
|
Allow
|
|
|
|
};
|
|
|
|
|
2021-12-30 14:44:46 +01:00
|
|
|
enum class ControlFlowStatement {
|
|
|
|
None,
|
|
|
|
Continue,
|
|
|
|
Break,
|
|
|
|
Return
|
|
|
|
};
|
|
|
|
|
2021-08-29 22:15:18 +02:00
|
|
|
class PatternData;
|
2021-10-02 15:22:38 +02:00
|
|
|
class PatternCreationLimiter;
|
2021-09-21 21:29:18 +02:00
|
|
|
class ASTNode;
|
2021-08-29 22:15:18 +02:00
|
|
|
|
2021-01-21 11:36:58 +01:00
|
|
|
class Evaluator {
|
|
|
|
public:
|
2021-01-23 14:00:09 +01:00
|
|
|
Evaluator() = default;
|
2021-01-09 23:48:42 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*> &ast);
|
|
|
|
|
|
|
|
[[nodiscard]]
|
|
|
|
LogConsole& getConsole() {
|
|
|
|
return this->m_console;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Scope { PatternData *parent; std::vector<PatternData*>* scope; };
|
2021-09-22 00:45:04 +02:00
|
|
|
void pushScope(PatternData *parent, std::vector<PatternData*> &scope) {
|
2021-10-07 11:34:46 +02:00
|
|
|
if (this->m_scopes.size() > this->getEvaluationDepth())
|
|
|
|
LogConsole::abortEvaluation(hex::format("evaluation depth exceeded set limit of {}", this->getEvaluationDepth()));
|
|
|
|
|
|
|
|
this->handleAbort();
|
2021-09-22 00:45:04 +02:00
|
|
|
|
|
|
|
this->m_scopes.push_back({ parent, &scope });
|
|
|
|
}
|
|
|
|
|
|
|
|
void popScope() {
|
|
|
|
this->m_scopes.pop_back();
|
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
const Scope& getScope(s32 index) {
|
|
|
|
return this->m_scopes[this->m_scopes.size() - 1 + index];
|
|
|
|
}
|
2021-01-09 23:48:42 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
const Scope& getGlobalScope() {
|
|
|
|
return this->m_scopes.front();
|
|
|
|
}
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-10-17 21:49:33 +02:00
|
|
|
size_t getScopeCount() {
|
|
|
|
return this->m_scopes.size();
|
|
|
|
}
|
|
|
|
|
2021-10-11 22:01:15 +02:00
|
|
|
bool isGlobalScope() {
|
|
|
|
return this->m_scopes.size() == 1;
|
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
void setProvider(prv::Provider *provider) {
|
|
|
|
this->m_provider = provider;
|
|
|
|
}
|
|
|
|
|
2021-12-18 22:56:36 +01:00
|
|
|
void setInVariables(const std::map<std::string, Token::Literal> &inVariables) {
|
|
|
|
this->m_inVariables = inVariables;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
|
|
|
std::map<std::string, Token::Literal> getOutVariables() const {
|
|
|
|
std::map<std::string, Token::Literal> result;
|
|
|
|
|
|
|
|
for (const auto &[name, offset] : this->m_outVariables) {
|
|
|
|
result.insert({ name, this->getStack()[offset] });
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
[[nodiscard]]
|
|
|
|
prv::Provider *getProvider() const {
|
|
|
|
return this->m_provider;
|
|
|
|
}
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
void setDefaultEndian(std::endian endian) {
|
|
|
|
this->m_defaultEndian = endian;
|
2021-01-22 18:01:39 +01:00
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
[[nodiscard]]
|
|
|
|
std::endian getDefaultEndian() const {
|
|
|
|
return this->m_defaultEndian;
|
|
|
|
}
|
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
void setEvaluationDepth(u64 evalDepth) {
|
2021-09-22 00:45:04 +02:00
|
|
|
this->m_evalDepth = evalDepth;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
2021-10-07 11:34:46 +02:00
|
|
|
u64 getEvaluationDepth() const {
|
2021-09-22 00:45:04 +02:00
|
|
|
return this->m_evalDepth;
|
|
|
|
}
|
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
void setArrayLimit(u64 arrayLimit) {
|
2021-09-22 00:45:04 +02:00
|
|
|
this->m_arrayLimit = arrayLimit;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
2021-10-07 11:34:46 +02:00
|
|
|
u64 getArrayLimit() const {
|
2021-09-22 00:45:04 +02:00
|
|
|
return this->m_arrayLimit;
|
|
|
|
}
|
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
void setPatternLimit(u64 limit) {
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_patternLimit = limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
2021-10-07 11:34:46 +02:00
|
|
|
u64 getPatternLimit() {
|
2021-10-02 15:22:38 +02:00
|
|
|
return this->m_patternLimit;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
2021-10-07 11:34:46 +02:00
|
|
|
u64 getPatternCount() {
|
2021-10-02 15:22:38 +02:00
|
|
|
return this->m_currPatternCount;
|
|
|
|
}
|
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
void setLoopLimit(u64 limit) {
|
|
|
|
this->m_loopLimit = limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
|
|
|
u64 getLoopLimit() {
|
|
|
|
return this->m_loopLimit;
|
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
u64& dataOffset() { return this->m_currOffset; }
|
|
|
|
|
2021-12-20 20:40:28 +01:00
|
|
|
bool addCustomFunction(const std::string &name, u32 numParams, const ContentRegistry::PatternLanguage::Callback &function) {
|
2021-09-21 21:29:18 +02:00
|
|
|
const auto [iter, inserted] = this->m_customFunctions.insert({ name, { numParams, function } });
|
|
|
|
|
|
|
|
return inserted;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
2021-12-20 20:40:28 +01:00
|
|
|
const std::map<std::string, ContentRegistry::PatternLanguage::Function>& getCustomFunctions() const {
|
2021-09-21 21:29:18 +02:00
|
|
|
return this->m_customFunctions;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
|
|
|
std::vector<Token::Literal>& getStack() {
|
|
|
|
return this->m_stack;
|
|
|
|
}
|
|
|
|
|
2021-12-18 22:56:36 +01:00
|
|
|
[[nodiscard]]
|
|
|
|
const std::vector<Token::Literal>& getStack() const {
|
|
|
|
return this->m_stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt, bool outVariable = false);
|
2021-09-21 21:29:18 +02:00
|
|
|
void setVariable(const std::string &name, const Token::Literal& value);
|
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
void abort() {
|
|
|
|
this->m_aborted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleAbort() {
|
|
|
|
if (this->m_aborted)
|
|
|
|
LogConsole::abortEvaluation("evaluation aborted by user");
|
|
|
|
}
|
|
|
|
|
2021-12-10 11:55:27 +01:00
|
|
|
[[nodiscard]]
|
|
|
|
std::optional<Token::Literal> getEnvVariable(const std::string &name) const {
|
|
|
|
if (this->m_envVariables.contains(name))
|
|
|
|
return this->m_envVariables.at(name);
|
|
|
|
else
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setEnvVariable(const std::string &name, const Token::Literal &value) {
|
|
|
|
this->m_envVariables[name] = value;
|
|
|
|
}
|
|
|
|
|
2021-12-19 12:32:15 +01:00
|
|
|
[[nodiscard]]
|
|
|
|
bool hasDangerousFunctionBeenCalled() const {
|
|
|
|
return this->m_dangerousFunctionCalled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dangerousFunctionCalled() {
|
|
|
|
this->m_dangerousFunctionCalled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void allowDangerousFunctions(bool allow) {
|
|
|
|
this->m_allowDangerousFunctions = allow ? DangerousFunctionPermission::Allow : DangerousFunctionPermission::Deny;
|
|
|
|
this->m_dangerousFunctionCalled = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
|
|
|
DangerousFunctionPermission getDangerousFunctionPermission() const {
|
|
|
|
return this->m_allowDangerousFunctions;
|
|
|
|
}
|
|
|
|
|
2021-12-30 14:44:46 +01:00
|
|
|
void setCurrentControlFlowStatement(ControlFlowStatement statement) {
|
|
|
|
this->m_currControlFlowStatement = statement;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]]
|
|
|
|
ControlFlowStatement getCurrentControlFlowStatement() const {
|
|
|
|
return this->m_currControlFlowStatement;
|
|
|
|
}
|
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
private:
|
|
|
|
|
|
|
|
void patternCreated();
|
|
|
|
void patternDestroyed();
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
private:
|
2021-09-21 21:29:18 +02:00
|
|
|
u64 m_currOffset;
|
|
|
|
prv::Provider *m_provider = nullptr;
|
2021-01-21 11:36:58 +01:00
|
|
|
LogConsole m_console;
|
Pattern Language rewrite (#111)
* Initial parser rewrite effort
Lexer and Token cleanup, Parser started over
* Greatly improved parser syntax
* Reimplemented using declarations and variable placement parsing
* Added back unions and structs
* Added enums as well as mathematical expressions (+, -, *, /, <<, >>, &, |, ^)
* Code style improvement
* Implemented arrays and fixed memory issues
* Fixed more memory issues in parser, reimplemented validator, evaluator and patterns
* Fixed builtin types, arrays and reimplemented strings
* Improved error messages
* Made character a distinct type, used for chars and strings
* Implemented padding, fixed arrays
* Added bitfields
* Added rvalue parsing, no evaluating yet
* Added .idea folder to gitignore
* Fixed build on MacOS
* Added custom implementation of integral concept if not available
* Rebased onto master
* Fixed array variable decl crash
* Added rvalues and dot syntax
* Lower case all pattern language error messages
* Fixed typo in variable name
* Fixed bug where preprocessor would not ignore commented out directives
* Reimplemented pointers
* Fixed rebase issues
2021-01-02 20:27:11 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
std::endian m_defaultEndian = std::endian::native;
|
2021-10-07 11:34:46 +02:00
|
|
|
u64 m_evalDepth;
|
|
|
|
u64 m_arrayLimit;
|
|
|
|
u64 m_patternLimit;
|
|
|
|
u64 m_loopLimit;
|
|
|
|
|
|
|
|
u64 m_currPatternCount;
|
2021-10-02 15:22:38 +02:00
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
std::atomic<bool> m_aborted;
|
2021-09-21 21:29:18 +02:00
|
|
|
|
|
|
|
std::vector<Scope> m_scopes;
|
2021-12-20 20:40:28 +01:00
|
|
|
std::map<std::string, ContentRegistry::PatternLanguage::Function> m_customFunctions;
|
2021-09-21 21:29:18 +02:00
|
|
|
std::vector<ASTNode*> m_customFunctionDefinitions;
|
|
|
|
std::vector<Token::Literal> m_stack;
|
2021-12-18 22:56:36 +01:00
|
|
|
|
2021-12-10 11:55:27 +01:00
|
|
|
std::map<std::string, Token::Literal> m_envVariables;
|
2021-12-18 22:56:36 +01:00
|
|
|
std::map<std::string, Token::Literal> m_inVariables;
|
|
|
|
std::map<std::string, size_t> m_outVariables;
|
2021-10-02 15:22:38 +02:00
|
|
|
|
2021-12-19 12:32:15 +01:00
|
|
|
std::atomic<bool> m_dangerousFunctionCalled = false;
|
|
|
|
std::atomic<DangerousFunctionPermission> m_allowDangerousFunctions = DangerousFunctionPermission::Ask;
|
2021-12-30 14:44:46 +01:00
|
|
|
ControlFlowStatement m_currControlFlowStatement;
|
2021-12-19 12:32:15 +01:00
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
friend class PatternCreationLimiter;
|
2020-11-19 11:36:52 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|