diff --git a/.gitmodules b/.gitmodules index d1a32ab3a..c67fa6aae 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,3 +26,6 @@ path = lib/external/libromfs url = https://github.com/WerWolv/libromfs ignore = dirty +[submodule "lib/external/pattern_language"] + path = lib/external/pattern_language + url = https://github.com/WerWolv/PatternLanguage diff --git a/.idea/vcs.xml b/.idea/vcs.xml index e47a4f3d0..996dfdeae 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,11 +2,16 @@ + + + + + diff --git a/lib/external/pattern_language b/lib/external/pattern_language new file mode 160000 index 000000000..3abaa2a36 --- /dev/null +++ b/lib/external/pattern_language @@ -0,0 +1 @@ +Subproject commit 3abaa2a36d833bb3be7a580dff9b89c37c876a18 diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index 6f2f80060..48e2f1cf8 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -79,7 +79,8 @@ else() pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone) endif() - +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/pattern_language ${CMAKE_CURRENT_BINARY_DIR}/external/pattern_language EXCLUDE_FROM_ALL) +set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON) find_package(mbedTLS 2.26.0 REQUIRED) configurePython() @@ -125,14 +126,6 @@ set(LIBIMHEX_SOURCES source/helpers/loader_script_handler.cpp source/helpers/logger.cpp - source/pattern_language/pattern_language.cpp - source/pattern_language/preprocessor.cpp - source/pattern_language/lexer.cpp - source/pattern_language/parser.cpp - source/pattern_language/validator.cpp - source/pattern_language/evaluator.cpp - source/pattern_language/log_console.cpp - source/providers/provider.cpp source/ui/imgui_imhex_extensions.cpp @@ -166,4 +159,4 @@ if (APPLE) target_link_libraries(libimhex PUBLIC ${FOUNDATION}) endif () -target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs) +target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl) diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index 49c32873d..16ea207d2 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include @@ -16,13 +16,15 @@ #include +namespace pl { + class Evaluator; +} + namespace hex { class View; class LanguageDefinition; - namespace pl { - class Evaluator; - } + namespace dp { class Node; } @@ -117,72 +119,28 @@ namespace hex { namespace impl { - struct ColorPalette { + struct FunctionDefinition { + pl::api::Namespace ns; std::string name; - std::vector colors; + + pl::api::FunctionParameterCount parameterCount; + pl::api::FunctionCallback callback; + + bool dangerous; }; } - struct ParameterCount { - ParameterCount() = default; + std::unique_ptr createDefaultRuntime(prv::Provider *provider); - constexpr bool operator==(const ParameterCount &other) const { - return this->min == other.min && this->max == other.max; - } + void addPragma(const std::string &name, const pl::api::PragmaHandler &handler); - [[nodiscard]] static ParameterCount unlimited() { - return ParameterCount { 0, 0xFFFF'FFFF }; - } + void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func); + void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func); - [[nodiscard]] static ParameterCount none() { - return ParameterCount { 0, 0 }; - } + std::map &getPragmas(); + std::vector &getFunctions(); - [[nodiscard]] static ParameterCount exactly(u32 value) { - return ParameterCount { value, value }; - } - - [[nodiscard]] static ParameterCount moreThan(u32 value) { - return ParameterCount { value + 1, 0xFFFF'FFFF }; - } - - [[nodiscard]] static ParameterCount lessThan(u32 value) { - return ParameterCount { 0, u32(std::max(i64(value) - 1, 0)) }; - } - - [[nodiscard]] static ParameterCount atLeast(u32 value) { - return ParameterCount { value, 0xFFFF'FFFF }; - } - - [[nodiscard]] static ParameterCount between(u32 min, u32 max) { - return ParameterCount { min, max }; - } - - u32 min = 0, max = 0; - private: - ParameterCount(u32 min, u32 max) : min(min), max(max) { } - }; - - using Namespace = std::vector; - using Callback = std::function(hex::pl::Evaluator *, const std::vector &)>; - - struct Function { - ParameterCount parameterCount; - std::vector defaultParameters; - Callback func; - bool dangerous; - }; - - void addFunction(const Namespace &ns, const std::string &name, ParameterCount parameterCount, const Callback &func); - void addDangerousFunction(const Namespace &ns, const std::string &name, ParameterCount parameterCount, const Callback &func); - std::map &getFunctions(); - - std::vector &getPalettes(); - void addColorPalette(const std::string &unlocalizedName, const std::vector &colors); - void setSelectedPalette(u32 index); - u32 getNextColor(); - void resetPalette(); } /* View Registry. Allows adding of new windows */ diff --git a/lib/libimhex/include/hex/api/event.hpp b/lib/libimhex/include/hex/api/event.hpp index 6108c9357..261716dda 100644 --- a/lib/libimhex/include/hex/api/event.hpp +++ b/lib/libimhex/include/hex/api/event.hpp @@ -18,6 +18,10 @@ struct GLFWwindow; +namespace pl { + class Pattern; +} + namespace hex { class EventId { @@ -96,10 +100,6 @@ namespace hex { static EventList s_events; }; - namespace pl { - class Pattern; - } - /* Default Events */ EVENT_DEF(EventFileLoaded, std::fs::path); EVENT_DEF(EventFileUnloaded); diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node.hpp deleted file mode 100644 index 3ecedb913..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace hex::pl { - - class Pattern; - class Evaluator; - - class ASTNode : public Cloneable { - public: - constexpr ASTNode() = default; - - constexpr virtual ~ASTNode() = default; - - constexpr ASTNode(const ASTNode &) = default; - - [[nodiscard]] constexpr u32 getLineNumber() const { return this->m_lineNumber; } - - [[maybe_unused]] constexpr void setLineNumber(u32 lineNumber) { this->m_lineNumber = lineNumber; } - - [[nodiscard]] virtual std::unique_ptr evaluate(Evaluator *evaluator) const { - hex::unused(evaluator); - - return this->clone(); - } - - [[nodiscard]] virtual std::vector> createPatterns(Evaluator *evaluator) const { - hex::unused(evaluator); - - return {}; - } - - using FunctionResult = std::optional; - virtual FunctionResult execute(Evaluator *evaluator) const { - hex::unused(evaluator); - - LogConsole::abortEvaluation("cannot execute non-function statement", this); - } - - private: - u32 m_lineNumber = 1; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_array_variable_decl.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_array_variable_decl.hpp deleted file mode 100644 index 23727bf19..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_array_variable_decl.hpp +++ /dev/null @@ -1,312 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace hex::pl { - - class ASTNodeArrayVariableDecl : public ASTNode, - public Attributable { - public: - ASTNodeArrayVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&size, std::unique_ptr &&placementOffset = {}) - : ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_size(std::move(size)), m_placementOffset(std::move(placementOffset)) { } - - ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other) : ASTNode(other), Attributable(other) { - this->m_name = other.m_name; - this->m_type = other.m_type; - if (other.m_size != nullptr) - this->m_size = other.m_size->clone(); - else - this->m_size = nullptr; - - if (other.m_placementOffset != nullptr) - this->m_placementOffset = other.m_placementOffset->clone(); - else - this->m_placementOffset = nullptr; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeArrayVariableDecl(*this)); - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto startOffset = evaluator->dataOffset(); - - if (this->m_placementOffset != nullptr) { - auto evaluatedPlacement = this->m_placementOffset->evaluate(evaluator); - auto offset = dynamic_cast(evaluatedPlacement.get()); - - evaluator->dataOffset() = std::visit(overloaded { - [this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); }, - [this](Pattern *) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); }, - [](auto &&offset) -> u64 { return offset; } }, - offset->getValue()); - } - - auto type = this->m_type->evaluate(evaluator); - - std::unique_ptr pattern; - if (dynamic_cast(type.get())) - pattern = createStaticArray(evaluator); - else if (auto attributable = dynamic_cast(type.get())) { - bool isStaticType = attributable->hasAttribute("static", false); - - if (isStaticType) - pattern = createStaticArray(evaluator); - else - pattern = createDynamicArray(evaluator); - } else { - LogConsole::abortEvaluation("invalid type used in array", this); - } - - applyVariableAttributes(evaluator, this, pattern.get()); - - if (this->m_placementOffset != nullptr && !evaluator->isGlobalScope()) { - evaluator->dataOffset() = startOffset; - } - - return hex::moveToVector(std::move(pattern)); - } - - private: - std::string m_name; - std::shared_ptr m_type; - std::unique_ptr m_size; - std::unique_ptr m_placementOffset; - - std::unique_ptr createStaticArray(Evaluator *evaluator) const { - u64 startOffset = evaluator->dataOffset(); - - auto templatePatterns = this->m_type->createPatterns(evaluator); - auto &templatePattern = templatePatterns.front(); - - evaluator->dataOffset() = startOffset; - - i128 entryCount = 0; - - if (this->m_size != nullptr) { - auto sizeNode = this->m_size->evaluate(evaluator); - - if (auto literal = dynamic_cast(sizeNode.get())) { - entryCount = std::visit(overloaded { - [this](const std::string &) -> i128 { LogConsole::abortEvaluation("cannot use string to index array", this); }, - [this](Pattern *) -> i128 { LogConsole::abortEvaluation("cannot use custom type to index array", this); }, - [](auto &&size) -> i128 { return size; } }, - literal->getValue()); - } else if (auto whileStatement = dynamic_cast(sizeNode.get())) { - while (whileStatement->evaluateCondition(evaluator)) { - entryCount++; - evaluator->dataOffset() += templatePattern->getSize(); - evaluator->handleAbort(); - } - } - - if (entryCount < 0) - LogConsole::abortEvaluation("array cannot have a negative size", this); - } else { - std::vector buffer(templatePattern->getSize()); - while (true) { - if (evaluator->dataOffset() > evaluator->getProvider()->getActualSize() - buffer.size()) - LogConsole::abortEvaluation("reached end of file before finding end of unsized array", this); - - evaluator->getProvider()->read(evaluator->dataOffset(), buffer.data(), buffer.size()); - evaluator->dataOffset() += buffer.size(); - - entryCount++; - - bool reachedEnd = true; - for (u8 &byte : buffer) { - if (byte != 0x00) { - reachedEnd = false; - break; - } - } - - if (reachedEnd) break; - evaluator->handleAbort(); - } - } - - std::unique_ptr outputPattern; - if (dynamic_cast(templatePattern.get())) { - outputPattern = std::unique_ptr(new PatternPadding(evaluator, startOffset, 0)); - } else if (dynamic_cast(templatePattern.get())) { - outputPattern = std::unique_ptr(new PatternString(evaluator, startOffset, 0)); - } else if (dynamic_cast(templatePattern.get())) { - outputPattern = std::unique_ptr(new PatternWideString(evaluator, startOffset, 0)); - } else { - auto arrayPattern = std::make_unique(evaluator, startOffset, 0); - arrayPattern->setEntries(templatePattern->clone(), entryCount); - outputPattern = std::move(arrayPattern); - } - - outputPattern->setVariableName(this->m_name); - outputPattern->setEndian(templatePattern->getEndian()); - outputPattern->setTypeName(templatePattern->getTypeName()); - outputPattern->setSize(templatePattern->getSize() * entryCount); - - evaluator->dataOffset() = startOffset + outputPattern->getSize(); - - return outputPattern; - } - - std::unique_ptr createDynamicArray(Evaluator *evaluator) const { - auto arrayPattern = std::make_unique(evaluator, evaluator->dataOffset(), 0); - arrayPattern->setVariableName(this->m_name); - - std::vector> entries; - - size_t size = 0; - u64 entryIndex = 0; - - auto addEntries = [&](std::vector> &&patterns) { - for (auto &pattern : patterns) { - pattern->setVariableName(hex::format("[{}]", entryIndex)); - pattern->setEndian(arrayPattern->getEndian()); - - size += pattern->getSize(); - entryIndex++; - - entries.push_back(std::move(pattern)); - - evaluator->handleAbort(); - } - }; - - auto discardEntries = [&](u32 count) { - for (u32 i = 0; i < count; i++) { - entries.pop_back(); - entryIndex--; - } - }; - - if (this->m_size != nullptr) { - auto sizeNode = this->m_size->evaluate(evaluator); - - if (auto literal = dynamic_cast(sizeNode.get())) { - auto entryCount = std::visit(overloaded { - [this](const std::string &) -> u128 { LogConsole::abortEvaluation("cannot use string to index array", this); }, - [this](Pattern *) -> u128 { LogConsole::abortEvaluation("cannot use custom type to index array", this); }, - [](auto &&size) -> u128 { return size; } }, - literal->getValue()); - - auto limit = evaluator->getArrayLimit(); - if (entryCount > limit) - LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this); - - for (u64 i = 0; i < entryCount; i++) { - evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None); - - auto patterns = this->m_type->createPatterns(evaluator); - size_t patternCount = patterns.size(); - - if (!patterns.empty()) - addEntries(std::move(patterns)); - - auto ctrlFlow = evaluator->getCurrentControlFlowStatement(); - evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None); - if (ctrlFlow == ControlFlowStatement::Break) - break; - else if (ctrlFlow == ControlFlowStatement::Continue) { - - discardEntries(patternCount); - continue; - } - } - } else if (auto whileStatement = dynamic_cast(sizeNode.get())) { - while (whileStatement->evaluateCondition(evaluator)) { - auto limit = evaluator->getArrayLimit(); - if (entryIndex > limit) - LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this); - - evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None); - - auto patterns = this->m_type->createPatterns(evaluator); - size_t patternCount = patterns.size(); - - if (!patterns.empty()) - addEntries(std::move(patterns)); - - auto ctrlFlow = evaluator->getCurrentControlFlowStatement(); - evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None); - if (ctrlFlow == ControlFlowStatement::Break) - break; - else if (ctrlFlow == ControlFlowStatement::Continue) { - discardEntries(patternCount); - continue; - } - } - } - } else { - while (true) { - bool reachedEnd = true; - auto limit = evaluator->getArrayLimit(); - if (entryIndex > limit) - LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this); - - evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None); - - auto patterns = this->m_type->createPatterns(evaluator); - - for (auto &pattern : patterns) { - std::vector buffer(pattern->getSize()); - - if (evaluator->dataOffset() > evaluator->getProvider()->getActualSize() - buffer.size()) { - LogConsole::abortEvaluation("reached end of file before finding end of unsized array", this); - } - - const auto patternSize = pattern->getSize(); - addEntries(hex::moveToVector(std::move(pattern))); - - auto ctrlFlow = evaluator->getCurrentControlFlowStatement(); - if (ctrlFlow == ControlFlowStatement::None) - break; - - evaluator->getProvider()->read(evaluator->dataOffset() - patternSize, buffer.data(), buffer.size()); - reachedEnd = true; - for (u8 &byte : buffer) { - if (byte != 0x00) { - reachedEnd = false; - break; - } - } - - if (reachedEnd) break; - } - - auto ctrlFlow = evaluator->getCurrentControlFlowStatement(); - evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None); - if (ctrlFlow == ControlFlowStatement::Break) - break; - else if (ctrlFlow == ControlFlowStatement::Continue) { - discardEntries(1); - continue; - } - - if (reachedEnd) break; - } - } - - - if (auto &arrayEntries = arrayPattern->getEntries(); !arrayEntries.empty()) - arrayPattern->setTypeName(arrayEntries.front()->getTypeName()); - - arrayPattern->setEntries(std::move(entries)); - arrayPattern->setSize(size); - - return arrayPattern; - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_assignment.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_assignment.hpp deleted file mode 100644 index 3fd529d52..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_assignment.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include - -namespace hex::pl { - - class ASTNodeAssignment : public ASTNode { - public: - ASTNodeAssignment(std::string lvalueName, std::unique_ptr &&rvalue) : m_lvalueName(std::move(lvalueName)), m_rvalue(std::move(rvalue)) { - } - - ASTNodeAssignment(const ASTNodeAssignment &other) : ASTNode(other) { - this->m_lvalueName = other.m_lvalueName; - this->m_rvalue = other.m_rvalue->clone(); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeAssignment(*this)); - } - - [[nodiscard]] const std::string &getLValueName() const { - return this->m_lvalueName; - } - - [[nodiscard]] const std::unique_ptr &getRValue() const { - return this->m_rvalue; - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - this->execute(evaluator); - - return {}; - } - - FunctionResult execute(Evaluator *evaluator) const override { - const auto node = this->getRValue()->evaluate(evaluator); - const auto literal = dynamic_cast(node.get()); - - if (this->getLValueName() == "$") - evaluator->dataOffset() = Token::literalToUnsigned(literal->getValue()); - else - evaluator->setVariable(this->getLValueName(), literal->getValue()); - - return {}; - } - - private: - std::string m_lvalueName; - std::unique_ptr m_rvalue; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_attribute.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_attribute.hpp deleted file mode 100644 index 017f6cac9..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_attribute.hpp +++ /dev/null @@ -1,220 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace hex::pl { - - class ASTNodeAttribute : public ASTNode { - public: - explicit ASTNodeAttribute(std::string attribute, std::optional value = std::nullopt) - : ASTNode(), m_attribute(std::move(attribute)), m_value(std::move(value)) { } - - ~ASTNodeAttribute() override = default; - - ASTNodeAttribute(const ASTNodeAttribute &other) : ASTNode(other) { - this->m_attribute = other.m_attribute; - this->m_value = other.m_value; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeAttribute(*this)); - } - - [[nodiscard]] const std::string &getAttribute() const { - return this->m_attribute; - } - - [[nodiscard]] const std::optional &getValue() const { - return this->m_value; - } - - private: - std::string m_attribute; - std::optional m_value; - }; - - - class Attributable { - protected: - Attributable() = default; - - Attributable(const Attributable &other) { - for (auto &attribute : other.m_attributes) { - auto copy = attribute->clone(); - if (auto node = dynamic_cast(copy.get())) { - this->m_attributes.push_back(std::unique_ptr(node)); - (void)copy.release(); - } - } - } - - public: - virtual void addAttribute(std::unique_ptr &&attribute) { - this->m_attributes.push_back(std::move(attribute)); - } - - [[nodiscard]] const auto &getAttributes() const { - return this->m_attributes; - } - - [[nodiscard]] bool hasAttribute(const std::string &key, bool needsParameter) const { - return std::any_of(this->m_attributes.begin(), this->m_attributes.end(), [&](const std::unique_ptr &attribute) { - if (attribute->getAttribute() == key) { - if (needsParameter && !attribute->getValue().has_value()) - LogConsole::abortEvaluation(hex::format("attribute '{}' expected a parameter"), attribute); - else if (!needsParameter && attribute->getValue().has_value()) - LogConsole::abortEvaluation(hex::format("attribute '{}' did not expect a parameter "), attribute); - else - return true; - } - - return false; - }); - } - - [[nodiscard]] std::optional getAttributeValue(const std::string &key) const { - auto attribute = std::find_if(this->m_attributes.begin(), this->m_attributes.end(), [&](const std::unique_ptr &attribute) { - return attribute->getAttribute() == key; - }); - - if (attribute != this->m_attributes.end()) - return (*attribute)->getValue(); - else - return std::nullopt; - } - - private: - std::vector> m_attributes; - }; - - - inline void applyTypeAttributes(Evaluator *evaluator, const ASTNode *node, Pattern *pattern) { - auto attributable = dynamic_cast(node); - if (attributable == nullptr) - LogConsole::abortEvaluation("attribute cannot be applied here", node); - - if (attributable->hasAttribute("inline", false)) { - auto inlinable = dynamic_cast(pattern); - - if (inlinable == nullptr) - LogConsole::abortEvaluation("inline attribute can only be applied to nested types", node); - else - inlinable->setInlined(true); - } - - using namespace ContentRegistry::PatternLanguage; - - if (auto value = attributable->getAttributeValue("format"); value) { - auto functions = evaluator->getCustomFunctions(); - if (!functions.contains(*value)) - LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node); - - const auto &function = functions[*value]; - if (function.parameterCount != ParameterCount::exactly(1)) - LogConsole::abortEvaluation("formatter function needs exactly one parameter", node); - - pattern->setFormatterFunction(function); - } - - if (auto value = attributable->getAttributeValue("format_entries"); value) { - auto functions = evaluator->getCustomFunctions(); - if (!functions.contains(*value)) - LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node); - - const auto &function = functions[*value]; - if (function.parameterCount != ParameterCount::exactly(1)) - LogConsole::abortEvaluation("formatter function needs exactly one parameter", node); - - auto array = dynamic_cast(pattern); - if (array == nullptr) - LogConsole::abortEvaluation("inline_array attribute can only be applied to array types", node); - - for (const auto &entry : array->getEntries()) { - entry->setFormatterFunction(function); - } - } - - if (auto value = attributable->getAttributeValue("transform"); value) { - auto functions = evaluator->getCustomFunctions(); - if (!functions.contains(*value)) - LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node); - - const auto &function = functions[*value]; - if (function.parameterCount != ParameterCount::exactly(1)) - LogConsole::abortEvaluation("transform function needs exactly one parameter", node); - - pattern->setTransformFunction(function); - } - - if (auto value = attributable->getAttributeValue("pointer_base"); value) { - auto functions = evaluator->getCustomFunctions(); - if (!functions.contains(*value)) - LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node); - - const auto &function = functions[*value]; - if (function.parameterCount != ParameterCount::exactly(1)) - LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node); - - if (auto pointerPattern = dynamic_cast(pattern)) { - u128 pointerValue = pointerPattern->getPointedAtAddress(); - - auto result = function.func(evaluator, { pointerValue }); - - if (!result.has_value()) - LogConsole::abortEvaluation("pointer base function did not return a value", node); - - pointerPattern->setPointedAtAddress(Token::literalToUnsigned(result.value()) + pointerValue); - } else { - LogConsole::abortEvaluation("pointer_base attribute may only be applied to a pointer"); - } - } - - if (attributable->hasAttribute("hidden", false)) { - pattern->setHidden(true); - } - - if (!pattern->hasOverriddenColor()) { - if (auto colorValue = attributable->getAttributeValue("color"); colorValue) { - u32 color = strtoul(colorValue->c_str(), nullptr, 16); - pattern->setColor(hex::changeEndianess(color, std::endian::big) >> 8); - } else if (auto singleColor = attributable->hasAttribute("single_color", false); singleColor) { - pattern->setColor(ContentRegistry::PatternLanguage::getNextColor()); - } - } - } - - inline void applyVariableAttributes(Evaluator *evaluator, const ASTNode *node, Pattern *pattern) { - auto attributable = dynamic_cast(node); - if (attributable == nullptr) - LogConsole::abortEvaluation("attribute cannot be applied here", node); - - auto endOffset = evaluator->dataOffset(); - evaluator->dataOffset() = pattern->getOffset(); - ON_SCOPE_EXIT { evaluator->dataOffset() = endOffset; }; - - applyTypeAttributes(evaluator, node, pattern); - - if (auto colorValue = attributable->getAttributeValue("color"); colorValue) { - u32 color = strtoul(colorValue->c_str(), nullptr, 16); - pattern->setColor(hex::changeEndianess(color, std::endian::big) >> 8); - } else if (auto singleColor = attributable->hasAttribute("single_color", false); singleColor) { - pattern->setColor(ContentRegistry::PatternLanguage::getNextColor()); - } - - if (auto value = attributable->getAttributeValue("name"); value) { - pattern->setDisplayName(*value); - } - - if (auto value = attributable->getAttributeValue("comment"); value) { - pattern->setComment(*value); - } - - if (attributable->hasAttribute("no_unique_address", false)) { - endOffset -= pattern->getSize(); - } - } - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_bitfield.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_bitfield.hpp deleted file mode 100644 index c8acddd8a..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_bitfield.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace hex::pl { - - class ASTNodeBitfield : public ASTNode, - public Attributable { - public: - ASTNodeBitfield() : ASTNode() { } - - ASTNodeBitfield(const ASTNodeBitfield &other) : ASTNode(other), Attributable(other) { - for (const auto &[name, entry] : other.getEntries()) - this->m_entries.emplace_back(name, entry->clone()); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeBitfield(*this)); - } - - [[nodiscard]] const std::vector>> &getEntries() const { return this->m_entries; } - void addEntry(const std::string &name, std::unique_ptr &&size) { this->m_entries.emplace_back(name, std::move(size)); } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto pattern = std::make_unique(evaluator, evaluator->dataOffset(), 0); - - size_t bitOffset = 0; - std::vector> fields; - - BitfieldOrder order = evaluator->getBitfieldOrder(); - if (this->hasAttribute("left_to_right", false)) - order = BitfieldOrder::LeftToRight; - else if (this->hasAttribute("right_to_left", false)) - order = BitfieldOrder::RightToLeft; - - std::vector> entries; - for (const auto &[name, entry] : this->m_entries) - entries.emplace_back(name, entry.get()); - - if (order == BitfieldOrder::LeftToRight) - std::reverse(entries.begin(), entries.end()); - - evaluator->pushScope(pattern.get(), fields); - ON_SCOPE_EXIT { - evaluator->popScope(); - }; - - for (auto &[name, bitSizeNode] : entries) { - auto literal = bitSizeNode->evaluate(evaluator); - - u8 bitSize = std::visit(overloaded { - [this](const std::string &) -> u8 { LogConsole::abortEvaluation("bitfield field size cannot be a string", this); }, - [this](Pattern *) -> u8 { LogConsole::abortEvaluation("bitfield field size cannot be a custom type", this); }, - [](auto &&offset) -> u8 { return static_cast(offset); } }, - dynamic_cast(literal.get())->getValue()); - - // If a field is named padding, it was created through a padding expression and only advances the bit position - if (name != "padding") { - auto field = std::make_unique(evaluator, evaluator->dataOffset(), bitOffset, bitSize, pattern.get()); - field->setVariableName(name); - - fields.push_back(std::move(field)); - } - - bitOffset += bitSize; - } - - pattern->setSize((bitOffset + 7) / 8); - pattern->setFields(std::move(fields)); - - evaluator->dataOffset() += pattern->getSize(); - - applyTypeAttributes(evaluator, this, pattern.get()); - - return hex::moveToVector>(std::move(pattern)); - } - - private: - std::vector>> m_entries; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_builtin_type.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_builtin_type.hpp deleted file mode 100644 index f76ddb8d8..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_builtin_type.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace hex::pl { - - class ASTNodeBuiltinType : public ASTNode { - public: - constexpr explicit ASTNodeBuiltinType(Token::ValueType type) - : ASTNode(), m_type(type) { } - - [[nodiscard]] constexpr const auto &getType() const { return this->m_type; } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeBuiltinType(*this)); - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto offset = evaluator->dataOffset(); - auto size = Token::getTypeSize(this->m_type); - - evaluator->dataOffset() += size; - - std::unique_ptr pattern; - if (Token::isUnsigned(this->m_type)) - pattern = std::unique_ptr(new PatternUnsigned(evaluator, offset, size)); - else if (Token::isSigned(this->m_type)) - pattern = std::unique_ptr(new PatternSigned(evaluator, offset, size)); - else if (Token::isFloatingPoint(this->m_type)) - pattern = std::unique_ptr(new PatternFloat(evaluator, offset, size)); - else if (this->m_type == Token::ValueType::Boolean) - pattern = std::unique_ptr(new PatternBoolean(evaluator, offset)); - else if (this->m_type == Token::ValueType::Character) - pattern = std::unique_ptr(new PatternCharacter(evaluator, offset)); - else if (this->m_type == Token::ValueType::Character16) - pattern = std::unique_ptr(new PatternWideCharacter(evaluator, offset)); - else if (this->m_type == Token::ValueType::Padding) - pattern = std::unique_ptr(new PatternPadding(evaluator, offset, 1)); - else if (this->m_type == Token::ValueType::String) - pattern = std::unique_ptr(new PatternString(evaluator, offset, 1)); - else if (this->m_type == Token::ValueType::Auto) - return {}; - else - LogConsole::abortEvaluation("invalid built-in type", this); - - pattern->setTypeName(Token::getTypeName(this->m_type)); - - return hex::moveToVector(std::move(pattern)); - } - - private: - const Token::ValueType m_type; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_cast.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_cast.hpp deleted file mode 100644 index f0ff2a43b..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_cast.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeCast : public ASTNode { - public: - ASTNodeCast(std::unique_ptr &&value, std::unique_ptr &&type) : m_value(std::move(value)), m_type(std::move(type)) { } - - ASTNodeCast(const ASTNodeCast &other) : ASTNode(other) { - this->m_value = other.m_value->clone(); - this->m_type = other.m_type->clone(); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeCast(*this)); - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - auto evaluatedValue = this->m_value->evaluate(evaluator); - auto evaluatedType = this->m_type->evaluate(evaluator); - - auto literal = dynamic_cast(evaluatedValue.get()); - auto type = dynamic_cast(evaluatedType.get())->getType(); - - auto typePatterns = this->m_type->createPatterns(evaluator); - auto &typePattern = typePatterns.front(); - - return std::unique_ptr(std::visit(overloaded { - [&, this](Pattern *value) -> ASTNode * { LogConsole::abortEvaluation(hex::format("cannot cast custom type '{}' to '{}'", value->getTypeName(), Token::getTypeName(type)), this); }, - [&, this](const std::string &) -> ASTNode * { LogConsole::abortEvaluation(hex::format("cannot cast string to '{}'", Token::getTypeName(type)), this); }, - [&, this](auto &&value) -> ASTNode * { - auto endianAdjustedValue = hex::changeEndianess(value, typePattern->getSize(), typePattern->getEndian()); - switch (type) { - case Token::ValueType::Unsigned8Bit: - return new ASTNodeLiteral(u128(u8(endianAdjustedValue))); - case Token::ValueType::Unsigned16Bit: - return new ASTNodeLiteral(u128(u16(endianAdjustedValue))); - case Token::ValueType::Unsigned32Bit: - return new ASTNodeLiteral(u128(u32(endianAdjustedValue))); - case Token::ValueType::Unsigned64Bit: - return new ASTNodeLiteral(u128(u64(endianAdjustedValue))); - case Token::ValueType::Unsigned128Bit: - return new ASTNodeLiteral(u128(endianAdjustedValue)); - case Token::ValueType::Signed8Bit: - return new ASTNodeLiteral(i128(i8(endianAdjustedValue))); - case Token::ValueType::Signed16Bit: - return new ASTNodeLiteral(i128(i16(endianAdjustedValue))); - case Token::ValueType::Signed32Bit: - return new ASTNodeLiteral(i128(i32(endianAdjustedValue))); - case Token::ValueType::Signed64Bit: - return new ASTNodeLiteral(i128(i64(endianAdjustedValue))); - case Token::ValueType::Signed128Bit: - return new ASTNodeLiteral(i128(endianAdjustedValue)); - case Token::ValueType::Float: - return new ASTNodeLiteral(double(float(endianAdjustedValue))); - case Token::ValueType::Double: - return new ASTNodeLiteral(double(endianAdjustedValue)); - case Token::ValueType::Character: - return new ASTNodeLiteral(char(endianAdjustedValue)); - case Token::ValueType::Character16: - return new ASTNodeLiteral(u128(char16_t(endianAdjustedValue))); - case Token::ValueType::Boolean: - return new ASTNodeLiteral(bool(endianAdjustedValue)); - case Token::ValueType::String: - { - std::string string(sizeof(value), '\x00'); - std::memcpy(string.data(), &value, string.size()); - hex::trim(string); - - if (typePattern->getEndian() != std::endian::native) - std::reverse(string.begin(), string.end()); - - return new ASTNodeLiteral(string); - } - default: - LogConsole::abortEvaluation(hex::format("cannot cast value to '{}'", Token::getTypeName(type)), this); - } - }, - }, - literal->getValue())); - } - - private: - std::unique_ptr m_value; - std::unique_ptr m_type; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_compound_statement.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_compound_statement.hpp deleted file mode 100644 index 1129e54ba..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_compound_statement.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeCompoundStatement : public ASTNode { - public: - explicit ASTNodeCompoundStatement(std::vector> &&statements, bool newScope = false) : m_statements(std::move(statements)), m_newScope(newScope) { - } - - ASTNodeCompoundStatement(const ASTNodeCompoundStatement &other) : ASTNode(other) { - for (const auto &statement : other.m_statements) { - this->m_statements.push_back(statement->clone()); - } - - this->m_newScope = other.m_newScope; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeCompoundStatement(*this)); - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - std::unique_ptr result = nullptr; - - for (const auto &statement : this->m_statements) { - result = statement->evaluate(evaluator); - } - - return result; - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - std::vector> result; - - for (const auto &statement : this->m_statements) { - auto patterns = statement->createPatterns(evaluator); - std::move(patterns.begin(), patterns.end(), std::back_inserter(result)); - } - - return result; - } - - FunctionResult execute(Evaluator *evaluator) const override { - FunctionResult result; - - auto variables = *evaluator->getScope(0).scope; - u32 startVariableCount = variables.size(); - - if (this->m_newScope) { - evaluator->pushScope(nullptr, variables); - } - - for (const auto &statement : this->m_statements) { - result = statement->execute(evaluator); - if (evaluator->getCurrentControlFlowStatement() != ControlFlowStatement::None) - return result; - } - - if (this->m_newScope) { - i64 stackSize = evaluator->getStack().size(); - for (u32 i = startVariableCount; i < variables.size(); i++) { - stackSize--; - } - if (stackSize < 0) LogConsole::abortEvaluation("stack pointer underflow!", this); - evaluator->getStack().resize(stackSize); - - evaluator->popScope(); - } - - return result; - } - - public: - std::vector> m_statements; - bool m_newScope = false; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_conditional_statement.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_conditional_statement.hpp deleted file mode 100644 index 1525de6e9..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_conditional_statement.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeConditionalStatement : public ASTNode { - public: - explicit ASTNodeConditionalStatement(std::unique_ptr condition, std::vector> &&trueBody, std::vector> &&falseBody) - : ASTNode(), m_condition(std::move(condition)), m_trueBody(std::move(trueBody)), m_falseBody(std::move(falseBody)) { } - - - ASTNodeConditionalStatement(const ASTNodeConditionalStatement &other) : ASTNode(other) { - this->m_condition = other.m_condition->clone(); - - for (auto &statement : other.m_trueBody) - this->m_trueBody.push_back(statement->clone()); - for (auto &statement : other.m_falseBody) - this->m_falseBody.push_back(statement->clone()); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeConditionalStatement(*this)); - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto &scope = *evaluator->getScope(0).scope; - auto &body = evaluateCondition(evaluator) ? this->m_trueBody : this->m_falseBody; - - for (auto &node : body) { - auto newPatterns = node->createPatterns(evaluator); - for (auto &pattern : newPatterns) { - scope.push_back(std::move(pattern)); - } - } - - return {}; - } - - [[nodiscard]] const std::unique_ptr &getCondition() { - return this->m_condition; - } - - FunctionResult execute(Evaluator *evaluator) const override { - auto &body = evaluateCondition(evaluator) ? this->m_trueBody : this->m_falseBody; - - auto variables = *evaluator->getScope(0).scope; - auto parameterPack = evaluator->getScope(0).parameterPack; - - u32 startVariableCount = variables.size(); - ON_SCOPE_EXIT { - i64 stackSize = evaluator->getStack().size(); - for (u32 i = startVariableCount; i < variables.size(); i++) { - stackSize--; - } - if (stackSize < 0) LogConsole::abortEvaluation("stack pointer underflow!", this); - evaluator->getStack().resize(stackSize); - }; - - evaluator->pushScope(nullptr, variables); - evaluator->getScope(0).parameterPack = parameterPack; - ON_SCOPE_EXIT { - evaluator->popScope(); - }; - - for (auto &statement : body) { - auto result = statement->execute(evaluator); - if (auto ctrlStatement = evaluator->getCurrentControlFlowStatement(); ctrlStatement != ControlFlowStatement::None) { - return result; - } - } - - return std::nullopt; - } - - private: - [[nodiscard]] bool evaluateCondition(Evaluator *evaluator) const { - const auto node = this->m_condition->evaluate(evaluator); - const auto literal = dynamic_cast(node.get()); - - return std::visit(overloaded { - [](const std::string &value) -> bool { return !value.empty(); }, - [this](Pattern *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); }, - [](auto &&value) -> bool { return value != 0; } }, - literal->getValue()); - } - - std::unique_ptr m_condition; - std::vector> m_trueBody, m_falseBody; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_control_flow_statement.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_control_flow_statement.hpp deleted file mode 100644 index bc774e490..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_control_flow_statement.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeControlFlowStatement : public ASTNode { - public: - explicit ASTNodeControlFlowStatement(ControlFlowStatement type, std::unique_ptr &&rvalue) : m_type(type), m_rvalue(std::move(rvalue)) { - } - - ASTNodeControlFlowStatement(const ASTNodeControlFlowStatement &other) : ASTNode(other) { - this->m_type = other.m_type; - - if (other.m_rvalue != nullptr) - this->m_rvalue = other.m_rvalue->clone(); - else - this->m_rvalue = nullptr; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeControlFlowStatement(*this)); - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - - this->execute(evaluator); - - return {}; - } - - FunctionResult execute(Evaluator *evaluator) const override { - if (this->m_rvalue == nullptr) { - evaluator->setCurrentControlFlowStatement(this->m_type); - return std::nullopt; - } else { - auto returnValue = this->m_rvalue->evaluate(evaluator); - auto literal = dynamic_cast(returnValue.get()); - - evaluator->setCurrentControlFlowStatement(this->m_type); - - if (literal == nullptr) - return std::nullopt; - else - return literal->getValue(); - } - } - - private: - ControlFlowStatement m_type; - std::unique_ptr m_rvalue; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_enum.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_enum.hpp deleted file mode 100644 index 3e4c2340b..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_enum.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace hex::pl { - - class ASTNodeEnum : public ASTNode, - public Attributable { - public: - explicit ASTNodeEnum(std::unique_ptr &&underlyingType) : ASTNode(), m_underlyingType(std::move(underlyingType)) { } - - ASTNodeEnum(const ASTNodeEnum &other) : ASTNode(other), Attributable(other) { - for (const auto &[name, entry] : other.getEntries()) - this->m_entries.emplace(name, entry->clone()); - this->m_underlyingType = other.m_underlyingType->clone(); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeEnum(*this)); - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto pattern = std::make_unique(evaluator, evaluator->dataOffset(), 0); - - std::vector> enumEntries; - for (const auto &[name, value] : this->m_entries) { - const auto node = value->evaluate(evaluator); - auto literal = dynamic_cast(node.get()); - - enumEntries.emplace_back(literal->getValue(), name); - } - - pattern->setEnumValues(enumEntries); - - const auto nodes = this->m_underlyingType->createPatterns(evaluator); - auto &underlying = nodes.front(); - - pattern->setSize(underlying->getSize()); - pattern->setEndian(underlying->getEndian()); - - applyTypeAttributes(evaluator, this, pattern.get()); - - return hex::moveToVector>(std::move(pattern)); - } - - [[nodiscard]] const std::map> &getEntries() const { return this->m_entries; } - void addEntry(const std::string &name, std::unique_ptr &&expression) { this->m_entries.insert({ name, std::move(expression) }); } - - [[nodiscard]] const std::unique_ptr &getUnderlyingType() { return this->m_underlyingType; } - - private: - std::map> m_entries; - std::unique_ptr m_underlyingType; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_function_call.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_function_call.hpp deleted file mode 100644 index 016247afb..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_function_call.hpp +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include - -namespace hex::pl { - - class ASTNodeFunctionCall : public ASTNode { - public: - explicit ASTNodeFunctionCall(std::string functionName, std::vector> &¶ms) - : ASTNode(), m_functionName(std::move(functionName)), m_params(std::move(params)) { } - - ASTNodeFunctionCall(const ASTNodeFunctionCall &other) : ASTNode(other) { - this->m_functionName = other.m_functionName; - - for (auto ¶m : other.m_params) - this->m_params.push_back(param->clone()); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeFunctionCall(*this)); - } - - [[nodiscard]] const std::string &getFunctionName() { - return this->m_functionName; - } - - [[nodiscard]] const std::vector> &getParams() const { - return this->m_params; - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - - this->execute(evaluator); - - return {}; - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - auto startOffset = evaluator->dataOffset(); - ON_SCOPE_EXIT { evaluator->dataOffset() = startOffset; }; - - std::vector evaluatedParams; - for (auto ¶m : this->m_params) { - const auto expression = param->evaluate(evaluator)->evaluate(evaluator); - - if (auto literal = dynamic_cast(expression.get())) { - evaluatedParams.push_back(literal->getValue()); - } else if (auto parameterPack = dynamic_cast(expression.get())) { - for (auto &value : parameterPack->getValues()) { - evaluatedParams.push_back(value); - } - } - } - - auto &customFunctions = evaluator->getCustomFunctions(); - auto functions = ContentRegistry::PatternLanguage::getFunctions(); - - for (auto &func : customFunctions) - functions.insert(func); - - if (!functions.contains(this->m_functionName)) { - if (this->m_functionName.starts_with("std::")) { - evaluator->getConsole().log(LogConsole::Level::Warning, "This function might be part of the standard library.\nYou can install the standard library though\nthe Content Store found under Help -> Content Store and then\ninclude the correct file."); - } - - LogConsole::abortEvaluation(hex::format("call to unknown function '{}'", this->m_functionName), this); - } - - using namespace ContentRegistry::PatternLanguage; - - auto function = functions[this->m_functionName]; - const auto &[min, max] = function.parameterCount; - - if (evaluatedParams.size() >= min && evaluatedParams.size() < max) { - while (true) { - auto remainingParams = max - evaluatedParams.size(); - if (remainingParams <= 0) - break; - - auto offset = evaluatedParams.size() - min; - if (offset >= function.defaultParameters.size()) - break; - - evaluatedParams.push_back(function.defaultParameters[offset]); - } - } - - if (evaluatedParams.size() < min) - LogConsole::abortEvaluation(hex::format("too few parameters for function '{0}'. Expected {1} at least", this->m_functionName, min), this); - else if (evaluatedParams.size() > max) - LogConsole::abortEvaluation(hex::format("too many parameters for function '{0}'. Expected {1} at most", this->m_functionName, max), this); - - try { - if (function.dangerous && evaluator->getDangerousFunctionPermission() != DangerousFunctionPermission::Allow) { - evaluator->dangerousFunctionCalled(); - - while (evaluator->getDangerousFunctionPermission() == DangerousFunctionPermission::Ask) { - using namespace std::literals::chrono_literals; - - std::this_thread::sleep_for(100ms); - } - - if (evaluator->getDangerousFunctionPermission() == DangerousFunctionPermission::Deny) { - LogConsole::abortEvaluation(hex::format("calling of dangerous function '{}' is not allowed", this->m_functionName), this); - } - } - - auto result = function.func(evaluator, evaluatedParams); - - if (result.has_value()) - return std::unique_ptr(new ASTNodeLiteral(std::move(result.value()))); - else - return std::unique_ptr(new ASTNodeMathematicalExpression(nullptr, nullptr, Token::Operator::Plus)); - } catch (std::string &error) { - LogConsole::abortEvaluation(error, this); - } - - return nullptr; - } - - FunctionResult execute(Evaluator *evaluator) const override { - (void)this->evaluate(evaluator); - - return {}; - } - - private: - std::string m_functionName; - std::vector> m_params; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_function_definition.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_function_definition.hpp deleted file mode 100644 index 8c015d1dd..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_function_definition.hpp +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeFunctionDefinition : public ASTNode { - public: - ASTNodeFunctionDefinition(std::string name, std::vector>> &¶ms, std::vector> &&body, std::optional parameterPack, std::vector> &&defaultParameters) - : m_name(std::move(name)), m_params(std::move(params)), m_body(std::move(body)), m_parameterPack(std::move(parameterPack)), m_defaultParameters(std::move(defaultParameters)) { - } - - ASTNodeFunctionDefinition(const ASTNodeFunctionDefinition &other) : ASTNode(other) { - this->m_name = other.m_name; - this->m_parameterPack = other.m_parameterPack; - - for (const auto &[name, type] : other.m_params) { - this->m_params.emplace_back(name, type->clone()); - } - - for (auto &statement : other.m_body) { - this->m_body.push_back(statement->clone()); - } - - for (auto &statement : other.m_defaultParameters) { - this->m_body.push_back(statement->clone()); - } - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeFunctionDefinition(*this)); - } - - [[nodiscard]] const std::string &getName() const { - return this->m_name; - } - - [[nodiscard]] const auto &getParams() const { - return this->m_params; - } - - [[nodiscard]] const auto &getBody() const { - return this->m_body; - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - using namespace ContentRegistry::PatternLanguage; - - ParameterCount paramCount; - - if (this->m_parameterPack.has_value() && !this->m_defaultParameters.empty()) - paramCount = ParameterCount::atLeast(this->m_params.size() - this->m_defaultParameters.size()); - else if (this->m_parameterPack.has_value()) - paramCount = ParameterCount::atLeast(this->m_params.size()); - else if (!this->m_defaultParameters.empty()) - paramCount = ParameterCount::between(this->m_params.size() - this->m_defaultParameters.size(), this->m_params.size()); - else - paramCount = ParameterCount::exactly(this->m_params.size()); - - std::vector evaluatedDefaultParams; - for (const auto ¶m : this->m_defaultParameters) { - const auto expression = param->evaluate(evaluator)->evaluate(evaluator); - - if (auto literal = dynamic_cast(expression.get())) { - evaluatedDefaultParams.push_back(literal->getValue()); - } else { - LogConsole::abortEvaluation(hex::format("invalid default parameter for function {}", this->m_name), expression); - } - } - - evaluator->addCustomFunction(this->m_name, paramCount, evaluatedDefaultParams, [this](Evaluator *ctx, const std::vector ¶ms) -> std::optional { - std::vector> variables; - - auto startOffset = ctx->dataOffset(); - ctx->pushScope(nullptr, variables); - ON_SCOPE_EXIT { - ctx->popScope(); - ctx->dataOffset() = startOffset; - }; - - if (this->m_parameterPack.has_value()) { - std::vector parameterPackContent; - for (u32 paramIndex = this->m_params.size(); paramIndex < params.size(); paramIndex++) - parameterPackContent.push_back(params[paramIndex]); - - ctx->createParameterPack(this->m_parameterPack.value(), parameterPackContent); - } - - for (u32 paramIndex = 0; paramIndex < this->m_params.size() && paramIndex < params.size(); paramIndex++) { - const auto &[name, type] = this->m_params[paramIndex]; - - ctx->createVariable(name, type.get(), params[paramIndex]); - ctx->setVariable(name, params[paramIndex]); - } - - for (auto &statement : this->m_body) { - auto result = statement->execute(ctx); - - if (ctx->getCurrentControlFlowStatement() != ControlFlowStatement::None) { - switch (ctx->getCurrentControlFlowStatement()) { - case ControlFlowStatement::Break: - LogConsole::abortEvaluation("break statement not within a loop", statement); - case ControlFlowStatement::Continue: - LogConsole::abortEvaluation("continue statement not within a loop", statement); - default: - break; - } - - ctx->setCurrentControlFlowStatement(ControlFlowStatement::None); - return result; - } - } - - return {}; - }); - - return nullptr; - } - - - private: - std::string m_name; - std::vector>> m_params; - std::vector> m_body; - std::optional m_parameterPack; - std::vector> m_defaultParameters; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_literal.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_literal.hpp deleted file mode 100644 index 7be3e7c20..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_literal.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeLiteral : public ASTNode { - public: - explicit ASTNodeLiteral(Token::Literal literal) : ASTNode(), m_literal(std::move(literal)) { } - - ASTNodeLiteral(const ASTNodeLiteral &) = default; - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeLiteral(*this)); - } - - [[nodiscard]] const auto &getValue() const { - return this->m_literal; - } - - private: - Token::Literal m_literal; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_mathematical_expression.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_mathematical_expression.hpp deleted file mode 100644 index 4cc0ce9db..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_mathematical_expression.hpp +++ /dev/null @@ -1,216 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - -#define FLOAT_BIT_OPERATION(name) \ - auto name(hex::floating_point auto left, auto right) const { \ - hex::unused(left, right); \ - LogConsole::abortEvaluation("invalid floating point operation", this); \ - return 0; \ - } \ - auto name(auto left, hex::floating_point auto right) const { \ - hex::unused(left, right); \ - LogConsole::abortEvaluation("invalid floating point operation", this); \ - return 0; \ - } \ - auto name(hex::floating_point auto left, hex::floating_point auto right) const { \ - hex::unused(left, right); \ - LogConsole::abortEvaluation("invalid floating point operation", this); \ - return 0; \ - } \ - auto name(hex::integral auto left, hex::integral auto right) const - - class ASTNodeMathematicalExpression : public ASTNode { - - FLOAT_BIT_OPERATION(shiftLeft) { - return left << right; - } - - FLOAT_BIT_OPERATION(shiftRight) { - return left >> right; - } - - FLOAT_BIT_OPERATION(bitAnd) { - return left & right; - } - - FLOAT_BIT_OPERATION(bitOr) { - return left | right; - } - - FLOAT_BIT_OPERATION(bitXor) { - return left ^ right; - } - - FLOAT_BIT_OPERATION(bitNot) { - hex::unused(left); - - return ~static_cast(right); - } - - FLOAT_BIT_OPERATION(modulus) { - return left % right; - } - -#undef FLOAT_BIT_OPERATION - public: - ASTNodeMathematicalExpression(std::unique_ptr &&left, std::unique_ptr &&right, Token::Operator op) - : ASTNode(), m_left(std::move(left)), m_right(std::move(right)), m_operator(op) { } - - ASTNodeMathematicalExpression(const ASTNodeMathematicalExpression &other) : ASTNode(other) { - this->m_operator = other.m_operator; - this->m_left = other.m_left->clone(); - this->m_right = other.m_right->clone(); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeMathematicalExpression(*this)); - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - if (this->getLeftOperand() == nullptr || this->getRightOperand() == nullptr) - LogConsole::abortEvaluation("attempted to use void expression in mathematical expression", this); - - auto leftValue = this->getLeftOperand()->evaluate(evaluator); - auto rightValue = this->getRightOperand()->evaluate(evaluator); - - auto *left = dynamic_cast(leftValue.get()); - auto *right = dynamic_cast(rightValue.get()); - - return std::unique_ptr(std::visit(overloaded { - // TODO: :notlikethis: - [this](u128, Pattern *const ) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](i128, Pattern *const &) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](double, Pattern *const &) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](char, Pattern *const &) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](bool, Pattern *const &) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](const std::string &, Pattern *const &) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](Pattern *const &, u128) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](Pattern *const &, i128) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](Pattern *const &, double) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](Pattern *const &, char) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](Pattern *const &, bool) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](Pattern *const &, const std::string &) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](Pattern *const &, Pattern *const &) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - - [this](auto &&, const std::string &) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); }, - [this](const std::string &left, auto &&right) -> ASTNode * { - switch (this->getOperator()) { - case Token::Operator::Star: - { - if (static_cast(right) < 0) - LogConsole::abortEvaluation("cannot repeat string a negative number of times", this); - - std::string result; - for (u128 i = 0; i < static_cast(right); i++) - result += left; - return new ASTNodeLiteral(result); - } - default: - LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); - } - }, - [this](const std::string &left, const std::string &right) -> ASTNode * { - switch (this->getOperator()) { - case Token::Operator::Plus: - return new ASTNodeLiteral(left + right); - case Token::Operator::BoolEquals: - return new ASTNodeLiteral(left == right); - case Token::Operator::BoolNotEquals: - return new ASTNodeLiteral(left != right); - case Token::Operator::BoolGreaterThan: - return new ASTNodeLiteral(left > right); - case Token::Operator::BoolLessThan: - return new ASTNodeLiteral(left < right); - case Token::Operator::BoolGreaterThanOrEquals: - return new ASTNodeLiteral(left >= right); - case Token::Operator::BoolLessThanOrEquals: - return new ASTNodeLiteral(left <= right); - default: - LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); - } - }, - [this](const std::string &left, char right) -> ASTNode * { - switch (this->getOperator()) { - case Token::Operator::Plus: - return new ASTNodeLiteral(left + right); - default: - LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); - } - }, - [this](char left, const std::string &right) -> ASTNode * { - switch (this->getOperator()) { - case Token::Operator::Plus: - return new ASTNodeLiteral(left + right); - default: - LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); - } - }, - [this](auto &&left, auto &&right) -> ASTNode * { - switch (this->getOperator()) { - case Token::Operator::Plus: - return new ASTNodeLiteral(left + right); - case Token::Operator::Minus: - return new ASTNodeLiteral(left - right); - case Token::Operator::Star: - return new ASTNodeLiteral(left * right); - case Token::Operator::Slash: - if (right == 0) LogConsole::abortEvaluation("division by zero!", this); - return new ASTNodeLiteral(left / right); - case Token::Operator::Percent: - if (right == 0) LogConsole::abortEvaluation("division by zero!", this); - return new ASTNodeLiteral(modulus(left, right)); - case Token::Operator::ShiftLeft: - return new ASTNodeLiteral(shiftLeft(left, right)); - case Token::Operator::ShiftRight: - return new ASTNodeLiteral(shiftRight(left, right)); - case Token::Operator::BitAnd: - return new ASTNodeLiteral(bitAnd(left, right)); - case Token::Operator::BitXor: - return new ASTNodeLiteral(bitXor(left, right)); - case Token::Operator::BitOr: - return new ASTNodeLiteral(bitOr(left, right)); - case Token::Operator::BitNot: - return new ASTNodeLiteral(bitNot(left, right)); - case Token::Operator::BoolEquals: - return new ASTNodeLiteral(bool(left == static_cast(right))); - case Token::Operator::BoolNotEquals: - return new ASTNodeLiteral(bool(left != static_cast(right))); - case Token::Operator::BoolGreaterThan: - return new ASTNodeLiteral(bool(left > static_cast(right))); - case Token::Operator::BoolLessThan: - return new ASTNodeLiteral(bool(left < static_cast(right))); - case Token::Operator::BoolGreaterThanOrEquals: - return new ASTNodeLiteral(bool(left >= static_cast(right))); - case Token::Operator::BoolLessThanOrEquals: - return new ASTNodeLiteral(bool(left <= static_cast(right))); - case Token::Operator::BoolAnd: - return new ASTNodeLiteral(bool(left && right)); - case Token::Operator::BoolXor: - return new ASTNodeLiteral(bool((left && !right) || (!left && right))); - case Token::Operator::BoolOr: - return new ASTNodeLiteral(bool(left || right)); - case Token::Operator::BoolNot: - return new ASTNodeLiteral(bool(!right)); - default: - LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); - } - } }, - left->getValue(), - right->getValue())); - } - - [[nodiscard]] const std::unique_ptr &getLeftOperand() const { return this->m_left; } - [[nodiscard]] const std::unique_ptr &getRightOperand() const { return this->m_right; } - [[nodiscard]] Token::Operator getOperator() const { return this->m_operator; } - - private: - std::unique_ptr m_left, m_right; - Token::Operator m_operator; - }; - -#undef FLOAT_BIT_OPERATION - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_multi_variable_decl.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_multi_variable_decl.hpp deleted file mode 100644 index d108d9ccf..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_multi_variable_decl.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include - -#include - -namespace hex::pl { - - class ASTNodeMultiVariableDecl : public ASTNode { - public: - explicit ASTNodeMultiVariableDecl(std::vector> &&variables) : m_variables(std::move(variables)) { } - - ASTNodeMultiVariableDecl(const ASTNodeMultiVariableDecl &other) : ASTNode(other) { - for (auto &variable : other.m_variables) - this->m_variables.push_back(variable->clone()); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeMultiVariableDecl(*this)); - } - - [[nodiscard]] const std::vector> &getVariables() { - return this->m_variables; - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - std::vector> patterns; - - for (auto &node : this->m_variables) { - auto newPatterns = node->createPatterns(evaluator); - std::move(newPatterns.begin(), newPatterns.end(), std::back_inserter(patterns)); - } - - return patterns; - } - - FunctionResult execute(Evaluator *evaluator) const override { - for (auto &variable : this->m_variables) { - auto variableDecl = dynamic_cast(variable.get()); - auto variableType = variableDecl->getType()->evaluate(evaluator); - - evaluator->createVariable(variableDecl->getName(), variableType.get()); - } - - return std::nullopt; - } - - private: - std::vector> m_variables; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_parameter_pack.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_parameter_pack.hpp deleted file mode 100644 index a008a9e0a..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_parameter_pack.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeParameterPack : public ASTNode { - public: - explicit ASTNodeParameterPack(std::vector &&values) : m_values(std::move(values)) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeParameterPack(*this)); - } - - [[nodiscard]] const std::vector &getValues() const { - return this->m_values; - } - - private: - std::vector m_values; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_pointer_variable_decl.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_pointer_variable_decl.hpp deleted file mode 100644 index 796b925e4..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_pointer_variable_decl.hpp +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace hex::pl { - - class ASTNodePointerVariableDecl : public ASTNode, - public Attributable { - public: - ASTNodePointerVariableDecl(std::string name, std::shared_ptr type, std::shared_ptr sizeType, std::unique_ptr &&placementOffset = nullptr) - : ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_sizeType(std::move(sizeType)), m_placementOffset(std::move(placementOffset)) { } - - ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other) : ASTNode(other), Attributable(other) { - this->m_name = other.m_name; - this->m_type = other.m_type; - this->m_sizeType = other.m_sizeType; - - if (other.m_placementOffset != nullptr) - this->m_placementOffset = other.m_placementOffset->clone(); - else - this->m_placementOffset = nullptr; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodePointerVariableDecl(*this)); - } - - [[nodiscard]] const std::string &getName() const { return this->m_name; } - [[nodiscard]] constexpr const std::shared_ptr &getType() const { return this->m_type; } - [[nodiscard]] constexpr const std::shared_ptr &getSizeType() const { return this->m_sizeType; } - [[nodiscard]] constexpr const std::unique_ptr &getPlacementOffset() const { return this->m_placementOffset; } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto startOffset = evaluator->dataOffset(); - - if (this->m_placementOffset != nullptr) { - const auto node = this->m_placementOffset->evaluate(evaluator); - const auto offset = dynamic_cast(node.get()); - - evaluator->dataOffset() = std::visit(overloaded { - [this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); }, - [this](const std::shared_ptr &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); }, - [](auto &&offset) -> u64 { return u64(offset); } }, - offset->getValue()); - } - - auto pointerStartOffset = evaluator->dataOffset(); - - const auto sizePatterns = this->m_sizeType->createPatterns(evaluator); - const auto &sizePattern = sizePatterns.front(); - - auto pattern = std::make_unique(evaluator, pointerStartOffset, sizePattern->getSize()); - pattern->setVariableName(this->m_name); - - auto pointerEndOffset = evaluator->dataOffset(); - - { - u128 pointerAddress = 0; - evaluator->getProvider()->read(pattern->getOffset(), &pointerAddress, pattern->getSize()); - pointerAddress = hex::changeEndianess(pointerAddress, sizePattern->getSize(), sizePattern->getEndian()); - - evaluator->dataOffset() = pointerStartOffset; - - pattern->setPointedAtAddress(pointerAddress); - applyVariableAttributes(evaluator, this, pattern.get()); - - evaluator->dataOffset() = pattern->getPointedAtAddress(); - - auto pointedAtPatterns = this->m_type->createPatterns(evaluator); - auto &pointedAtPattern = pointedAtPatterns.front(); - - pattern->setPointedAtPattern(std::move(pointedAtPattern)); - pattern->setEndian(sizePattern->getEndian()); - } - - if (this->m_placementOffset != nullptr && !evaluator->isGlobalScope()) { - evaluator->dataOffset() = startOffset; - } else { - evaluator->dataOffset() = pointerEndOffset; - } - - return hex::moveToVector>(std::move(pattern)); - } - - private: - std::string m_name; - std::shared_ptr m_type; - std::shared_ptr m_sizeType; - std::unique_ptr m_placementOffset; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_rvalue.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_rvalue.hpp deleted file mode 100644 index 544d9a551..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_rvalue.hpp +++ /dev/null @@ -1,293 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace hex::pl { - - class ASTNodeRValue : public ASTNode { - public: - using PathSegment = std::variant>; - using Path = std::vector; - - explicit ASTNodeRValue(Path &&path) : ASTNode(), m_path(std::move(path)) { } - - ASTNodeRValue(const ASTNodeRValue &other) : ASTNode(other) { - for (auto &part : other.m_path) { - if (auto stringPart = std::get_if(&part); stringPart != nullptr) - this->m_path.push_back(*stringPart); - else if (auto nodePart = std::get_if>(&part); nodePart != nullptr) - this->m_path.push_back((*nodePart)->clone()); - } - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeRValue(*this)); - } - - [[nodiscard]] const Path &getPath() const { - return this->m_path; - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - if (this->getPath().size() == 1) { - if (auto name = std::get_if(&this->getPath().front()); name != nullptr) { - if (*name == "$") return std::unique_ptr(new ASTNodeLiteral(u128(evaluator->dataOffset()))); - - auto parameterPack = evaluator->getScope(0).parameterPack; - if (parameterPack && *name == parameterPack->name) - return std::unique_ptr(new ASTNodeParameterPack(std::move(parameterPack->values))); - } - } - - auto patterns = this->createPatterns(evaluator); - auto &pattern = patterns.front(); - - Token::Literal literal; - if (dynamic_cast(pattern.get()) || dynamic_cast(pattern.get())) { - u128 value = 0; - readVariable(evaluator, value, pattern.get()); - literal = value; - } else if (dynamic_cast(pattern.get())) { - i128 value = 0; - readVariable(evaluator, value, pattern.get()); - value = hex::signExtend(pattern->getSize() * 8, value); - literal = value; - } else if (dynamic_cast(pattern.get())) { - if (pattern->getSize() == sizeof(u16)) { - u16 value = 0; - readVariable(evaluator, value, pattern.get()); - literal = double(float16ToFloat32(value)); - } else if (pattern->getSize() == sizeof(float)) { - float value = 0; - readVariable(evaluator, value, pattern.get()); - literal = double(value); - } else if (pattern->getSize() == sizeof(double)) { - double value = 0; - readVariable(evaluator, value, pattern.get()); - literal = value; - } else LogConsole::abortEvaluation("invalid floating point type access", this); - } else if (dynamic_cast(pattern.get())) { - char value = 0; - readVariable(evaluator, value, pattern.get()); - literal = value; - } else if (dynamic_cast(pattern.get())) { - bool value = false; - readVariable(evaluator, value, pattern.get()); - literal = value; - } else if (dynamic_cast(pattern.get())) { - std::string value; - - if (pattern->isLocal()) { - auto &variableValue = evaluator->getStack()[pattern->getOffset()]; - - std::visit(overloaded { - [&](char assignmentValue) { if (assignmentValue != 0x00) value = std::string({ assignmentValue }); }, - [&](std::string &assignmentValue) { value = assignmentValue; }, - [&, this](Pattern *const &assignmentValue) { - if (!dynamic_cast(assignmentValue) && !dynamic_cast(assignmentValue)) - LogConsole::abortEvaluation(hex::format("cannot assign '{}' to string", pattern->getTypeName()), this); - - readVariable(evaluator, value, assignmentValue); - }, - [&, this](auto &&) { LogConsole::abortEvaluation(hex::format("cannot assign '{}' to string", pattern->getTypeName()), this); } }, - variableValue); - } else { - value.resize(pattern->getSize()); - evaluator->getProvider()->read(pattern->getOffset(), value.data(), value.size()); - value.erase(std::find(value.begin(), value.end(), '\0'), value.end()); - } - - literal = value; - } else if (auto bitfieldFieldPattern = dynamic_cast(pattern.get())) { - u64 value = 0; - readVariable(evaluator, value, pattern.get()); - literal = u128(hex::extract(bitfieldFieldPattern->getBitOffset() + (bitfieldFieldPattern->getBitSize() - 1), bitfieldFieldPattern->getBitOffset(), value)); - } else { - literal = pattern.get(); - } - - if (auto transformFunc = pattern->getTransformFunction(); transformFunc.has_value()) { - auto result = transformFunc->func(evaluator, { std::move(literal) }); - - if (!result.has_value()) - LogConsole::abortEvaluation("transform function did not return a value", this); - literal = std::move(result.value()); - } - - return std::unique_ptr(new ASTNodeLiteral(std::move(literal))); - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - std::vector> searchScope; - std::unique_ptr currPattern; - i32 scopeIndex = 0; - - - if (!evaluator->isGlobalScope()) { - auto globalScope = evaluator->getGlobalScope().scope; - std::copy(globalScope->begin(), globalScope->end(), std::back_inserter(searchScope)); - } - - { - auto currScope = evaluator->getScope(scopeIndex).scope; - std::copy(currScope->begin(), currScope->end(), std::back_inserter(searchScope)); - } - - for (const auto &part : this->getPath()) { - - if (part.index() == 0) { - // Variable access - auto name = std::get(part); - - if (name == "parent") { - scopeIndex--; - - if (static_cast(std::abs(scopeIndex)) >= evaluator->getScopeCount()) - LogConsole::abortEvaluation("cannot access parent of global scope", this); - - searchScope = *evaluator->getScope(scopeIndex).scope; - auto currParent = evaluator->getScope(scopeIndex).parent; - - if (currParent == nullptr) { - currPattern = nullptr; - } else { - currPattern = currParent->clone(); - } - - continue; - } else if (name == "this") { - searchScope = *evaluator->getScope(scopeIndex).scope; - - auto currParent = evaluator->getScope(0).parent; - - if (currParent == nullptr) - LogConsole::abortEvaluation("invalid use of 'this' outside of struct-like type", this); - - currPattern = currParent->clone(); - continue; - } else { - bool found = false; - for (auto iter = searchScope.crbegin(); iter != searchScope.crend(); ++iter) { - if ((*iter)->getVariableName() == name) { - currPattern = (*iter)->clone(); - found = true; - break; - } - } - - if (name == "$") - LogConsole::abortEvaluation("invalid use of placeholder operator in rvalue"); - - if (!found) { - LogConsole::abortEvaluation(hex::format("no variable named '{}' found", name), this); - } - } - } else { - // Array indexing - auto node = std::get>(part)->evaluate(evaluator); - auto index = dynamic_cast(node.get()); - - std::visit(overloaded { - [this](const std::string &) { LogConsole::abortEvaluation("cannot use string to index array", this); }, - [this](Pattern *) { LogConsole::abortEvaluation("cannot use custom type to index array", this); }, - [&, this](auto &&index) { - if (auto dynamicArrayPattern = dynamic_cast(currPattern.get())) { - if (static_cast(index) >= searchScope.size() || static_cast(index) < 0) - LogConsole::abortEvaluation("array index out of bounds", this); - - currPattern = searchScope[index]->clone(); - } else if (auto staticArrayPattern = dynamic_cast(currPattern.get())) { - if (static_cast(index) >= staticArrayPattern->getEntryCount() || static_cast(index) < 0) - LogConsole::abortEvaluation("array index out of bounds", this); - - auto newPattern = searchScope.front()->clone(); - newPattern->setOffset(staticArrayPattern->getOffset() + index * staticArrayPattern->getTemplate()->getSize()); - currPattern = std::move(newPattern); - } - } }, - index->getValue()); - } - - if (currPattern == nullptr) - break; - - if (auto pointerPattern = dynamic_cast(currPattern.get())) { - currPattern = pointerPattern->getPointedAtPattern()->clone(); - } - - Pattern *indexPattern; - if (currPattern->isLocal()) { - auto stackLiteral = evaluator->getStack()[currPattern->getOffset()]; - if (auto stackPattern = std::get_if(&stackLiteral); stackPattern != nullptr) - indexPattern = *stackPattern; - else - return hex::moveToVector>(std::move(currPattern)); - } else - indexPattern = currPattern.get(); - - if (auto structPattern = dynamic_cast(indexPattern)) - searchScope = structPattern->getMembers(); - else if (auto unionPattern = dynamic_cast(indexPattern)) - searchScope = unionPattern->getMembers(); - else if (auto bitfieldPattern = dynamic_cast(indexPattern)) - searchScope = bitfieldPattern->getFields(); - else if (auto dynamicArrayPattern = dynamic_cast(indexPattern)) - searchScope = dynamicArrayPattern->getEntries(); - else if (auto staticArrayPattern = dynamic_cast(indexPattern)) - searchScope = { staticArrayPattern->getTemplate() }; - } - - if (currPattern == nullptr) - LogConsole::abortEvaluation("cannot reference global scope", this); - - return hex::moveToVector>(std::move(currPattern)); - } - - private: - Path m_path; - - void readVariable(Evaluator *evaluator, auto &value, Pattern *variablePattern) const { - constexpr bool isString = std::same_as, std::string>; - - if (variablePattern->isLocal()) { - auto &literal = evaluator->getStack()[variablePattern->getOffset()]; - - std::visit(overloaded { - [&](std::string &assignmentValue) { - if constexpr (isString) value = assignmentValue; - }, - [&](Pattern *assignmentValue) { readVariable(evaluator, value, assignmentValue); }, - [&](auto &&assignmentValue) { value = assignmentValue; } }, - literal); - } else { - if constexpr (isString) { - value.resize(variablePattern->getSize()); - evaluator->getProvider()->read(variablePattern->getOffset(), value.data(), value.size()); - value.erase(std::find(value.begin(), value.end(), '\0'), value.end()); - } else { - evaluator->getProvider()->read(variablePattern->getOffset(), &value, variablePattern->getSize()); - } - } - - if constexpr (!isString) - value = hex::changeEndianess(value, variablePattern->getSize(), variablePattern->getEndian()); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_scope_resolution.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_scope_resolution.hpp deleted file mode 100644 index df375b73f..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_scope_resolution.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeScopeResolution : public ASTNode { - public: - explicit ASTNodeScopeResolution(std::unique_ptr &&type, std::string name) : ASTNode(), m_type(std::move(type)), m_name(std::move(name)) { } - - ASTNodeScopeResolution(const ASTNodeScopeResolution &other) : ASTNode(other) { - this->m_type = other.m_type->clone(); - this->m_name = other.m_name; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeScopeResolution(*this)); - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - auto type = this->m_type->evaluate(evaluator); - - if (auto enumType = dynamic_cast(type.get())) { - for (auto &[name, value] : enumType->getEntries()) { - if (name == this->m_name) - return value->evaluate(evaluator); - } - } else { - LogConsole::abortEvaluation("invalid scope resolution. Cannot access this type"); - } - - LogConsole::abortEvaluation(hex::format("could not find constant '{}'", this->m_name), this); - } - - private: - std::unique_ptr m_type; - std::string m_name; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_struct.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_struct.hpp deleted file mode 100644 index 9ca36c305..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_struct.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace hex::pl { - - class ASTNodeStruct : public ASTNode, - public Attributable { - public: - ASTNodeStruct() : ASTNode() { } - - ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other), Attributable(other) { - for (const auto &otherMember : other.getMembers()) - this->m_members.push_back(otherMember->clone()); - for (const auto &otherInheritance : other.getInheritance()) - this->m_inheritance.push_back(otherInheritance->clone()); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeStruct(*this)); - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto pattern = std::make_unique(evaluator, evaluator->dataOffset(), 0); - - u64 startOffset = evaluator->dataOffset(); - std::vector> memberPatterns; - - evaluator->pushScope(pattern.get(), memberPatterns); - ON_SCOPE_EXIT { - evaluator->popScope(); - }; - - for (auto &inheritance : this->m_inheritance) { - auto inheritancePatterns = inheritance->createPatterns(evaluator); - auto &inheritancePattern = inheritancePatterns.front(); - - if (auto structPattern = dynamic_cast(inheritancePattern.get())) { - for (auto &member : structPattern->getMembers()) { - memberPatterns.push_back(member->clone()); - } - } - } - - for (auto &member : this->m_members) { - for (auto &memberPattern : member->createPatterns(evaluator)) { - memberPatterns.push_back(std::move(memberPattern)); - } - } - - pattern->setMembers(std::move(memberPatterns)); - pattern->setSize(evaluator->dataOffset() - startOffset); - - applyTypeAttributes(evaluator, this, pattern.get()); - - return hex::moveToVector>(std::move(pattern)); - } - - [[nodiscard]] const std::vector> &getMembers() const { return this->m_members; } - void addMember(std::shared_ptr &&node) { this->m_members.push_back(std::move(node)); } - - [[nodiscard]] const std::vector> &getInheritance() const { return this->m_inheritance; } - void addInheritance(std::shared_ptr &&node) { this->m_inheritance.push_back(std::move(node)); } - - private: - std::vector> m_members; - std::vector> m_inheritance; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_ternary_expression.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_ternary_expression.hpp deleted file mode 100644 index 46ec4dde6..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_ternary_expression.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeTernaryExpression : public ASTNode { - public: - ASTNodeTernaryExpression(std::unique_ptr &&first, std::unique_ptr &&second, std::unique_ptr &&third, Token::Operator op) - : ASTNode(), m_first(std::move(first)), m_second(std::move(second)), m_third(std::move(third)), m_operator(op) { } - - ASTNodeTernaryExpression(const ASTNodeTernaryExpression &other) : ASTNode(other) { - this->m_operator = other.m_operator; - this->m_first = other.m_first->clone(); - this->m_second = other.m_second->clone(); - this->m_third = other.m_third->clone(); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeTernaryExpression(*this)); - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - if (this->getFirstOperand() == nullptr || this->getSecondOperand() == nullptr || this->getThirdOperand() == nullptr) - LogConsole::abortEvaluation("attempted to use void expression in mathematical expression", this); - - auto firstNode = this->getFirstOperand()->evaluate(evaluator); - auto secondNode = this->getSecondOperand()->evaluate(evaluator); - auto thirdNode = this->getThirdOperand()->evaluate(evaluator); - - auto *first = dynamic_cast(firstNode.get()); - auto *second = dynamic_cast(secondNode.get()); - auto *third = dynamic_cast(thirdNode.get()); - - auto condition = std::visit(overloaded { - [](const std::string &value) -> bool { return !value.empty(); }, - [this](const std::shared_ptr &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); }, - [](auto &&value) -> bool { return bool(value); } }, - first->getValue()); - - return std::visit(overloaded { - [condition](const T &second, const T &third) -> std::unique_ptr { return std::unique_ptr(new ASTNodeLiteral(condition ? second : third)); }, - [this](auto &&, auto &&) -> std::unique_ptr { LogConsole::abortEvaluation("operands to ternary expression have different types", this); } }, - second->getValue(), - third->getValue()); - } - - [[nodiscard]] const std::unique_ptr &getFirstOperand() const { return this->m_first; } - [[nodiscard]] const std::unique_ptr &getSecondOperand() const { return this->m_second; } - [[nodiscard]] const std::unique_ptr &getThirdOperand() const { return this->m_third; } - [[nodiscard]] Token::Operator getOperator() const { return this->m_operator; } - - private: - std::unique_ptr m_first, m_second, m_third; - Token::Operator m_operator; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_type_decl.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_type_decl.hpp deleted file mode 100644 index 984d3478e..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_type_decl.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include -#include - -namespace hex::pl { - - class ASTNodeTypeDecl : public ASTNode, - public Attributable { - public: - explicit ASTNodeTypeDecl(std::string name) : m_forwardDeclared(true), m_name(std::move(name)) { } - - ASTNodeTypeDecl(std::string name, std::shared_ptr type, std::optional endian = std::nullopt) - : ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_endian(endian) { } - - ASTNodeTypeDecl(const ASTNodeTypeDecl &other) : ASTNode(other), Attributable(other) { - this->m_name = other.m_name; - this->m_type = other.m_type; - this->m_endian = other.m_endian; - this->m_forwardDeclared = other.m_forwardDeclared; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeTypeDecl(*this)); - } - - void setName(const std::string &name) { this->m_name = name; } - [[nodiscard]] const std::string &getName() const { return this->m_name; } - [[nodiscard]] const std::shared_ptr &getType() const { - if (this->isForwardDeclared()) - LogConsole::abortEvaluation(hex::format("cannot use incomplete type '{}'", this->m_name), this); - - return this->m_type; - } - [[nodiscard]] std::optional getEndian() const { return this->m_endian; } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - auto type = this->getType()->evaluate(evaluator); - - if (auto attributable = dynamic_cast(type.get())) { - for (auto &attribute : this->getAttributes()) { - auto copy = attribute->clone(); - if (auto node = dynamic_cast(copy.get())) { - attributable->addAttribute(std::unique_ptr(node)); - (void)copy.release(); - } - } - } - - return type; - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto patterns = this->getType()->createPatterns(evaluator); - - for (auto &pattern : patterns) { - if (pattern == nullptr) - continue; - - if (!this->m_name.empty()) - pattern->setTypeName(this->m_name); - - if (this->m_endian.has_value()) - pattern->setEndian(this->m_endian.value()); - - applyTypeAttributes(evaluator, this, pattern.get()); - } - - return patterns; - } - - void addAttribute(std::unique_ptr &&attribute) override { - if (auto attributable = dynamic_cast(this->getType().get()); attributable != nullptr) { - attributable->addAttribute(std::unique_ptr(static_cast(attribute->clone().release()))); - } - - Attributable::addAttribute(std::move(attribute)); - } - - [[nodiscard]] - bool isForwardDeclared() const { - return this->m_forwardDeclared; - } - - void setType(std::shared_ptr type) { - this->m_forwardDeclared = false; - this->m_type = type; - } - - private: - bool m_forwardDeclared = false; - std::string m_name; - std::shared_ptr m_type; - std::optional m_endian; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_type_operator.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_type_operator.hpp deleted file mode 100644 index febe5eb15..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_type_operator.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeTypeOperator : public ASTNode { - public: - ASTNodeTypeOperator(Token::Operator op, std::unique_ptr &&expression) : m_op(op), m_expression(std::move(expression)) { - } - - ASTNodeTypeOperator(const ASTNodeTypeOperator &other) : ASTNode(other) { - this->m_op = other.m_op; - this->m_expression = other.m_expression->clone(); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeTypeOperator(*this)); - } - - [[nodiscard]] Token::Operator getOperator() const { - return this->m_op; - } - - [[nodiscard]] const std::unique_ptr &getExpression() const { - return this->m_expression; - } - - [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { - auto patterns = this->m_expression->createPatterns(evaluator); - auto &pattern = patterns.front(); - - switch (this->getOperator()) { - case Token::Operator::AddressOf: - return std::unique_ptr(new ASTNodeLiteral(u128(pattern->getOffset()))); - case Token::Operator::SizeOf: - return std::unique_ptr(new ASTNodeLiteral(u128(pattern->getSize()))); - default: - LogConsole::abortEvaluation("invalid type operator", this); - } - } - - - private: - Token::Operator m_op; - std::unique_ptr m_expression; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_union.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_union.hpp deleted file mode 100644 index 4d5cd3e7c..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_union.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace hex::pl { - - class ASTNodeUnion : public ASTNode, - public Attributable { - public: - ASTNodeUnion() : ASTNode() { } - - ASTNodeUnion(const ASTNodeUnion &other) : ASTNode(other), Attributable(other) { - for (const auto &otherMember : other.getMembers()) - this->m_members.push_back(otherMember->clone()); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeUnion(*this)); - } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - auto pattern = std::make_unique(evaluator, evaluator->dataOffset(), 0); - - size_t size = 0; - std::vector> memberPatterns; - u64 startOffset = evaluator->dataOffset(); - - evaluator->pushScope(pattern.get(), memberPatterns); - ON_SCOPE_EXIT { - evaluator->popScope(); - }; - - for (auto &member : this->m_members) { - for (auto &memberPattern : member->createPatterns(evaluator)) { - memberPattern->setOffset(startOffset); - size = std::max(memberPattern->getSize(), size); - - memberPatterns.push_back(std::move(memberPattern)); - } - } - - evaluator->dataOffset() = startOffset + size; - pattern->setMembers(std::move(memberPatterns)); - pattern->setSize(size); - - applyTypeAttributes(evaluator, this, pattern.get()); - - return hex::moveToVector>(std::move(pattern)); - } - - [[nodiscard]] const std::vector> &getMembers() const { return this->m_members; } - - private: - std::vector> m_members; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_variable_decl.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_variable_decl.hpp deleted file mode 100644 index a1f9a2325..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_variable_decl.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace hex::pl { - - class ASTNodeVariableDecl : public ASTNode, - public Attributable { - public: - ASTNodeVariableDecl(std::string name, std::shared_ptr type, std::unique_ptr &&placementOffset = nullptr, bool inVariable = false, bool outVariable = false) - : ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_placementOffset(std::move(placementOffset)), m_inVariable(inVariable), m_outVariable(outVariable) { } - - ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other), Attributable(other) { - this->m_name = other.m_name; - this->m_type = other.m_type; - - if (other.m_placementOffset != nullptr) - this->m_placementOffset = other.m_placementOffset->clone(); - else - this->m_placementOffset = nullptr; - - this->m_inVariable = other.m_inVariable; - this->m_outVariable = other.m_outVariable; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeVariableDecl(*this)); - } - - [[nodiscard]] const std::string &getName() const { return this->m_name; } - [[nodiscard]] constexpr const std::shared_ptr &getType() const { return this->m_type; } - [[nodiscard]] constexpr const std::unique_ptr &getPlacementOffset() const { return this->m_placementOffset; } - - [[nodiscard]] constexpr bool isInVariable() const { return this->m_inVariable; } - [[nodiscard]] constexpr bool isOutVariable() const { return this->m_outVariable; } - - [[nodiscard]] std::vector> createPatterns(Evaluator *evaluator) const override { - u64 startOffset = evaluator->dataOffset(); - - if (this->m_placementOffset != nullptr) { - const auto node = this->m_placementOffset->evaluate(evaluator); - const auto offset = dynamic_cast(node.get()); - - evaluator->dataOffset() = std::visit(overloaded { - [this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); }, - [this](Pattern *) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); }, - [](auto &&offset) -> u64 { return offset; } }, - offset->getValue()); - } - - auto patterns = this->m_type->createPatterns(evaluator); - auto &pattern = patterns.front(); - pattern->setVariableName(this->m_name); - - applyVariableAttributes(evaluator, this, pattern.get()); - - if (this->m_placementOffset != nullptr && !evaluator->isGlobalScope()) { - evaluator->dataOffset() = startOffset; - } - - return hex::moveToVector>(std::move(pattern)); - } - - FunctionResult execute(Evaluator *evaluator) const override { - evaluator->createVariable(this->getName(), this->getType().get()); - - return std::nullopt; - } - - private: - std::string m_name; - std::shared_ptr m_type; - std::unique_ptr m_placementOffset; - - bool m_inVariable = false, m_outVariable = false; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/ast/ast_node_while_statement.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_while_statement.hpp deleted file mode 100644 index 827a52645..000000000 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_while_statement.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class ASTNodeWhileStatement : public ASTNode { - public: - explicit ASTNodeWhileStatement(std::unique_ptr &&condition, std::vector> &&body, std::unique_ptr &&postExpression = nullptr) - : ASTNode(), m_condition(std::move(condition)), m_body(std::move(body)), m_postExpression(std::move(postExpression)) { } - - ASTNodeWhileStatement(const ASTNodeWhileStatement &other) : ASTNode(other) { - this->m_condition = other.m_condition->clone(); - - for (auto &statement : other.m_body) - this->m_body.push_back(statement->clone()); - - if (other.m_postExpression != nullptr) - this->m_postExpression = other.m_postExpression->clone(); - else - this->m_postExpression = nullptr; - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new ASTNodeWhileStatement(*this)); - } - - [[nodiscard]] const std::unique_ptr &getCondition() { - return this->m_condition; - } - - [[nodiscard]] const std::vector> &getBody() { - return this->m_body; - } - - FunctionResult execute(Evaluator *evaluator) const override { - - u64 loopIterations = 0; - while (evaluateCondition(evaluator)) { - evaluator->handleAbort(); - - auto variables = *evaluator->getScope(0).scope; - auto parameterPack = evaluator->getScope(0).parameterPack; - u32 startVariableCount = variables.size(); - ON_SCOPE_EXIT { - ssize_t stackSize = evaluator->getStack().size(); - for (u32 i = startVariableCount; i < variables.size(); i++) { - stackSize--; - } - if (stackSize < 0) LogConsole::abortEvaluation("stack pointer underflow!", this); - evaluator->getStack().resize(stackSize); - }; - - evaluator->pushScope(nullptr, variables); - evaluator->getScope(0).parameterPack = parameterPack; - ON_SCOPE_EXIT { - evaluator->popScope(); - }; - - auto ctrlFlow = ControlFlowStatement::None; - for (auto &statement : this->m_body) { - auto result = statement->execute(evaluator); - - ctrlFlow = evaluator->getCurrentControlFlowStatement(); - evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None); - if (ctrlFlow == ControlFlowStatement::Return) - return result; - else if (ctrlFlow != ControlFlowStatement::None) - break; - } - - if (this->m_postExpression != nullptr) - this->m_postExpression->execute(evaluator); - - loopIterations++; - if (loopIterations >= evaluator->getLoopLimit()) - LogConsole::abortEvaluation(hex::format("loop iterations exceeded limit of {}", evaluator->getLoopLimit()), this); - - evaluator->handleAbort(); - - if (ctrlFlow == ControlFlowStatement::Break) - break; - else if (ctrlFlow == ControlFlowStatement::Continue) - continue; - } - - return std::nullopt; - } - - [[nodiscard]] bool evaluateCondition(Evaluator *evaluator) const { - const auto node = this->m_condition->evaluate(evaluator); - const auto literal = dynamic_cast(node.get()); - - return std::visit(overloaded { - [](const std::string &value) -> bool { return !value.empty(); }, - [this](Pattern *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); }, - [](auto &&value) -> bool { return value != 0; } }, - literal->getValue()); - } - - private: - std::unique_ptr m_condition; - std::vector> m_body; - std::unique_ptr m_postExpression; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/error.hpp b/lib/libimhex/include/hex/pattern_language/error.hpp deleted file mode 100644 index 624fd8f22..000000000 --- a/lib/libimhex/include/hex/pattern_language/error.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -#include -#include - -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; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/evaluator.hpp b/lib/libimhex/include/hex/pattern_language/evaluator.hpp deleted file mode 100644 index 978a2facd..000000000 --- a/lib/libimhex/include/hex/pattern_language/evaluator.hpp +++ /dev/null @@ -1,293 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -namespace hex::prv { - class Provider; -} - -namespace hex::pl { - - enum class DangerousFunctionPermission - { - Ask, - Deny, - Allow - }; - - enum class ControlFlowStatement - { - None, - Continue, - Break, - Return - }; - - enum class BitfieldOrder - { - RightToLeft, - LeftToRight - }; - - class Pattern; - class PatternCreationLimiter; - class ASTNode; - - class Evaluator { - public: - Evaluator() = default; - - std::optional>> evaluate(const std::vector> &ast); - - [[nodiscard]] LogConsole &getConsole() { - return this->m_console; - } - - struct ParameterPack { - std::string name; - std::vector values; - }; - - struct Scope { - Pattern *parent; - std::vector> *scope; - std::optional parameterPack; - }; - - void pushScope(Pattern *parent, std::vector> &scope) { - if (this->m_scopes.size() > this->getEvaluationDepth()) - LogConsole::abortEvaluation(hex::format("evaluation depth exceeded set limit of {}", this->getEvaluationDepth())); - - this->handleAbort(); - - this->m_scopes.push_back({ parent, &scope, { } }); - } - - void popScope() { - this->m_scopes.pop_back(); - } - - [[nodiscard]] Scope &getScope(i32 index) { - return this->m_scopes[this->m_scopes.size() - 1 + index]; - } - - [[nodiscard]] const Scope &getScope(i32 index) const { - return this->m_scopes[this->m_scopes.size() - 1 + index]; - } - - [[nodiscard]] Scope &getGlobalScope() { - return this->m_scopes.front(); - } - - [[nodiscard]] const Scope &getGlobalScope() const { - return this->m_scopes.front(); - } - - [[nodiscard]] size_t getScopeCount() { - return this->m_scopes.size(); - } - - [[nodiscard]] bool isGlobalScope() { - return this->m_scopes.size() == 1; - } - - void setProvider(prv::Provider *provider) { - this->m_provider = provider; - } - - void setInVariables(const std::map &inVariables) { - this->m_inVariables = inVariables; - } - - [[nodiscard]] std::map getOutVariables() const { - std::map result; - - for (const auto &[name, offset] : this->m_outVariables) { - result.insert({ name, this->getStack()[offset] }); - } - - return result; - } - - [[nodiscard]] prv::Provider *getProvider() const { - return this->m_provider; - } - - void setDefaultEndian(std::endian endian) { - this->m_defaultEndian = endian; - } - - [[nodiscard]] std::endian getDefaultEndian() const { - return this->m_defaultEndian; - } - - void setEvaluationDepth(u64 evalDepth) { - this->m_evalDepth = evalDepth; - } - - [[nodiscard]] u64 getEvaluationDepth() const { - return this->m_evalDepth; - } - - void setArrayLimit(u64 arrayLimit) { - this->m_arrayLimit = arrayLimit; - } - - [[nodiscard]] u64 getArrayLimit() const { - return this->m_arrayLimit; - } - - void setPatternLimit(u64 limit) { - this->m_patternLimit = limit; - } - - [[nodiscard]] u64 getPatternLimit() const { - return this->m_patternLimit; - } - - [[nodiscard]] u64 getPatternCount() const { - return this->m_currPatternCount; - } - - void setLoopLimit(u64 limit) { - this->m_loopLimit = limit; - } - - [[nodiscard]] u64 getLoopLimit() const { - return this->m_loopLimit; - } - - void setBitfieldOrder(BitfieldOrder order) { - this->m_bitfieldOrder = order; - } - - [[nodiscard]] BitfieldOrder getBitfieldOrder() { - return this->m_bitfieldOrder; - } - - u64 &dataOffset() { return this->m_currOffset; } - - bool addCustomFunction(const std::string &name, ContentRegistry::PatternLanguage::ParameterCount numParams, std::vector defaultParameters, const ContentRegistry::PatternLanguage::Callback &function) { - const auto [iter, inserted] = this->m_customFunctions.insert({ - name, {numParams, std::move(defaultParameters), function, false} - }); - - return inserted; - } - - [[nodiscard]] const std::map &getCustomFunctions() const { - return this->m_customFunctions; - } - - [[nodiscard]] std::vector &getStack() { - return this->m_stack; - } - - [[nodiscard]] const std::vector &getStack() const { - return this->m_stack; - } - - void createParameterPack(const std::string &name, const std::vector &values); - void createVariable(const std::string &name, ASTNode *type, const std::optional &value = std::nullopt, bool outVariable = false); - void setVariable(const std::string &name, const Token::Literal &value); - - void abort() { - this->m_aborted = true; - } - - void handleAbort() { - if (this->m_aborted) - LogConsole::abortEvaluation("evaluation aborted by user"); - } - - [[nodiscard]] std::optional getEnvVariable(const std::string &name) const { - if (this->m_envVariables.contains(name)) { - auto value = this->m_envVariables.at(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; - } - - [[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; - } - - void setCurrentControlFlowStatement(ControlFlowStatement statement) { - this->m_currControlFlowStatement = statement; - } - - [[nodiscard]] ControlFlowStatement getCurrentControlFlowStatement() const { - return this->m_currControlFlowStatement; - } - - [[nodiscard]] const std::optional &getMainResult() { - return this->m_mainResult; - } - - private: - void patternCreated(); - void patternDestroyed(); - - private: - u64 m_currOffset; - prv::Provider *m_provider = nullptr; - LogConsole m_console; - - std::endian m_defaultEndian = std::endian::native; - u64 m_evalDepth; - u64 m_arrayLimit; - u64 m_patternLimit; - u64 m_loopLimit; - - u64 m_currPatternCount; - - std::atomic m_aborted; - - std::vector m_scopes; - std::map m_customFunctions; - std::vector> m_customFunctionDefinitions; - std::vector m_stack; - - std::optional m_mainResult; - - std::map m_envVariables; - std::map m_inVariables; - std::map m_outVariables; - - std::atomic m_dangerousFunctionCalled = false; - std::atomic m_allowDangerousFunctions = DangerousFunctionPermission::Ask; - ControlFlowStatement m_currControlFlowStatement; - BitfieldOrder m_bitfieldOrder = BitfieldOrder::RightToLeft; - - friend class PatternCreationLimiter; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/lexer.hpp b/lib/libimhex/include/hex/pattern_language/lexer.hpp deleted file mode 100644 index 9a86c7ad9..000000000 --- a/lib/libimhex/include/hex/pattern_language/lexer.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include -#include - -namespace hex::pl { - - class Lexer { - public: - Lexer() = default; - - std::optional> lex(const std::string &code); - const std::optional &getError() { return this->m_error; } - - private: - std::optional m_error; - - [[noreturn]] static void throwLexerError(const std::string &error, u32 lineNumber) { - throw PatternLanguageError(lineNumber, "Lexer: " + error); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/log_console.hpp b/lib/libimhex/include/hex/pattern_language/log_console.hpp deleted file mode 100644 index fd824183f..000000000 --- a/lib/libimhex/include/hex/pattern_language/log_console.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -namespace hex::pl { - - class ASTNode; - - class LogConsole { - public: - enum Level - { - Debug, - Info, - Warning, - Error - }; - - [[nodiscard]] const auto &getLog() const { return this->m_consoleLog; } - - void log(Level level, const std::string &message) { - this->m_consoleLog.emplace_back(level, message); - } - - [[noreturn]] static void abortEvaluation(const std::string &message) { - abortEvaluation(message, nullptr); - } - - template - [[noreturn]] static void abortEvaluation(const std::string &message, const std::unique_ptr &node) { - abortEvaluation(message, node.get()); - } - - [[noreturn]] static void abortEvaluation(const std::string &message, const ASTNode *node); - - void clear() { - this->m_consoleLog.clear(); - this->m_lastHardError.reset(); - } - - void setHardError(const PatternLanguageError &error) { this->m_lastHardError = error; } - - [[nodiscard]] const std::optional &getLastHardError() { return this->m_lastHardError; }; - - private: - std::vector> m_consoleLog; - std::optional m_lastHardError; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/parser.hpp b/lib/libimhex/include/hex/pattern_language/parser.hpp deleted file mode 100644 index e4366cec2..000000000 --- a/lib/libimhex/include/hex/pattern_language/parser.hpp +++ /dev/null @@ -1,293 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace hex::pl { - - class Parser { - public: - using TokenIter = std::vector::const_iterator; - - Parser() = default; - ~Parser() = default; - - std::optional>> parse(const std::vector &tokens); - const std::optional &getError() { return this->m_error; } - - private: - std::optional m_error; - TokenIter m_curr; - TokenIter m_originalPosition, m_partOriginalPosition; - - std::unordered_map> m_types; - std::vector m_matchedOptionals; - std::vector> m_currNamespace; - - u32 getLineNumber(i32 index) const { - return this->m_curr[index].lineNumber; - } - - template - std::unique_ptr create(T *node) { - node->setLineNumber(this->getLineNumber(-1)); - return std::unique_ptr(node); - } - - template - const T &getValue(i32 index) const { - auto value = std::get_if(&this->m_curr[index].value); - - if (value == nullptr) - throwParserError("failed to decode token. Invalid type.", getLineNumber(index)); - - return *value; - } - - Token::Type getType(i32 index) const { - return this->m_curr[index].type; - } - - std::string getNamespacePrefixedName(const std::string &name) { - std::string result; - for (const auto &part : this->m_currNamespace.back()) { - result += part + "::"; - } - - result += name; - - return result; - } - - std::unique_ptr parseFunctionCall(); - std::unique_ptr parseStringLiteral(); - std::string parseNamespaceResolution(); - std::unique_ptr parseScopeResolution(); - std::unique_ptr parseRValue(); - std::unique_ptr parseRValue(ASTNodeRValue::Path &path); - std::unique_ptr parseFactor(); - std::unique_ptr parseCastExpression(); - std::unique_ptr parseUnaryExpression(); - std::unique_ptr parseMultiplicativeExpression(); - std::unique_ptr parseAdditiveExpression(); - std::unique_ptr parseShiftExpression(); - std::unique_ptr parseBinaryAndExpression(); - std::unique_ptr parseBinaryXorExpression(); - std::unique_ptr parseBinaryOrExpression(); - std::unique_ptr parseBooleanAnd(); - std::unique_ptr parseBooleanXor(); - std::unique_ptr parseBooleanOr(); - std::unique_ptr parseRelationExpression(); - std::unique_ptr parseEqualityExpression(); - std::unique_ptr parseTernaryConditional(); - std::unique_ptr parseMathematicalExpression(); - - std::unique_ptr parseFunctionDefinition(); - std::unique_ptr parseFunctionVariableDecl(); - std::unique_ptr parseFunctionStatement(); - std::unique_ptr parseFunctionVariableAssignment(const std::string &lvalue); - std::unique_ptr parseFunctionVariableCompoundAssignment(const std::string &lvalue); - std::unique_ptr parseFunctionControlFlowStatement(); - std::vector> parseStatementBody(); - std::unique_ptr parseFunctionConditional(); - std::unique_ptr parseFunctionWhileLoop(); - std::unique_ptr parseFunctionForLoop(); - - void parseAttribute(Attributable *currNode); - std::unique_ptr parseConditional(); - std::unique_ptr parseWhileStatement(); - std::unique_ptr parseType(bool allowFunctionTypes = false); - std::shared_ptr parseUsingDeclaration(); - std::unique_ptr parsePadding(); - std::unique_ptr parseMemberVariable(const std::shared_ptr &type); - std::unique_ptr parseMemberArrayVariable(const std::shared_ptr &type); - std::unique_ptr parseMemberPointerVariable(const std::shared_ptr &type); - std::unique_ptr parseMember(); - std::shared_ptr parseStruct(); - std::shared_ptr parseUnion(); - std::shared_ptr parseEnum(); - std::shared_ptr parseBitfield(); - void parseForwardDeclaration(); - std::unique_ptr parseVariablePlacement(const std::shared_ptr &type); - std::unique_ptr parseArrayVariablePlacement(const std::shared_ptr &type); - std::unique_ptr parsePointerVariablePlacement(const std::shared_ptr &type); - std::unique_ptr parsePlacement(); - std::vector> parseNamespace(); - std::vector> parseStatements(); - - std::shared_ptr addType(const std::string &name, std::unique_ptr &&node, std::optional endian = std::nullopt); - - std::vector> parseTillToken(Token::Type endTokenType, const auto value) { - std::vector> program; - - while (this->m_curr->type != endTokenType || (*this->m_curr) != value) { - for (auto &statement : parseStatements()) - program.push_back(std::move(statement)); - } - - this->m_curr++; - - return program; - } - - [[noreturn]] void throwParserError(const std::string &error, i32 token = -1) const { - throw PatternLanguageError(this->m_curr[token].lineNumber, "Parser: " + error); - } - - /* Token consuming */ - - enum class Setting - { - }; - constexpr static auto Normal = static_cast(0); - constexpr static auto Not = static_cast(1); - - bool begin() { - this->m_originalPosition = this->m_curr; - this->m_matchedOptionals.clear(); - - return true; - } - - bool partBegin() { - this->m_partOriginalPosition = this->m_curr; - this->m_matchedOptionals.clear(); - - return true; - } - - void reset() { - this->m_curr = this->m_originalPosition; - } - - void partReset() { - this->m_curr = this->m_partOriginalPosition; - } - - bool resetIfFailed(bool value) { - if (!value) reset(); - - return value; - } - - template - bool sequenceImpl() { - if constexpr (S == Normal) - return true; - else if constexpr (S == Not) - return false; - else - hex::unreachable(); - } - - template - bool sequenceImpl(Token::Type type, auto value, auto... args) { - if constexpr (S == Normal) { - if (!peek(type, value)) { - partReset(); - return false; - } - - this->m_curr++; - - if (!sequenceImpl(args...)) { - partReset(); - return false; - } - - return true; - } else if constexpr (S == Not) { - if (!peek(type, value)) - return true; - - this->m_curr++; - - if (!sequenceImpl(args...)) - return true; - - partReset(); - return false; - } else - hex::unreachable(); - } - - template - bool sequence(Token::Type type, auto value, auto... args) { - return partBegin() && sequenceImpl(type, value, args...); - } - - template - bool oneOfImpl() { - if constexpr (S == Normal) - return false; - else if constexpr (S == Not) - return true; - else - hex::unreachable(); - } - - template - bool oneOfImpl(Token::Type type, auto value, auto... args) { - if constexpr (S == Normal) - return sequenceImpl(type, value) || oneOfImpl(args...); - else if constexpr (S == Not) - return sequenceImpl(type, value) && oneOfImpl(args...); - else - hex::unreachable(); - } - - template - bool oneOf(Token::Type type, auto value, auto... args) { - return partBegin() && oneOfImpl(type, value, args...); - } - - bool variantImpl(Token::Type type1, auto value1, Token::Type type2, auto value2) { - if (!peek(type1, value1)) { - if (!peek(type2, value2)) { - partReset(); - return false; - } - } - - this->m_curr++; - - return true; - } - - bool variant(Token::Type type1, auto value1, Token::Type type2, auto value2) { - return partBegin() && variantImpl(type1, value1, type2, value2); - } - - bool optionalImpl(Token::Type type, auto value) { - if (peek(type, value)) { - this->m_matchedOptionals.push_back(this->m_curr); - this->m_curr++; - } - - return true; - } - - bool optional(Token::Type type, auto value) { - return partBegin() && optionalImpl(type, value); - } - - bool peek(Token::Type type, auto value, i32 index = 0) { - return this->m_curr[index].type == type && this->m_curr[index] == value; - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/pattern_language.hpp b/lib/libimhex/include/hex/pattern_language/pattern_language.hpp deleted file mode 100644 index 393d9c925..000000000 --- a/lib/libimhex/include/hex/pattern_language/pattern_language.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace hex::prv { - class Provider; -} - -namespace hex::pl { - - class Preprocessor; - class Lexer; - class Parser; - class Validator; - class Evaluator; - class Pattern; - - class ASTNode; - - class PatternLanguage { - public: - PatternLanguage(); - ~PatternLanguage(); - - [[nodiscard]] std::optional>> parseString(const std::string &code); - [[nodiscard]] bool executeString(prv::Provider *provider, const std::string &string, const std::map &envVars = {}, const std::map &inVariables = {}, bool checkResult = true); - [[nodiscard]] bool executeFile(prv::Provider *provider, const std::fs::path &path, const std::map &envVars = {}, const std::map &inVariables = {}); - [[nodiscard]] std::pair> executeFunction(prv::Provider *provider, const std::string &code); - [[nodiscard]] const std::vector> &getCurrentAST() const; - - void abort(); - - [[nodiscard]] const std::vector> &getConsoleLog(); - [[nodiscard]] const std::optional &getError(); - [[nodiscard]] std::map getOutVariables() const; - - [[nodiscard]] u32 getCreatedPatternCount(); - [[nodiscard]] u32 getMaximumPatternCount(); - - [[nodiscard]] bool hasDangerousFunctionBeenCalled() const; - void allowDangerousFunctions(bool allow); - - [[nodiscard]] const std::vector> &getPatterns() { - const static std::vector> empty; - - if (isRunning()) return empty; - else return this->m_patterns; - } - - void reset(); - [[nodiscard]] bool isRunning() const { return this->m_running; } - - private: - Preprocessor *m_preprocessor; - Lexer *m_lexer; - Parser *m_parser; - Validator *m_validator; - Evaluator *m_evaluator; - - std::vector> m_currAST; - - std::optional m_currError; - - std::vector> m_patterns; - - bool m_running = false; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/pattern_visitor.hpp b/lib/libimhex/include/hex/pattern_language/pattern_visitor.hpp deleted file mode 100644 index 602ef19d6..000000000 --- a/lib/libimhex/include/hex/pattern_language/pattern_visitor.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -namespace hex::pl { - - class PatternArrayDynamic; - class PatternArrayStatic; - class PatternBitfield; - class PatternBitfieldField; - class PatternBoolean; - class PatternCharacter; - class PatternEnum; - class PatternFloat; - class PatternPadding; - class PatternPointer; - class PatternSigned; - class PatternString; - class PatternStruct; - class PatternUnion; - class PatternUnsigned; - class PatternWideCharacter; - class PatternWideString; - - class PatternVisitor - { - public: - virtual void visit(PatternArrayDynamic& pattern) = 0; - virtual void visit(PatternArrayStatic& pattern) = 0; - virtual void visit(PatternBitfield& pattern) = 0; - virtual void visit(PatternBitfieldField& pattern) = 0; - virtual void visit(PatternBoolean& pattern) = 0; - virtual void visit(PatternCharacter& pattern) = 0; - virtual void visit(PatternEnum& pattern) = 0; - virtual void visit(PatternFloat& pattern) = 0; - virtual void visit(PatternPadding& pattern) = 0; - virtual void visit(PatternPointer& pattern) = 0; - virtual void visit(PatternSigned& pattern) = 0; - virtual void visit(PatternString& pattern) = 0; - virtual void visit(PatternStruct& pattern) = 0; - virtual void visit(PatternUnion& pattern) = 0; - virtual void visit(PatternUnsigned& pattern) = 0; - virtual void visit(PatternWideCharacter& pattern) = 0; - virtual void visit(PatternWideString& pattern) = 0; - }; -}; \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern.hpp deleted file mode 100644 index 8f1986af7..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern.hpp +++ /dev/null @@ -1,275 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include -#include -#include - -#include - -namespace hex::pl { - - using namespace ::std::literals::string_literals; - - class Inlinable { - public: - [[nodiscard]] bool isInlined() const { return this->m_inlined; } - void setInlined(bool inlined) { this->m_inlined = inlined; } - - private: - bool m_inlined = false; - }; - - class PatternCreationLimiter { - public: - explicit PatternCreationLimiter(Evaluator *evaluator) : m_evaluator(evaluator) { - if (getEvaluator() == nullptr) return; - - getEvaluator()->patternCreated(); - } - - PatternCreationLimiter(const PatternCreationLimiter &other) : PatternCreationLimiter(other.m_evaluator) { } - - virtual ~PatternCreationLimiter() { - if (getEvaluator() == nullptr) return; - - getEvaluator()->patternDestroyed(); - } - - [[nodiscard]] Evaluator *getEvaluator() const { - return this->m_evaluator; - } - - private: - Evaluator *m_evaluator = nullptr; - }; - - class Pattern : public PatternCreationLimiter, - public Cloneable { - public: - Pattern(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : PatternCreationLimiter(evaluator), m_offset(offset), m_size(size), m_color(color) { - - if (color != 0) - return; - - this->m_color = ContentRegistry::PatternLanguage::getNextColor(); - this->m_manualColor = false; - } - - Pattern(const Pattern &other) = default; - - ~Pattern() override = default; - - [[nodiscard]] u64 getOffset() const { return this->m_offset; } - virtual void setOffset(u64 offset) { this->m_offset = offset; } - - [[nodiscard]] size_t getSize() const { return this->m_size; } - void setSize(size_t size) { this->m_size = size; } - - [[nodiscard]] const std::string &getVariableName() const { return this->m_variableName; } - void setVariableName(std::string name) { this->m_variableName = std::move(name); } - - [[nodiscard]] const std::optional &getComment() const { return this->m_comment; } - void setComment(std::string comment) { this->m_comment = std::move(comment); } - - [[nodiscard]] virtual std::string getTypeName() const { return this->m_typeName; } - void setTypeName(std::string name) { this->m_typeName = std::move(name); } - - [[nodiscard]] u32 getColor() const { return this->m_color; } - virtual void setColor(u32 color) { - this->m_color = color; - this->m_manualColor = true; - } - void setBaseColor(u32 color) { - if (this->hasOverriddenColor()) - this->setColor(color); - else - this->m_color = color; - } - [[nodiscard]] bool hasOverriddenColor() const { return this->m_manualColor; } - - [[nodiscard]] std::endian getEndian() const { - if (this->getEvaluator() == nullptr) return std::endian::native; - else return this->m_endian.value_or(this->getEvaluator()->getDefaultEndian()); - } - virtual void setEndian(std::endian endian) { this->m_endian = endian; } - [[nodiscard]] bool hasOverriddenEndian() const { return this->m_endian.has_value(); } - - [[nodiscard]] std::string getDisplayName() const { return this->m_displayName.value_or(this->m_variableName); } - void setDisplayName(const std::string &name) { this->m_displayName = name; } - - [[nodiscard]] const auto &getTransformFunction() const { return this->m_transformFunction; } - void setTransformFunction(const ContentRegistry::PatternLanguage::Function &function) { this->m_transformFunction = function; } - [[nodiscard]] const auto &getFormatterFunction() const { return this->m_formatterFunction; } - void setFormatterFunction(const ContentRegistry::PatternLanguage::Function &function) { this->m_formatterFunction = function; } - - [[nodiscard]] virtual std::string getFormattedName() const = 0; - - [[nodiscard]] virtual const Pattern *getPattern(u64 offset) const { - if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()) && !this->isHidden()) - return this; - else - return nullptr; - } - - virtual void getHighlightedAddresses(std::map &highlight) const { - if (this->isHidden()) return; - - for (u64 i = 0; i < this->getSize(); i++) - highlight.insert({ this->getOffset() + i, this->getColor() }); - - this->getEvaluator()->handleAbort(); - } - - virtual void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) { - hex::unused(sortSpecs, provider); - } - - [[nodiscard]] virtual std::string toString(prv::Provider *provider) const { - hex::unused(provider); - - return hex::format("{} {} @ 0x{:X}", this->getTypeName(), this->getVariableName(), this->getOffset()); - } - - static bool sortPatternTable(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider, pl::Pattern *left, pl::Pattern *right) { - if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getDisplayName() > right->getDisplayName(); - else - return left->getDisplayName() < right->getDisplayName(); - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getOffset() > right->getOffset(); - else - return left->getOffset() < right->getOffset(); - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getSize() > right->getSize(); - else - return left->getSize() < right->getSize(); - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) { - size_t biggerSize = std::max(left->getSize(), right->getSize()); - std::vector leftBuffer(biggerSize, 0x00), rightBuffer(biggerSize, 0x00); - - provider->read(left->getOffset(), leftBuffer.data(), left->getSize()); - provider->read(right->getOffset(), rightBuffer.data(), right->getSize()); - - if (left->m_endian != std::endian::native) - std::reverse(leftBuffer.begin(), leftBuffer.end()); - if (right->m_endian != std::endian::native) - std::reverse(rightBuffer.begin(), rightBuffer.end()); - - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return leftBuffer > rightBuffer; - else - return leftBuffer < rightBuffer; - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getTypeName() > right->getTypeName(); - else - return left->getTypeName() < right->getTypeName(); - } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) { - if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getColor() > right->getColor(); - else - return left->getColor() < right->getColor(); - } - - return false; - } - - void setHidden(bool hidden) { - this->m_hidden = hidden; - } - - [[nodiscard]] bool isHidden() const { - return this->m_hidden; - } - - void setLocal(bool local) { - this->m_local = local; - } - - [[nodiscard]] bool isLocal() const { - return this->m_local; - } - - [[nodiscard]] virtual bool operator!=(const Pattern &other) const final { return !operator==(other); } - [[nodiscard]] virtual bool operator==(const Pattern &other) const = 0; - - template - [[nodiscard]] bool areCommonPropertiesEqual(const Pattern &other) const { - return typeid(other) == typeid(std::remove_cvref_t) && - this->m_offset == other.m_offset && - this->m_size == other.m_size && - this->m_hidden == other.m_hidden && - (this->m_endian == other.m_endian || (!this->m_endian.has_value() && other.m_endian == std::endian::native) || (!other.m_endian.has_value() && this->m_endian == std::endian::native)) && - this->m_variableName == other.m_variableName && - this->m_typeName == other.m_typeName && - this->m_comment == other.m_comment && - this->m_local == other.m_local; - } - - [[nodiscard]] std::string calcDisplayValue(const std::string &value, const Token::Literal &literal) const { - if (!this->m_formatterFunction.has_value()) - return value; - else { - try { - auto result = this->m_formatterFunction->func(this->getEvaluator(), { literal }); - - if (result.has_value()) { - if (auto displayValue = std::get_if(&result.value()); displayValue != nullptr) - return *displayValue; - else - return "???"; - } else { - return "???"; - } - } catch (PatternLanguageError &error) { - return "Error: "s + error.what(); - } - } - } - - [[nodiscard]] std::string formatDisplayValue(const std::string &value, const Token::Literal &literal) const { - if (!this->m_cachedDisplayValue.has_value()) { - this->m_cachedDisplayValue = calcDisplayValue(value, literal); - } - - return this->m_cachedDisplayValue.value(); - } - - void clearFormatCache() { - this->m_cachedDisplayValue.reset(); - } - - virtual void accept(PatternVisitor &v) = 0; - - protected: - std::optional m_endian; - bool m_hidden = false; - - private: - u64 m_offset = 0x00; - size_t m_size = 0x00; - - u32 m_color = 0x00; - std::optional m_displayName; - mutable std::optional m_cachedDisplayValue; - std::string m_variableName; - std::optional m_comment; - std::string m_typeName; - - std::optional m_formatterFunction; - std::optional m_transformFunction; - - bool m_local = false; - bool m_manualColor = false; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_dynamic.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_dynamic.hpp deleted file mode 100644 index d634b87ac..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_dynamic.hpp +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternArrayDynamic : public Pattern, - public Inlinable { - public: - PatternArrayDynamic(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { - } - - PatternArrayDynamic(const PatternArrayDynamic &other) : Pattern(other) { - std::vector> entries; - for (const auto &entry : other.m_entries) - entries.push_back(entry->clone()); - - this->setEntries(std::move(entries)); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternArrayDynamic(*this)); - } - - void setColor(u32 color) override { - Pattern::setColor(color); - for (auto &entry : this->m_entries) - entry->setColor(color); - } - - void getHighlightedAddresses(std::map &highlight) const override { - for (auto &entry : this->m_entries) { - entry->getHighlightedAddresses(highlight); - } - } - - [[nodiscard]] std::string getFormattedName() const override { - return this->m_entries[0]->getTypeName() + "[" + std::to_string(this->m_entries.size()) + "]"; - } - - [[nodiscard]] std::string getTypeName() const override { - return this->m_entries[0]->getTypeName(); - } - - void setOffset(u64 offset) override { - for (auto &entry : this->m_entries) - entry->setOffset(entry->getOffset() - this->getOffset() + offset); - - Pattern::setOffset(offset); - } - - [[nodiscard]] size_t getEntryCount() const { - return this->m_entries.size(); - } - - [[nodiscard]] const auto &getEntries() { - return this->m_entries; - } - - void forEachArrayEntry(const std::function& fn) { - for (u64 i = 0; i < this->m_entries.size(); i++) - fn(i, *this->m_entries[i]); - } - - void setEntries(std::vector> &&entries) { - this->m_entries = std::move(entries); - - for (auto &entry : this->m_entries) { - entry->setBaseColor(this->getColor()); - } - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { - if (!areCommonPropertiesEqual(other)) - return false; - - auto &otherArray = *static_cast(&other); - if (this->m_entries.size() != otherArray.m_entries.size()) - return false; - - for (u64 i = 0; i < this->m_entries.size(); i++) { - if (*this->m_entries[i] != *otherArray.m_entries[i]) - return false; - } - - return true; - } - - [[nodiscard]] const Pattern *getPattern(u64 offset) const override { - if (this->isHidden()) return nullptr; - - for (auto &pattern : this->m_entries) { - auto result = pattern->getPattern(offset); - if (result != nullptr) - return result; - } - - return nullptr; - } - - void setEndian(std::endian endian) override { - for (auto &entry : this->m_entries) { - entry->setEndian(endian); - } - - Pattern::setEndian(endian); - } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - - private: - std::vector> m_entries; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_static.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_static.hpp deleted file mode 100644 index 1b7f84584..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_static.hpp +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternArrayStatic : public Pattern, - public Inlinable { - public: - PatternArrayStatic(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { - } - - PatternArrayStatic(const PatternArrayStatic &other) : Pattern(other) { - this->setEntries(other.getTemplate()->clone(), other.getEntryCount()); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternArrayStatic(*this)); - } - - void forEachArrayEntry(const std::function& fn) { - auto entry = std::shared_ptr(this->m_template->clone()); - for (u64 index = 0; index < this->m_entryCount; index++) { - entry->clearFormatCache(); - entry->setVariableName(hex::format("[{0}]", index)); - entry->setOffset(this->getOffset() + index * this->m_template->getSize()); - fn(index, *entry); - } - } - - void getHighlightedAddresses(std::map &highlight) const override { - auto entry = this->m_template->clone(); - - for (u64 address = this->getOffset(); address < this->getOffset() + this->getSize(); address += entry->getSize()) { - entry->setOffset(address); - entry->getHighlightedAddresses(highlight); - } - } - - void setOffset(u64 offset) override { - this->m_template->setOffset(this->m_template->getOffset() - this->getOffset() + offset); - - Pattern::setOffset(offset); - } - - void setColor(u32 color) override { - Pattern::setColor(color); - this->m_template->setColor(color); - } - - [[nodiscard]] std::string getFormattedName() const override { - return this->m_template->getTypeName() + "[" + std::to_string(this->m_entryCount) + "]"; - } - - [[nodiscard]] std::string getTypeName() const override { - return this->m_template->getTypeName(); - } - - [[nodiscard]] const std::shared_ptr &getTemplate() const { - return this->m_template; - } - - [[nodiscard]] size_t getEntryCount() const { - return this->m_entryCount; - } - - void setEntryCount(size_t count) { - this->m_entryCount = count; - } - - void setEntries(std::unique_ptr &&templatePattern, size_t count) { - this->m_template = std::move(templatePattern); - this->m_highlightTemplate = this->m_template->clone(); - this->m_entryCount = count; - - this->m_template->setBaseColor(this->getColor()); - this->m_highlightTemplate->setBaseColor(this->getColor()); - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { - if (!areCommonPropertiesEqual(other)) - return false; - - auto &otherArray = *static_cast(&other); - return *this->m_template == *otherArray.m_template && this->m_entryCount == otherArray.m_entryCount; - } - - [[nodiscard]] const Pattern *getPattern(u64 offset) const override { - if (this->isHidden()) return nullptr; - - this->m_highlightTemplate->setBaseColor(this->getColor()); - this->m_highlightTemplate->setVariableName(this->getVariableName()); - this->m_highlightTemplate->setDisplayName(this->getDisplayName()); - - if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize())) { - this->m_highlightTemplate->setOffset((offset / this->m_highlightTemplate->getSize()) * this->m_highlightTemplate->getSize()); - return this->m_highlightTemplate->getPattern(offset); - } else { - return nullptr; - } - } - - void setEndian(std::endian endian) override { - this->m_template->setEndian(endian); - - Pattern::setEndian(endian); - } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - - private: - std::shared_ptr m_template = nullptr; - mutable std::unique_ptr m_highlightTemplate = nullptr; - size_t m_entryCount = 0; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_bitfield.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_bitfield.hpp deleted file mode 100644 index bde54268b..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_bitfield.hpp +++ /dev/null @@ -1,141 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternBitfieldField : public Pattern { - public: - PatternBitfieldField(Evaluator *evaluator, u64 offset, u8 bitOffset, u8 bitSize, Pattern *bitField, u32 color = 0) - : Pattern(evaluator, offset, 0, color), m_bitOffset(bitOffset), m_bitSize(bitSize), m_bitField(bitField) { - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternBitfieldField(*this)); - } - - u64 getValue(prv::Provider *&provider) { - std::vector value(this->m_bitField->getSize(), 0); - provider->read(this->m_bitField->getOffset(), &value[0], value.size()); - - if (this->m_bitField->getEndian() != std::endian::native) - std::reverse(value.begin(), value.end()); - - return hex::extract(this->m_bitOffset + (this->m_bitSize - 1), this->m_bitOffset, value); - } - - [[nodiscard]] std::string getFormattedName() const override { - return "bits"; - } - - [[nodiscard]] u8 getBitOffset() const { - return this->m_bitOffset; - } - - [[nodiscard]] u8 getBitSize() const { - return this->m_bitSize; - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { - if (!areCommonPropertiesEqual(other)) - return false; - - auto &otherBitfieldField = *static_cast(&other); - return this->m_bitOffset == otherBitfieldField.m_bitOffset && this->m_bitSize == otherBitfieldField.m_bitSize; - } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - - private: - u8 m_bitOffset, m_bitSize; - Pattern *m_bitField; - }; - - class PatternBitfield : public Pattern, - public Inlinable { - public: - PatternBitfield(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { - } - - PatternBitfield(const PatternBitfield &other) : Pattern(other) { - for (auto &field : other.m_fields) - this->m_fields.push_back(field->clone()); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternBitfield(*this)); - } - - std::vector getValue(prv::Provider *&provider) const { - std::vector value(this->getSize(), 0); - provider->read(this->getOffset(), &value[0], value.size()); - - if (this->getEndian() == std::endian::little) - std::reverse(value.begin(), value.end()); - - return value; - } - - void forEachMember(const std::function& fn) { - for (auto &field : this->m_fields) - fn(*field); - } - - void setOffset(u64 offset) override { - for (auto &field : this->m_fields) - field->setOffset(field->getOffset() - this->getOffset() + offset); - - Pattern::setOffset(offset); - } - - [[nodiscard]] std::string getFormattedName() const override { - return "bitfield " + Pattern::getTypeName(); - } - - [[nodiscard]] const auto &getFields() const { - return this->m_fields; - } - - void setFields(std::vector> &&fields) { - this->m_fields = std::move(fields); - - for (auto &field : this->m_fields) { - field->setSize(this->getSize()); - field->setColor(this->getColor()); - } - } - - void setColor(u32 color) override { - Pattern::setColor(color); - for (auto &field : this->m_fields) - field->setColor(color); - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { - if (!areCommonPropertiesEqual(other)) - return false; - - auto &otherBitfield = *static_cast(&other); - if (this->m_fields.size() != otherBitfield.m_fields.size()) - return false; - - for (u64 i = 0; i < this->m_fields.size(); i++) { - if (*this->m_fields[i] != *otherBitfield.m_fields[i]) - return false; - } - - return true; - } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - - private: - std::vector> m_fields; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_boolean.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_boolean.hpp deleted file mode 100644 index 271b4f58f..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_boolean.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternBoolean : public Pattern { - public: - explicit PatternBoolean(Evaluator *evaluator, u64 offset, u32 color = 0) - : Pattern(evaluator, offset, 1, color) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternBoolean(*this)); - } - - u8 getValue(prv::Provider *&provider) { - u8 boolean; - provider->read(this->getOffset(), &boolean, 1); - return boolean; - } - - [[nodiscard]] std::string getFormattedName() const override { - return "bool"; - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_character.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_character.hpp deleted file mode 100644 index 2ac1cb33b..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_character.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternCharacter : public Pattern { - public: - explicit PatternCharacter(Evaluator *evaluator, u64 offset, u32 color = 0) - : Pattern(evaluator, offset, 1, color) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternCharacter(*this)); - } - - char getValue(prv::Provider *&provider) { - char character; - provider->read(this->getOffset(), &character, 1); - return character; - } - - [[nodiscard]] std::string getFormattedName() const override { - return "char"; - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_enum.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_enum.hpp deleted file mode 100644 index 3359a1cda..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_enum.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternEnum : public Pattern { - public: - PatternEnum(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternEnum(*this)); - } - - u64 getValue(prv::Provider *&provider) { - u64 value = 0; - provider->read(this->getOffset(), &value, this->getSize()); - return hex::changeEndianess(value, this->getSize(), this->getEndian()); - } - - [[nodiscard]] std::string getFormattedName() const override { - return "enum " + Pattern::getTypeName(); - } - - [[nodiscard]] std::string getTypeName() const override { - return Pattern::getTypeName(); - } - - void setEnumValues(const std::vector> &enumValues) { - this->m_enumValues = enumValues; - } - - const auto& getEnumValues() const { - return this->m_enumValues; - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { - if (!areCommonPropertiesEqual(other)) - return false; - - auto &otherEnum = *static_cast(&other); - if (this->m_enumValues.size() != otherEnum.m_enumValues.size()) - return false; - - for (u64 i = 0; i < this->m_enumValues.size(); i++) { - if (this->m_enumValues[i] != otherEnum.m_enumValues[i]) - return false; - } - - return true; - } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - - private: - std::vector> m_enumValues; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_float.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_float.hpp deleted file mode 100644 index aa01fe94f..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_float.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternFloat : public Pattern { - public: - PatternFloat(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternFloat(*this)); - } - - double getValue(prv::Provider *&provider) { - if (this->getSize() == 4) { - u32 data = 0; - provider->read(this->getOffset(), &data, 4); - data = hex::changeEndianess(data, 4, this->getEndian()); - - float result = 0; - std::memcpy(&result, &data, sizeof(float)); - return result; - } else if (this->getSize() == 8) { - u64 data = 0; - provider->read(this->getOffset(), &data, 8); - data = hex::changeEndianess(data, 8, this->getEndian()); - - double result = 0; - std::memcpy(&result, &data, sizeof(double)); - return result; - } else { - assert(false); - return std::numeric_limits::quiet_NaN(); - } - } - - [[nodiscard]] std::string getFormattedName() const override { - switch (this->getSize()) { - case 4: - return "float"; - case 8: - return "double"; - default: - return "Floating point data"; - } - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_padding.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_padding.hpp deleted file mode 100644 index 033d25143..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_padding.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternPadding : public Pattern { - public: - PatternPadding(Evaluator *evaluator, u64 offset, size_t size) : Pattern(evaluator, offset, size, 0xFF000000) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternPadding(*this)); - } - - [[nodiscard]] std::string getFormattedName() const override { - return ""; - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_pointer.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_pointer.hpp deleted file mode 100644 index 9dd60632f..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_pointer.hpp +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternPointer : public Pattern, - public Inlinable { - public: - PatternPointer(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color), m_pointedAt(nullptr) { - } - - PatternPointer(const PatternPointer &other) : Pattern(other) { - this->m_pointedAt = other.m_pointedAt->clone(); - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternPointer(*this)); - } - - u64 getValue(prv::Provider *&provider) { - u64 data = 0; - provider->read(this->getOffset(), &data, this->getSize()); - return hex::changeEndianess(data, this->getSize(), this->getEndian()); - } - - void getHighlightedAddresses(std::map &highlight) const override { - Pattern::getHighlightedAddresses(highlight); - this->m_pointedAt->getHighlightedAddresses(highlight); - } - - [[nodiscard]] std::string getFormattedName() const override { - std::string result = (this->getTypeName().empty() ? this->m_pointedAt->getTypeName() : this->getTypeName()) + "* : "; - switch (this->getSize()) { - case 1: - result += "u8"; - break; - case 2: - result += "u16"; - break; - case 4: - result += "u32"; - break; - case 8: - result += "u64"; - break; - case 16: - result += "u128"; - break; - } - - return result; - } - - void setPointedAtPattern(std::unique_ptr &&pattern) { - this->m_pointedAt = std::move(pattern); - this->m_pointedAt->setVariableName(hex::format("*({})", this->getVariableName())); - this->m_pointedAt->setOffset(this->m_pointedAtAddress); - } - - void setPointedAtAddress(u64 address) { - this->m_pointedAtAddress = address; - } - - [[nodiscard]] u64 getPointedAtAddress() const { - return this->m_pointedAtAddress; - } - - [[nodiscard]] const std::unique_ptr &getPointedAtPattern() { - return this->m_pointedAt; - } - - void setColor(u32 color) override { - Pattern::setColor(color); - this->m_pointedAt->setColor(color); - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { - return areCommonPropertiesEqual(other) && - *static_cast(&other)->m_pointedAt == *this->m_pointedAt; - } - - void rebase(u64 base) { - if (this->m_pointedAt != nullptr) { - this->m_pointedAtAddress = (this->m_pointedAt->getOffset() - this->m_pointerBase) + base; - this->m_pointedAt->setOffset(this->m_pointedAtAddress); - } - - this->m_pointerBase = base; - } - - [[nodiscard]] const Pattern *getPattern(u64 offset) const override { - if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()) && !this->isHidden()) - return this; - else - return this->m_pointedAt->getPattern(offset); - } - - void setEndian(std::endian endian) override { - this->m_pointedAt->setEndian(endian); - - Pattern::setEndian(endian); - } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - - private: - std::unique_ptr m_pointedAt; - u64 m_pointedAtAddress = 0; - - u64 m_pointerBase = 0; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_signed.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_signed.hpp deleted file mode 100644 index 7f46b84e4..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_signed.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternSigned : public Pattern { - public: - PatternSigned(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternSigned(*this)); - } - - i128 getValue(prv::Provider *&provider) { - i128 data = 0; - provider->read(this->getOffset(), &data, this->getSize()); - data = hex::changeEndianess(data, this->getSize(), this->getEndian()); - - return hex::signExtend(this->getSize() * 8, data); - } - - [[nodiscard]] std::string getFormattedName() const override { - switch (this->getSize()) { - case 1: - return "s8"; - case 2: - return "s16"; - case 4: - return "s32"; - case 8: - return "s64"; - case 16: - return "s128"; - default: - return "Signed data"; - } - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_string.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_string.hpp deleted file mode 100644 index 5e25e5822..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_string.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternString : public Pattern { - public: - PatternString(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternString(*this)); - } - - std::string getValue(prv::Provider *&provider) const { - return this->getValue(provider, this->getSize()); - } - - std::string getValue(prv::Provider *&provider, size_t size) const { - std::vector buffer(size, 0x00); - provider->read(this->getOffset(), buffer.data(), size); - return hex::encodeByteString(buffer); - } - - [[nodiscard]] std::string getFormattedName() const override { - return "String"; - } - - [[nodiscard]] std::string toString(prv::Provider *provider) const override { - return this->getValue(provider); - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_struct.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_struct.hpp deleted file mode 100644 index bfbf80e87..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_struct.hpp +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternStruct : public Pattern, - public Inlinable { - public: - PatternStruct(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { - } - - PatternStruct(const PatternStruct &other) : Pattern(other) { - for (const auto &member : other.m_members) { - auto copy = member->clone(); - - this->m_sortedMembers.push_back(copy.get()); - this->m_members.push_back(std::move(copy)); - } - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternStruct(*this)); - } - - void getHighlightedAddresses(std::map &highlight) const override { - for (auto &member : this->m_members) { - member->getHighlightedAddresses(highlight); - } - } - - void forEachMember(const std::function& fn) { - for (auto &member : this->m_sortedMembers) - fn(*member); - } - - void setOffset(u64 offset) override { - for (auto &member : this->m_members) - member->setOffset(member->getOffset() - this->getOffset() + offset); - - Pattern::setOffset(offset); - } - - void setColor(u32 color) override { - Pattern::setColor(color); - for (auto &member : this->m_members) { - if (!member->hasOverriddenColor()) - member->setColor(color); - } - } - - void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override { - this->m_sortedMembers.clear(); - for (auto &member : this->m_members) - this->m_sortedMembers.push_back(member.get()); - - std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), [&sortSpecs, &provider](Pattern *left, Pattern *right) { - return Pattern::sortPatternTable(sortSpecs, provider, left, right); - }); - - for (auto &member : this->m_members) - member->sort(sortSpecs, provider); - } - - [[nodiscard]] std::string getFormattedName() const override { - return "struct " + Pattern::getTypeName(); - } - - [[nodiscard]] const auto &getMembers() const { - return this->m_members; - } - - void setMembers(std::vector> &&members) { - this->m_members.clear(); - - for (auto &member : members) { - if (member == nullptr) continue; - - this->m_sortedMembers.push_back(member.get()); - this->m_members.push_back(std::move(member)); - } - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { - if (!areCommonPropertiesEqual(other)) - return false; - - auto &otherStruct = *static_cast(&other); - if (this->m_members.size() != otherStruct.m_members.size()) - return false; - - for (u64 i = 0; i < this->m_members.size(); i++) { - if (*this->m_members[i] != *otherStruct.m_members[i]) - return false; - } - - return true; - } - - [[nodiscard]] const Pattern *getPattern(u64 offset) const override { - if (this->isHidden()) return nullptr; - - for (auto member : this->m_members) { - if (offset >= member->getOffset() && offset < (member->getOffset() + member->getSize())) { - auto candidate = member->getPattern(offset); - if (candidate != nullptr) - return candidate; - } - } - - return nullptr; - } - - void setEndian(std::endian endian) override { - for (auto &member : this->m_members) { - if (!member->hasOverriddenEndian()) - member->setEndian(endian); - } - - Pattern::setEndian(endian); - } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - - private: - std::vector> m_members; - std::vector m_sortedMembers; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_union.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_union.hpp deleted file mode 100644 index fadd34a8e..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_union.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternUnion : public Pattern, - public Inlinable { - public: - PatternUnion(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { - } - - PatternUnion(const PatternUnion &other) : Pattern(other) { - for (const auto &member : other.m_members) { - auto copy = member->clone(); - - this->m_sortedMembers.push_back(copy.get()); - this->m_members.push_back(std::move(copy)); - } - } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternUnion(*this)); - } - - void forEachMember(const std::function& fn) { - for (auto &member : this->m_sortedMembers) - fn(*member); - } - - void getHighlightedAddresses(std::map &highlight) const override { - for (auto &member : this->m_members) { - member->getHighlightedAddresses(highlight); - } - } - - void setOffset(u64 offset) override { - for (auto &member : this->m_members) - member->setOffset(member->getOffset() - this->getOffset() + offset); - - Pattern::setOffset(offset); - } - - void setColor(u32 color) override { - Pattern::setColor(color); - for (auto &member : this->m_members) { - if (!member->hasOverriddenColor()) - member->setColor(color); - } - } - - void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override { - this->m_sortedMembers.clear(); - for (auto &member : this->m_members) - this->m_sortedMembers.push_back(member.get()); - - std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), [&sortSpecs, &provider](Pattern *left, Pattern *right) { - return Pattern::sortPatternTable(sortSpecs, provider, left, right); - }); - - for (auto &member : this->m_members) - member->sort(sortSpecs, provider); - } - - [[nodiscard]] std::string getFormattedName() const override { - return "union " + Pattern::getTypeName(); - } - - [[nodiscard]] const auto &getMembers() const { - return this->m_members; - } - - void setMembers(std::vector> &&members) { - this->m_members.clear(); - for (auto &member : members) { - if (member == nullptr) continue; - - this->m_sortedMembers.push_back(member.get()); - this->m_members.push_back(std::move(member)); - } - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { - if (!areCommonPropertiesEqual(other)) - return false; - - auto &otherUnion = *static_cast(&other); - if (this->m_members.size() != otherUnion.m_members.size()) - return false; - - for (u64 i = 0; i < this->m_members.size(); i++) { - if (*this->m_members[i] != *otherUnion.m_members[i]) - return false; - } - - return true; - } - - [[nodiscard]] const Pattern *getPattern(u64 offset) const override { - if (this->isHidden()) return nullptr; - - auto largestMember = std::find_if(this->m_members.begin(), this->m_members.end(), [this](const std::shared_ptr &pattern) { - return pattern->getSize() == this->getSize(); - }); - - if (largestMember == this->m_members.end()) - return nullptr; - else - return (*largestMember)->getPattern(offset); - ; - } - - void setEndian(std::endian endian) override { - for (auto &member : this->m_members) { - if (!member->hasOverriddenEndian()) - member->setEndian(endian); - } - - Pattern::setEndian(endian); - } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - - private: - std::vector> m_members; - std::vector m_sortedMembers; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_unsigned.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_unsigned.hpp deleted file mode 100644 index 098733407..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_unsigned.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include - -namespace hex::pl { - - class PatternUnsigned : public Pattern { - public: - PatternUnsigned(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternUnsigned(*this)); - } - - u128 getValue(prv::Provider *&provider) { - u128 data = 0; - provider->read(this->getOffset(), &data, this->getSize()); - return hex::changeEndianess(data, this->getSize(), this->getEndian()); - } - - [[nodiscard]] std::string getFormattedName() const override { - switch (this->getSize()) { - case 1: - return "u8"; - case 2: - return "u16"; - case 4: - return "u32"; - case 8: - return "u64"; - case 16: - return "u128"; - default: - return "Unsigned data"; - } - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_character.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_character.hpp deleted file mode 100644 index 2e224b0c7..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_character.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -#include - -namespace hex::pl { - - class PatternWideCharacter : public Pattern { - public: - explicit PatternWideCharacter(Evaluator *evaluator, u64 offset, u32 color = 0) - : Pattern(evaluator, offset, 2, color) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternWideCharacter(*this)); - } - - char16_t getValue(prv::Provider *&provider) { - char16_t character; - provider->read(this->getOffset(), &character, 2); - return hex::changeEndianess(character, this->getEndian()); - } - - [[nodiscard]] std::string getFormattedName() const override { - return "char16"; - } - - [[nodiscard]] std::string toString(prv::Provider *provider) const override { - char16_t character; - provider->read(this->getOffset(), &character, 2); - character = hex::changeEndianess(character, this->getEndian()); - - return std::wstring_convert, char16_t> {}.to_bytes(character); - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_string.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_string.hpp deleted file mode 100644 index 3754e97e0..000000000 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_string.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include - -#include - -namespace hex::pl { - - class PatternWideString : public Pattern { - public: - PatternWideString(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0) - : Pattern(evaluator, offset, size, color) { } - - [[nodiscard]] std::unique_ptr clone() const override { - return std::unique_ptr(new PatternWideString(*this)); - } - - std::string getValue(prv::Provider *&provider) { - return this->getValue(provider, this->getSize()); - } - - std::string getValue(prv::Provider *&provider, size_t size) { - std::u16string buffer(this->getSize() / sizeof(char16_t), 0x00); - provider->read(this->getOffset(), buffer.data(), size); - - for (auto &c : buffer) - c = hex::changeEndianess(c, 2, this->getEndian()); - - auto it = std::remove_if(buffer.begin(), buffer.end(), - [](auto c) { return c == 0x00; }); - buffer.erase(it, buffer.end()); - - return std::wstring_convert, char16_t> {}.to_bytes(buffer); - } - - [[nodiscard]] std::string getFormattedName() const override { - return "String16"; - } - - [[nodiscard]] std::string toString(prv::Provider *provider) const override { - std::u16string buffer(this->getSize() / sizeof(char16_t), 0x00); - provider->read(this->getOffset(), buffer.data(), this->getSize()); - - for (auto &c : buffer) - c = hex::changeEndianess(c, 2, this->getEndian()); - - std::erase_if(buffer, [](auto c) { - return c == 0x00; - }); - - return std::wstring_convert, char16_t> {}.to_bytes(buffer); - } - - [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } - - void accept(PatternVisitor &v) override { - v.visit(*this); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/preprocessor.hpp b/lib/libimhex/include/hex/pattern_language/preprocessor.hpp deleted file mode 100644 index 80e8576bc..000000000 --- a/lib/libimhex/include/hex/pattern_language/preprocessor.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace hex::pl { - - class Preprocessor { - public: - Preprocessor() = default; - - std::optional preprocess(std::string code, bool initialRun = true); - - void addPragmaHandler(const std::string &pragmaType, const std::function &function); - void removePragmaHandler(const std::string &pragmaType); - void addDefaultPragmaHandlers(); - - const std::optional &getError() { return this->m_error; } - - [[nodiscard]] bool shouldOnlyIncludeOnce() const { - return this->m_onlyIncludeOnce; - } - - private: - [[noreturn]] static void throwPreprocessorError(const std::string &error, u32 lineNumber) { - throw PatternLanguageError(lineNumber, "Preprocessor: " + error); - } - - std::unordered_map> m_pragmaHandlers; - - std::set> m_defines; - std::set> m_pragmas; - - std::set m_onceIncludedFiles; - - std::optional m_error; - - bool m_onlyIncludeOnce = false; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/token.hpp b/lib/libimhex/include/hex/pattern_language/token.hpp deleted file mode 100644 index 405d11c66..000000000 --- a/lib/libimhex/include/hex/pattern_language/token.hpp +++ /dev/null @@ -1,365 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include -#include - -namespace hex::pl { - - class ASTNode; - class Pattern; - - class Token { - public: - enum class Type : u64 - { - Keyword, - ValueType, - Operator, - Integer, - String, - Identifier, - Separator - }; - - enum class Keyword - { - Struct, - Union, - Using, - Enum, - Bitfield, - LittleEndian, - BigEndian, - If, - Else, - Parent, - This, - While, - For, - Function, - Return, - Namespace, - In, - Out, - Break, - Continue - }; - - enum class Operator - { - AtDeclaration, - Assignment, - Inherit, - Plus, - Minus, - Star, - Slash, - Percent, - ShiftLeft, - ShiftRight, - BitOr, - BitAnd, - BitXor, - BitNot, - BoolEquals, - BoolNotEquals, - BoolGreaterThan, - BoolLessThan, - BoolGreaterThanOrEquals, - BoolLessThanOrEquals, - BoolAnd, - BoolOr, - BoolXor, - BoolNot, - TernaryConditional, - Dollar, - AddressOf, - SizeOf, - ScopeResolution - }; - - enum class ValueType - { - Unsigned8Bit = 0x10, - Signed8Bit = 0x11, - Unsigned16Bit = 0x20, - Signed16Bit = 0x21, - Unsigned32Bit = 0x40, - Signed32Bit = 0x41, - Unsigned64Bit = 0x80, - Signed64Bit = 0x81, - Unsigned128Bit = 0x100, - Signed128Bit = 0x101, - Character = 0x13, - Character16 = 0x23, - Boolean = 0x14, - Float = 0x42, - Double = 0x82, - String = 0x15, - Auto = 0x16, - CustomType = 0x00, - Padding = 0x1F, - - Unsigned = 0xFF00, - Signed = 0xFF01, - FloatingPoint = 0xFF02, - Integer = 0xFF03, - Any = 0xFFFF - }; - - enum class Separator - { - RoundBracketOpen, - RoundBracketClose, - CurlyBracketOpen, - CurlyBracketClose, - SquareBracketOpen, - SquareBracketClose, - Comma, - Dot, - EndOfExpression, - EndOfProgram - }; - - struct Identifier { - explicit Identifier(std::string identifier) : m_identifier(std::move(identifier)) { } - - [[nodiscard]] const std::string &get() const { return this->m_identifier; } - - bool operator==(const Identifier &) const = default; - - private: - std::string m_identifier; - }; - - using Literal = std::variant; - using ValueTypes = std::variant; - - Token(Type type, auto value, u32 lineNumber) : type(type), value(value), lineNumber(lineNumber) { - } - - [[nodiscard]] constexpr static inline bool isUnsigned(const ValueType type) { - return (static_cast(type) & 0x0F) == 0x00; - } - - [[nodiscard]] constexpr static inline bool isSigned(const ValueType type) { - return (static_cast(type) & 0x0F) == 0x01; - } - - [[nodiscard]] constexpr static inline bool isFloatingPoint(const ValueType type) { - return (static_cast(type) & 0x0F) == 0x02; - } - - [[nodiscard]] constexpr static inline u32 getTypeSize(const ValueType type) { - return static_cast(type) >> 4; - } - - static u128 literalToUnsigned(const pl::Token::Literal &literal) { - return std::visit(overloaded { - [](const std::string &) -> u128 { LogConsole::abortEvaluation("expected integral type, got string"); }, - [](Pattern *) -> u128 { LogConsole::abortEvaluation("expected integral type, got custom type"); }, - [](auto &&result) -> u128 { return result; } }, - literal); - } - - static i128 literalToSigned(const pl::Token::Literal &literal) { - return std::visit(overloaded { - [](const std::string &) -> i128 { LogConsole::abortEvaluation("expected integral type, got string"); }, - [](Pattern *) -> i128 { LogConsole::abortEvaluation("expected integral type, got custom type"); }, - [](auto &&result) -> i128 { return result; } }, - literal); - } - - static double literalToFloatingPoint(const pl::Token::Literal &literal) { - return std::visit(overloaded { - [](const std::string &) -> double { LogConsole::abortEvaluation("expected integral type, got string"); }, - [](Pattern *) -> double { LogConsole::abortEvaluation("expected integral type, got custom type"); }, - [](auto &&result) -> double { return result; } }, - literal); - } - - static bool literalToBoolean(const pl::Token::Literal &literal) { - return std::visit(overloaded { - [](const std::string &) -> bool { LogConsole::abortEvaluation("expected integral type, got string"); }, - [](Pattern *) -> bool { LogConsole::abortEvaluation("expected integral type, got custom type"); }, - [](auto &&result) -> bool { return result != 0; } }, - literal); - } - - static std::string literalToString(const pl::Token::Literal &literal, bool cast) { - if (!cast && std::get_if(&literal) == nullptr) - LogConsole::abortEvaluation("expected string type, got integral"); - - return std::visit(overloaded { - [](std::string result) -> std::string { return result; }, - [](u128 result) -> std::string { return hex::to_string(result); }, - [](i128 result) -> std::string { return hex::to_string(result); }, - [](bool result) -> std::string { return result ? "true" : "false"; }, - [](char result) -> std::string { return { 1, result }; }, - [](Pattern *) -> std::string { LogConsole::abortEvaluation("expected integral type, got custom type"); }, - [](auto &&result) -> std::string { return std::to_string(result); } }, - literal); - } - - [[nodiscard]] constexpr static auto getTypeName(const pl::Token::ValueType type) { - switch (type) { - case ValueType::Signed8Bit: - return "s8"; - case ValueType::Signed16Bit: - return "s16"; - case ValueType::Signed32Bit: - return "s32"; - case ValueType::Signed64Bit: - return "s64"; - case ValueType::Signed128Bit: - return "s128"; - case ValueType::Unsigned8Bit: - return "u8"; - case ValueType::Unsigned16Bit: - return "u16"; - case ValueType::Unsigned32Bit: - return "u32"; - case ValueType::Unsigned64Bit: - return "u64"; - case ValueType::Unsigned128Bit: - return "u128"; - case ValueType::Float: - return "float"; - case ValueType::Double: - return "double"; - case ValueType::Character: - return "char"; - case ValueType::Character16: - return "char16"; - case ValueType::Padding: - return "padding"; - case ValueType::String: - return "str"; - case ValueType::Boolean: - return "bool"; - default: - return "< ??? >"; - } - } - - bool operator==(const ValueTypes &other) const { - if (this->type == Type::Integer || this->type == Type::Identifier || this->type == Type::String) - return true; - else if (this->type == Type::ValueType) { - auto otherValueType = std::get_if(&other); - auto valueType = std::get_if(&this->value); - - if (otherValueType == nullptr) return false; - if (valueType == nullptr) return false; - - if (*otherValueType == *valueType) - return true; - else if (*otherValueType == ValueType::Any) - return *valueType != ValueType::CustomType && *valueType != ValueType::Padding; - else if (*otherValueType == ValueType::Unsigned) - return isUnsigned(*valueType); - else if (*otherValueType == ValueType::Signed) - return isSigned(*valueType); - else if (*otherValueType == ValueType::FloatingPoint) - return isFloatingPoint(*valueType); - else if (*otherValueType == ValueType::Integer) - return isUnsigned(*valueType) || isSigned(*valueType); - } else - return other == this->value; - - return false; - } - - bool operator!=(const ValueTypes &other) const { - return !operator==(other); - } - - Type type; - ValueTypes value; - u32 lineNumber; - }; - -} - -#define COMPONENT(type, value) hex::pl::Token::Type::type, hex::pl::Token::type::value - -#define KEYWORD_STRUCT COMPONENT(Keyword, Struct) -#define KEYWORD_UNION COMPONENT(Keyword, Union) -#define KEYWORD_USING COMPONENT(Keyword, Using) -#define KEYWORD_ENUM COMPONENT(Keyword, Enum) -#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield) -#define KEYWORD_LE COMPONENT(Keyword, LittleEndian) -#define KEYWORD_BE COMPONENT(Keyword, BigEndian) -#define KEYWORD_IF COMPONENT(Keyword, If) -#define KEYWORD_ELSE COMPONENT(Keyword, Else) -#define KEYWORD_PARENT COMPONENT(Keyword, Parent) -#define KEYWORD_THIS COMPONENT(Keyword, This) -#define KEYWORD_WHILE COMPONENT(Keyword, While) -#define KEYWORD_FOR COMPONENT(Keyword, For) -#define KEYWORD_FUNCTION COMPONENT(Keyword, Function) -#define KEYWORD_RETURN COMPONENT(Keyword, Return) -#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace) -#define KEYWORD_IN COMPONENT(Keyword, In) -#define KEYWORD_OUT COMPONENT(Keyword, Out) -#define KEYWORD_BREAK COMPONENT(Keyword, Break) -#define KEYWORD_CONTINUE COMPONENT(Keyword, Continue) - -#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0)) -#define IDENTIFIER hex::pl::Token::Type::Identifier, "" -#define STRING hex::pl::Token::Type::String, hex::pl::Token::Literal("") - -#define OPERATOR_ANY COMPONENT(Operator, Any) -#define OPERATOR_AT COMPONENT(Operator, AtDeclaration) -#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment) -#define OPERATOR_INHERIT COMPONENT(Operator, Inherit) -#define OPERATOR_PLUS COMPONENT(Operator, Plus) -#define OPERATOR_MINUS COMPONENT(Operator, Minus) -#define OPERATOR_STAR COMPONENT(Operator, Star) -#define OPERATOR_SLASH COMPONENT(Operator, Slash) -#define OPERATOR_PERCENT COMPONENT(Operator, Percent) -#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft) -#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight) -#define OPERATOR_BITOR COMPONENT(Operator, BitOr) -#define OPERATOR_BITAND COMPONENT(Operator, BitAnd) -#define OPERATOR_BITXOR COMPONENT(Operator, BitXor) -#define OPERATOR_BITNOT COMPONENT(Operator, BitNot) -#define OPERATOR_BOOLEQUALS COMPONENT(Operator, BoolEquals) -#define OPERATOR_BOOLNOTEQUALS COMPONENT(Operator, BoolNotEquals) -#define OPERATOR_BOOLGREATERTHAN COMPONENT(Operator, BoolGreaterThan) -#define OPERATOR_BOOLLESSTHAN COMPONENT(Operator, BoolLessThan) -#define OPERATOR_BOOLGREATERTHANOREQUALS COMPONENT(Operator, BoolGreaterThanOrEquals) -#define OPERATOR_BOOLLESSTHANOREQUALS COMPONENT(Operator, BoolLessThanOrEquals) -#define OPERATOR_BOOLAND COMPONENT(Operator, BoolAnd) -#define OPERATOR_BOOLOR COMPONENT(Operator, BoolOr) -#define OPERATOR_BOOLXOR COMPONENT(Operator, BoolXor) -#define OPERATOR_BOOLNOT COMPONENT(Operator, BoolNot) -#define OPERATOR_TERNARYCONDITIONAL COMPONENT(Operator, TernaryConditional) -#define OPERATOR_DOLLAR COMPONENT(Operator, Dollar) -#define OPERATOR_ADDRESSOF COMPONENT(Operator, AddressOf) -#define OPERATOR_SIZEOF COMPONENT(Operator, SizeOf) -#define OPERATOR_SCOPERESOLUTION COMPONENT(Operator, ScopeResolution) - -#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType) -#define VALUETYPE_PADDING COMPONENT(ValueType, Padding) -#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned) -#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed) -#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint) -#define VALUETYPE_AUTO COMPONENT(ValueType, Auto) -#define VALUETYPE_ANY COMPONENT(ValueType, Any) - -#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen) -#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose) -#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen) -#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose) -#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen) -#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose) -#define SEPARATOR_COMMA COMPONENT(Separator, Comma) -#define SEPARATOR_DOT COMPONENT(Separator, Dot) -#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression) -#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram) \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/validator.hpp b/lib/libimhex/include/hex/pattern_language/validator.hpp deleted file mode 100644 index 0911881c2..000000000 --- a/lib/libimhex/include/hex/pattern_language/validator.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include - -#include - -namespace hex::pl { - - class ASTNode; - - class Validator { - public: - Validator() = default; - - bool validate(const std::vector> &ast); - - const std::optional &getError() { return this->m_error; } - - private: - std::optional m_error; - - [[noreturn]] static void throwValidatorError(const std::string &error, u32 lineNumber) { - throw PatternLanguageError(lineNumber, "Validator: " + error); - } - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/providers/provider.hpp b/lib/libimhex/include/hex/providers/provider.hpp index 3bb00121e..53b603236 100644 --- a/lib/libimhex/include/hex/providers/provider.hpp +++ b/lib/libimhex/include/hex/providers/provider.hpp @@ -11,7 +11,7 @@ #include #include -namespace hex::pl { +namespace pl { class PatternLanguage; } diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index b6141e6f6..44a64612a 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -220,7 +220,7 @@ namespace hex { namespace ContentRegistry::PatternLanguage { - static std::string getFunctionName(const Namespace &ns, const std::string &name) { + static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) { std::string functionName; for (auto &scope : ns) functionName += scope + "::"; @@ -230,63 +230,67 @@ namespace hex { return functionName; } - void addFunction(const Namespace &ns, const std::string &name, ParameterCount parameterCount, const Callback &func) { + std::unique_ptr createDefaultRuntime(prv::Provider *provider) { + auto runtime = std::make_unique(); + + runtime->setDataSource([provider](u64 offset, u8 *buffer, size_t size) { + provider->read(offset, buffer, size); + }, 0, 0); + + runtime->setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude)); + + for (const auto &func : getFunctions()) { + if (func.dangerous) + runtime->addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback); + else + runtime->addFunction(func.ns, func.name, func.parameterCount, func.callback); + } + + for (const auto &[name, callback] : getPragmas()) { + runtime->addPragma(name, callback); + } + + return runtime; + } + + void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) { + log::info("Registered new pattern language pragma: {}", name); + + getPragmas()[name] = handler; + } + + void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) { log::info("Registered new pattern language function: {}", getFunctionName(ns, name)); - getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, { }, func, false }; + getFunctions().push_back({ + ns, name, + parameterCount, func, + false + }); } - void addDangerousFunction(const Namespace &ns, const std::string &name, ParameterCount parameterCount, const Callback &func) { + void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) { log::info("Registered new dangerous pattern language function: {}", getFunctionName(ns, name)); - getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, { }, func, true }; + getFunctions().push_back({ + ns, name, + parameterCount, func, + true + }); } - std::map &getFunctions() { - static std::map functions; + std::map &getPragmas() { + static std::map pragmas; + + return pragmas; + } + + std::vector &getFunctions() { + static std::vector functions; return functions; } - - static std::vector s_colorPalettes; - static u32 s_colorIndex; - static u32 s_selectedColorPalette; - - std::vector &getPalettes() { - return s_colorPalettes; - } - - void addColorPalette(const std::string &unlocalizedName, const std::vector &colors) { - s_colorPalettes.push_back({ unlocalizedName, - colors }); - } - - void setSelectedPalette(u32 index) { - if (index < s_colorPalettes.size()) - s_selectedColorPalette = index; - - resetPalette(); - } - - u32 getNextColor() { - if (s_colorPalettes.empty()) - return 0x00; - - auto &currColors = s_colorPalettes[s_selectedColorPalette].colors; - - u32 color = currColors[s_colorIndex]; - - s_colorIndex++; - s_colorIndex %= currColors.size(); - - return color; - } - - void resetPalette() { - s_colorIndex = 0; - } - } diff --git a/lib/libimhex/source/pattern_language/evaluator.cpp b/lib/libimhex/source/pattern_language/evaluator.cpp deleted file mode 100644 index 81246bb45..000000000 --- a/lib/libimhex/source/pattern_language/evaluator.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace hex::pl { - - void Evaluator::createParameterPack(const std::string &name, const std::vector &values) { - this->getScope(0).parameterPack = ParameterPack { - name, - values - }; - } - - void Evaluator::createVariable(const std::string &name, ASTNode *type, const std::optional &value, bool outVariable) { - auto &variables = *this->getScope(0).scope; - for (auto &variable : variables) { - if (variable->getVariableName() == name) { - LogConsole::abortEvaluation(hex::format("variable with name '{}' already exists", name)); - } - } - - auto startOffset = this->dataOffset(); - - std::unique_ptr pattern; - - bool referenceType = false; - - auto typePattern = type->createPatterns(this); - - this->dataOffset() = startOffset; - - if (typePattern.empty()) { - // Handle auto variables - if (!value.has_value()) - LogConsole::abortEvaluation("cannot determine type of auto variable", type); - - if (std::get_if(&value.value()) != nullptr) - pattern = std::unique_ptr(new PatternUnsigned(this, 0, sizeof(u128))); - else if (std::get_if(&value.value()) != nullptr) - pattern = std::unique_ptr(new PatternSigned(this, 0, sizeof(i128))); - else if (std::get_if(&value.value()) != nullptr) - pattern = std::unique_ptr(new PatternFloat(this, 0, sizeof(double))); - else if (std::get_if(&value.value()) != nullptr) - pattern = std::unique_ptr(new PatternBoolean(this, 0)); - else if (std::get_if(&value.value()) != nullptr) - pattern = std::unique_ptr(new PatternCharacter(this, 0)); - else if (std::get_if(&value.value()) != nullptr) - pattern = std::unique_ptr(new PatternString(this, 0, 1)); - else if (auto patternValue = std::get_if(&value.value()); patternValue != nullptr) { - pattern = (*patternValue)->clone(); - referenceType = true; - } else - LogConsole::abortEvaluation("cannot determine type of auto variable", type); - } else { - pattern = std::move(typePattern.front()); - } - - pattern->setVariableName(name); - - if (!referenceType) { - pattern->setOffset(this->getStack().size()); - pattern->setLocal(true); - this->getStack().emplace_back(); - } - - if (outVariable) - this->m_outVariables[name] = pattern->getOffset(); - - variables.push_back(std::move(pattern)); - } - - void Evaluator::setVariable(const std::string &name, const Token::Literal &value) { - std::unique_ptr pattern = nullptr; - - { - auto &variables = *this->getScope(0).scope; - for (auto &variable : variables) { - if (variable->getVariableName() == name) { - pattern = variable->clone(); - break; - } - } - } - - if (pattern == nullptr) { - auto &variables = *this->getGlobalScope().scope; - for (auto &variable : variables) { - if (variable->getVariableName() == name) { - if (!variable->isLocal()) - LogConsole::abortEvaluation(hex::format("cannot modify global variable '{}' which has been placed in memory", name)); - - pattern = variable->clone(); - break; - } - } - } - - if (pattern == nullptr) - LogConsole::abortEvaluation(hex::format("no variable with name '{}' found", name)); - - if (!pattern->isLocal()) return; - - Token::Literal castedLiteral = std::visit(overloaded { - [&](double &value) -> Token::Literal { - if (dynamic_cast(pattern.get())) - return u128(value) & bitmask(pattern->getSize() * 8); - else if (dynamic_cast(pattern.get())) - return i128(value) & bitmask(pattern->getSize() * 8); - else if (dynamic_cast(pattern.get())) - return pattern->getSize() == sizeof(float) ? double(float(value)) : value; - else - LogConsole::abortEvaluation(hex::format("cannot cast type 'double' to type '{}'", pattern->getTypeName())); - }, - [&](const std::string &value) -> Token::Literal { - if (dynamic_cast(pattern.get())) - return value; - else - LogConsole::abortEvaluation(hex::format("cannot cast type 'string' to type '{}'", pattern->getTypeName())); - }, - [&](Pattern *value) -> Token::Literal { - if (value->getTypeName() == pattern->getTypeName()) - return value; - else - LogConsole::abortEvaluation(hex::format("cannot cast type '{}' to type '{}'", value->getTypeName(), pattern->getTypeName())); - }, - [&](auto &&value) -> Token::Literal { - if (dynamic_cast(pattern.get()) || dynamic_cast(pattern.get())) - return u128(value) & bitmask(pattern->getSize() * 8); - else if (dynamic_cast(pattern.get())) - return i128(value) & bitmask(pattern->getSize() * 8); - else if (dynamic_cast(pattern.get())) - return char(value); - else if (dynamic_cast(pattern.get())) - return bool(value); - else if (dynamic_cast(pattern.get())) - return pattern->getSize() == sizeof(float) ? double(float(value)) : value; - else - LogConsole::abortEvaluation(hex::format("cannot cast integer literal to type '{}'", pattern->getTypeName())); - } }, - value); - - this->getStack()[pattern->getOffset()] = castedLiteral; - } - - std::optional>> Evaluator::evaluate(const std::vector> &ast) { - this->m_stack.clear(); - this->m_customFunctions.clear(); - this->m_scopes.clear(); - this->m_mainResult.reset(); - this->m_aborted = false; - - if (this->m_allowDangerousFunctions == DangerousFunctionPermission::Deny) - this->m_allowDangerousFunctions = DangerousFunctionPermission::Ask; - - this->m_dangerousFunctionCalled = false; - - ON_SCOPE_EXIT { - this->m_envVariables.clear(); - }; - - this->dataOffset() = 0x00; - this->m_currPatternCount = 0; - - this->m_customFunctionDefinitions.clear(); - - std::vector> patterns; - - try { - this->setCurrentControlFlowStatement(ControlFlowStatement::None); - pushScope(nullptr, patterns); - ON_SCOPE_EXIT { - popScope(); - }; - - for (auto &node : ast) { - if (dynamic_cast(node.get())) { - ; // Don't create patterns from type declarations - } else if (dynamic_cast(node.get())) { - (void)node->evaluate(this); - } else if (dynamic_cast(node.get())) { - this->m_customFunctionDefinitions.push_back(node->evaluate(this)); - } else if (auto varDeclNode = dynamic_cast(node.get())) { - for (auto &pattern : node->createPatterns(this)) { - if (varDeclNode->getPlacementOffset() == nullptr) { - auto type = varDeclNode->getType()->evaluate(this); - - auto &name = pattern->getVariableName(); - this->createVariable(name, type.get(), std::nullopt, varDeclNode->isOutVariable()); - - if (varDeclNode->isInVariable() && this->m_inVariables.contains(name)) - this->setVariable(name, this->m_inVariables[name]); - } else { - patterns.push_back(std::move(pattern)); - } - } - } else { - auto newPatterns = node->createPatterns(this); - std::move(newPatterns.begin(), newPatterns.end(), std::back_inserter(patterns)); - } - } - - if (this->m_customFunctions.contains("main")) { - auto mainFunction = this->m_customFunctions["main"]; - - if (mainFunction.parameterCount.max > 0) - LogConsole::abortEvaluation("main function may not accept any arguments"); - - this->m_mainResult = mainFunction.func(this, {}); - } - } catch (PatternLanguageError &error) { - if (error.getLineNumber() != 0) - this->m_console.setHardError(error); - - patterns.clear(); - - this->m_currPatternCount = 0; - - return std::nullopt; - } - - // Remove global local variables - std::erase_if(patterns, [](const std::shared_ptr &pattern) { - return pattern->isLocal(); - }); - - return patterns; - } - - void Evaluator::patternCreated() { - if (this->m_currPatternCount > this->m_patternLimit) - LogConsole::abortEvaluation(hex::format("exceeded maximum number of patterns: {}", this->m_patternLimit)); - this->m_currPatternCount++; - } - - void Evaluator::patternDestroyed() { - this->m_currPatternCount--; - } - -} \ No newline at end of file diff --git a/lib/libimhex/source/pattern_language/lexer.cpp b/lib/libimhex/source/pattern_language/lexer.cpp deleted file mode 100644 index 07b332774..000000000 --- a/lib/libimhex/source/pattern_language/lexer.cpp +++ /dev/null @@ -1,534 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -namespace hex::pl { - -#define TOKEN(type, value) Token::Type::type, Token::type::value, lineNumber -#define VALUE_TOKEN(type, value) Token::Type::type, value, lineNumber - - std::string matchTillInvalid(const char *characters, const std::function &predicate) { - std::string ret; - - while (*characters != 0x00) { - ret += *characters; - characters++; - - if (!predicate(*characters)) - break; - } - - return ret; - } - - bool isIdentifierCharacter(char c) { - return std::isalnum(c) || c == '_'; - } - - size_t getIntegerLiteralLength(std::string_view string) { - auto count = string.find_first_not_of("0123456789ABCDEFabcdef'xXoOpP.uU"); - if (count == std::string_view::npos) - return string.size(); - else - return count; - } - - std::optional lexIntegerLiteral(std::string_view string) { - bool hasFloatSuffix = string.ends_with('D') || string.ends_with('F') || string.ends_with('d') || string.ends_with('f'); - bool isFloat = std::count(string.begin(), string.end(), '.') == 1 || (!string.starts_with("0x") && hasFloatSuffix); - - if (isFloat) { - // Parse double - char suffix = 0x00; - if (hasFloatSuffix) { - suffix = string.back(); - string = string.substr(0, string.length() - 1); - } - - char *end = nullptr; - double value = std::strtod(string.begin(), &end); - - if (end == string.end()) { - switch (suffix) { - case 'd': - case 'D': - return double(value); - case 'f': - case 'F': - return float(value); - default: - return value; - } - } - } else { - bool isUnsigned = false; - if (string.ends_with('U') || string.ends_with('u')) { - isUnsigned = true; - string = string.substr(0, string.length() - 1); - } - - u8 prefixOffset = 0; - u8 base = 10; - - if (string.starts_with("0x") || string.starts_with("0X")) { - // Parse hexadecimal - prefixOffset = 2; - base = 16; - } else if (string.starts_with("0o") || string.starts_with("0O")) { - // Parse octal - prefixOffset = 2; - base = 8; - } else if (string.starts_with("0b") || string.starts_with("0B")) { - // Parse binary - prefixOffset = 2; - base = 2; - } else { - // Parse decimal - prefixOffset = 0; - base = 10; - } - - u128 value = 0x00; - for (char c : string.substr(prefixOffset)) { - value *= base; - value += [&] { - if (c >= '0' && c <= '9') return c - '0'; - else if (c >= 'A' && c <= 'F') return 0xA + (c - 'A'); - else if (c >= 'a' && c <= 'f') return 0xA + (c - 'a'); - else return 0x00; - }(); - } - - if (isUnsigned) - return value; - else - return i128(value); - } - - return std::nullopt; - } - - std::optional lexIntegerLiteralWithSeparator(std::string_view string) { - - if (string.starts_with('\'') || string.ends_with('\'')) - return std::nullopt; - else if (string.find('\'') == std::string_view::npos) - return lexIntegerLiteral(string); - else { - auto preprocessedString = std::string(string); - preprocessedString.erase(std::remove(preprocessedString.begin(), preprocessedString.end(), '\''), preprocessedString.end()); - return lexIntegerLiteral(preprocessedString); - } - } - - std::optional> getCharacter(const std::string &string) { - - if (string.length() < 1) - return std::nullopt; - - // Escape sequences - if (string[0] == '\\') { - - if (string.length() < 2) - return std::nullopt; - - // Handle simple escape sequences - switch (string[1]) { - case 'a': - return { - {'\a', 2} - }; - case 'b': - return { - {'\b', 2} - }; - case 'f': - return { - {'\f', 2} - }; - case 'n': - return { - {'\n', 2} - }; - case 'r': - return { - {'\r', 2} - }; - case 't': - return { - {'\t', 2} - }; - case 'v': - return { - {'\v', 2} - }; - case '\\': - return { - {'\\', 2} - }; - case '\'': - return { - {'\'', 2} - }; - case '\"': - return { - {'\"', 2} - }; - } - - // Hexadecimal number - if (string[1] == 'x') { - if (string.length() != 4) - return std::nullopt; - - if (!isxdigit(string[2]) || !isxdigit(string[3])) - return std::nullopt; - - return { - {std::strtoul(&string[2], nullptr, 16), 4} - }; - } - - // Octal number - if (string[1] == 'o') { - if (string.length() != 5) - return {}; - - if (string[2] < '0' || string[2] > '7' || string[3] < '0' || string[3] > '7' || string[4] < '0' || string[4] > '7') - return {}; - - return { - {std::strtoul(&string[2], nullptr, 8), 5} - }; - } - - return std::nullopt; - } else return { - {string[0], 1} - }; - } - - std::optional> getStringLiteral(const std::string &string) { - if (!string.starts_with('\"')) - return {}; - - size_t size = 1; - - std::string result; - while (string[size] != '\"') { - auto character = getCharacter(string.substr(size)); - - if (!character.has_value()) - return {}; - - auto &[c, charSize] = character.value(); - - result += c; - size += charSize; - - if (size >= string.length()) - return {}; - } - - return { - {result, size + 1} - }; - } - - std::optional> getCharacterLiteral(const std::string &string) { - if (string.empty()) - return {}; - - if (string[0] != '\'') - return {}; - - - auto character = getCharacter(string.substr(1)); - - if (!character.has_value()) - return {}; - - auto &[c, charSize] = character.value(); - - if (string.length() >= charSize + 2 && string[charSize + 1] != '\'') - return {}; - - return { - {c, charSize + 2} - }; - } - - std::optional> Lexer::lex(const std::string &code) { - std::vector tokens; - u32 offset = 0; - - u32 lineNumber = 1; - - try { - - while (offset < code.length()) { - const char &c = code[offset]; - - if (c == 0x00) - break; - - if (std::isblank(c) || std::isspace(c)) { - if (code[offset] == '\n') lineNumber++; - offset += 1; - } else if (c == ';') { - tokens.emplace_back(TOKEN(Separator, EndOfExpression)); - offset += 1; - } else if (c == '(') { - tokens.emplace_back(TOKEN(Separator, RoundBracketOpen)); - offset += 1; - } else if (c == ')') { - tokens.emplace_back(TOKEN(Separator, RoundBracketClose)); - offset += 1; - } else if (c == '{') { - tokens.emplace_back(TOKEN(Separator, CurlyBracketOpen)); - offset += 1; - } else if (c == '}') { - tokens.emplace_back(TOKEN(Separator, CurlyBracketClose)); - offset += 1; - } else if (c == '[') { - tokens.emplace_back(TOKEN(Separator, SquareBracketOpen)); - offset += 1; - } else if (c == ']') { - tokens.emplace_back(TOKEN(Separator, SquareBracketClose)); - offset += 1; - } else if (c == ',') { - tokens.emplace_back(TOKEN(Separator, Comma)); - offset += 1; - } else if (c == '.') { - tokens.emplace_back(TOKEN(Separator, Dot)); - offset += 1; - } else if (code.substr(offset, 2) == "::") { - tokens.emplace_back(TOKEN(Operator, ScopeResolution)); - offset += 2; - } else if (c == '@') { - tokens.emplace_back(TOKEN(Operator, AtDeclaration)); - offset += 1; - } else if (code.substr(offset, 2) == "==") { - tokens.emplace_back(TOKEN(Operator, BoolEquals)); - offset += 2; - } else if (code.substr(offset, 2) == "!=") { - tokens.emplace_back(TOKEN(Operator, BoolNotEquals)); - offset += 2; - } else if (code.substr(offset, 2) == ">=") { - tokens.emplace_back(TOKEN(Operator, BoolGreaterThanOrEquals)); - offset += 2; - } else if (code.substr(offset, 2) == "<=") { - tokens.emplace_back(TOKEN(Operator, BoolLessThanOrEquals)); - offset += 2; - } else if (code.substr(offset, 2) == "&&") { - tokens.emplace_back(TOKEN(Operator, BoolAnd)); - offset += 2; - } else if (code.substr(offset, 2) == "||") { - tokens.emplace_back(TOKEN(Operator, BoolOr)); - offset += 2; - } else if (code.substr(offset, 2) == "^^") { - tokens.emplace_back(TOKEN(Operator, BoolXor)); - offset += 2; - } else if (c == '=') { - tokens.emplace_back(TOKEN(Operator, Assignment)); - offset += 1; - } else if (c == ':') { - tokens.emplace_back(TOKEN(Operator, Inherit)); - offset += 1; - } else if (c == '+') { - tokens.emplace_back(TOKEN(Operator, Plus)); - offset += 1; - } else if (c == '-') { - tokens.emplace_back(TOKEN(Operator, Minus)); - offset += 1; - } else if (c == '*') { - tokens.emplace_back(TOKEN(Operator, Star)); - offset += 1; - } else if (c == '/') { - tokens.emplace_back(TOKEN(Operator, Slash)); - offset += 1; - } else if (c == '%') { - tokens.emplace_back(TOKEN(Operator, Percent)); - offset += 1; - } else if (code.substr(offset, 2) == "<<") { - tokens.emplace_back(TOKEN(Operator, ShiftLeft)); - offset += 2; - } else if (code.substr(offset, 2) == ">>") { - tokens.emplace_back(TOKEN(Operator, ShiftRight)); - offset += 2; - } else if (c == '>') { - tokens.emplace_back(TOKEN(Operator, BoolGreaterThan)); - offset += 1; - } else if (c == '<') { - tokens.emplace_back(TOKEN(Operator, BoolLessThan)); - offset += 1; - } else if (c == '!') { - tokens.emplace_back(TOKEN(Operator, BoolNot)); - offset += 1; - } else if (c == '|') { - tokens.emplace_back(TOKEN(Operator, BitOr)); - offset += 1; - } else if (c == '&') { - tokens.emplace_back(TOKEN(Operator, BitAnd)); - offset += 1; - } else if (c == '^') { - tokens.emplace_back(TOKEN(Operator, BitXor)); - offset += 1; - } else if (c == '~') { - tokens.emplace_back(TOKEN(Operator, BitNot)); - offset += 1; - } else if (c == '?') { - tokens.emplace_back(TOKEN(Operator, TernaryConditional)); - offset += 1; - } else if (c == '$') { - tokens.emplace_back(TOKEN(Operator, Dollar)); - offset += 1; - } else if (code.substr(offset, 9) == "addressof" && !isIdentifierCharacter(code[offset + 9])) { - tokens.emplace_back(TOKEN(Operator, AddressOf)); - offset += 9; - } else if (code.substr(offset, 6) == "sizeof" && !isIdentifierCharacter(code[offset + 6])) { - tokens.emplace_back(TOKEN(Operator, SizeOf)); - offset += 6; - } else if (c == '\'') { - auto lexedCharacter = getCharacterLiteral(code.substr(offset)); - - if (!lexedCharacter.has_value()) - throwLexerError("invalid character literal", lineNumber); - - auto [character, charSize] = lexedCharacter.value(); - - tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(character))); - offset += charSize; - } else if (c == '\"') { - auto string = getStringLiteral(code.substr(offset)); - - if (!string.has_value()) - throwLexerError("invalid string literal", lineNumber); - - auto [s, stringSize] = string.value(); - - tokens.emplace_back(VALUE_TOKEN(String, Token::Literal(s))); - offset += stringSize; - } else if (isIdentifierCharacter(c) && !std::isdigit(c)) { - std::string identifier = matchTillInvalid(&code[offset], isIdentifierCharacter); - - // Check for reserved keywords - - if (identifier == "struct") - tokens.emplace_back(TOKEN(Keyword, Struct)); - else if (identifier == "union") - tokens.emplace_back(TOKEN(Keyword, Union)); - else if (identifier == "using") - tokens.emplace_back(TOKEN(Keyword, Using)); - else if (identifier == "enum") - tokens.emplace_back(TOKEN(Keyword, Enum)); - else if (identifier == "bitfield") - tokens.emplace_back(TOKEN(Keyword, Bitfield)); - else if (identifier == "be") - tokens.emplace_back(TOKEN(Keyword, BigEndian)); - else if (identifier == "le") - tokens.emplace_back(TOKEN(Keyword, LittleEndian)); - else if (identifier == "if") - tokens.emplace_back(TOKEN(Keyword, If)); - else if (identifier == "else") - tokens.emplace_back(TOKEN(Keyword, Else)); - else if (identifier == "false") - tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(false))); - else if (identifier == "true") - tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(true))); - else if (identifier == "parent") - tokens.emplace_back(TOKEN(Keyword, Parent)); - else if (identifier == "this") - tokens.emplace_back(TOKEN(Keyword, This)); - else if (identifier == "while") - tokens.emplace_back(TOKEN(Keyword, While)); - else if (identifier == "for") - tokens.emplace_back(TOKEN(Keyword, For)); - else if (identifier == "fn") - tokens.emplace_back(TOKEN(Keyword, Function)); - else if (identifier == "return") - tokens.emplace_back(TOKEN(Keyword, Return)); - else if (identifier == "namespace") - tokens.emplace_back(TOKEN(Keyword, Namespace)); - else if (identifier == "in") - tokens.emplace_back(TOKEN(Keyword, In)); - else if (identifier == "out") - tokens.emplace_back(TOKEN(Keyword, Out)); - else if (identifier == "break") - tokens.emplace_back(TOKEN(Keyword, Break)); - else if (identifier == "continue") - tokens.emplace_back(TOKEN(Keyword, Continue)); - - // Check for built-in types - else if (identifier == "u8") - tokens.emplace_back(TOKEN(ValueType, Unsigned8Bit)); - else if (identifier == "s8") - tokens.emplace_back(TOKEN(ValueType, Signed8Bit)); - else if (identifier == "u16") - tokens.emplace_back(TOKEN(ValueType, Unsigned16Bit)); - else if (identifier == "s16") - tokens.emplace_back(TOKEN(ValueType, Signed16Bit)); - else if (identifier == "u32") - tokens.emplace_back(TOKEN(ValueType, Unsigned32Bit)); - else if (identifier == "s32") - tokens.emplace_back(TOKEN(ValueType, Signed32Bit)); - else if (identifier == "u64") - tokens.emplace_back(TOKEN(ValueType, Unsigned64Bit)); - else if (identifier == "s64") - tokens.emplace_back(TOKEN(ValueType, Signed64Bit)); - else if (identifier == "u128") - tokens.emplace_back(TOKEN(ValueType, Unsigned128Bit)); - else if (identifier == "s128") - tokens.emplace_back(TOKEN(ValueType, Signed128Bit)); - else if (identifier == "float") - tokens.emplace_back(TOKEN(ValueType, Float)); - else if (identifier == "double") - tokens.emplace_back(TOKEN(ValueType, Double)); - else if (identifier == "char") - tokens.emplace_back(TOKEN(ValueType, Character)); - else if (identifier == "char16") - tokens.emplace_back(TOKEN(ValueType, Character16)); - else if (identifier == "bool") - tokens.emplace_back(TOKEN(ValueType, Boolean)); - else if (identifier == "str") - tokens.emplace_back(TOKEN(ValueType, String)); - else if (identifier == "padding") - tokens.emplace_back(TOKEN(ValueType, Padding)); - else if (identifier == "auto") - tokens.emplace_back(TOKEN(ValueType, Auto)); - - // If it's not a keyword and a builtin type, it has to be an identifier - - else - tokens.emplace_back(VALUE_TOKEN(Identifier, Token::Identifier(identifier))); - - offset += identifier.length(); - } else if (std::isdigit(c)) { - auto integerLength = getIntegerLiteralLength(&code[offset]); - auto integer = lexIntegerLiteralWithSeparator(std::string_view(&code[offset], integerLength)); - - if (!integer.has_value()) - throwLexerError("invalid integer literal", lineNumber); - - - tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(integer.value()))); - offset += integerLength; - } else - throwLexerError("unknown token", lineNumber); - } - - tokens.emplace_back(TOKEN(Separator, EndOfProgram)); - } catch (PatternLanguageError &e) { - this->m_error = e; - - return std::nullopt; - } - - - return tokens; - } -} \ No newline at end of file diff --git a/lib/libimhex/source/pattern_language/log_console.cpp b/lib/libimhex/source/pattern_language/log_console.cpp deleted file mode 100644 index 2fc104438..000000000 --- a/lib/libimhex/source/pattern_language/log_console.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#include - -namespace hex::pl { - - [[noreturn]] void LogConsole::abortEvaluation(const std::string &message, const ASTNode *node) { - if (node == nullptr) - throw PatternLanguageError(0, "Evaluator: " + message); - else - throw PatternLanguageError(node->getLineNumber(), "Evaluator: " + message); - } - -} \ No newline at end of file diff --git a/lib/libimhex/source/pattern_language/parser.cpp b/lib/libimhex/source/pattern_language/parser.cpp deleted file mode 100644 index 49ac9a548..000000000 --- a/lib/libimhex/source/pattern_language/parser.cpp +++ /dev/null @@ -1,1197 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MATCHES(x) (begin() && resetIfFailed(x)) - -// Definition syntax: -// [A] : Either A or no token -// [A|B] : Either A, B or no token -// : Either A or B -// : One or more of A -// A B C : Sequence of tokens A then B then C -// (parseXXXX) : Parsing handled by other function -namespace hex::pl { - - /* Mathematical expressions */ - - // Identifier([(parseMathematicalExpression)|<(parseMathematicalExpression),...>(parseMathematicalExpression)] - std::unique_ptr Parser::parseFunctionCall() { - std::string functionName = parseNamespaceResolution(); - - if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN))) - throwParserError("expected '(' after function name"); - - std::vector> params; - - while (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) { - params.push_back(parseMathematicalExpression()); - - if (MATCHES(sequence(SEPARATOR_COMMA, SEPARATOR_ROUNDBRACKETCLOSE))) - throwParserError("unexpected ',' at end of function parameter list", -1); - else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) - break; - else if (!MATCHES(sequence(SEPARATOR_COMMA))) - throwParserError("missing ',' between parameters", -1); - } - - return create(new ASTNodeFunctionCall(functionName, std::move(params))); - } - - std::unique_ptr Parser::parseStringLiteral() { - return create(new ASTNodeLiteral(getValue(-1))); - } - - std::string Parser::parseNamespaceResolution() { - std::string name; - - while (true) { - name += getValue(-1).get(); - - if (MATCHES(sequence(OPERATOR_SCOPERESOLUTION, IDENTIFIER))) { - name += "::"; - continue; - } else - break; - } - - return name; - } - - std::unique_ptr Parser::parseScopeResolution() { - std::string typeName; - - while (true) { - typeName += getValue(-1).get(); - - if (MATCHES(sequence(OPERATOR_SCOPERESOLUTION, IDENTIFIER))) { - if (peek(OPERATOR_SCOPERESOLUTION, 0) && peek(IDENTIFIER, 1)) { - typeName += "::"; - continue; - } else { - if (!this->m_types.contains(typeName)) - throwParserError(hex::format("cannot access scope of invalid type '{}'", typeName), -1); - - return create(new ASTNodeScopeResolution(this->m_types[typeName]->clone(), getValue(-1).get())); - } - } else - break; - } - - throwParserError("failed to parse scope resolution. Expected 'TypeName::Identifier'"); - } - - std::unique_ptr Parser::parseRValue() { - ASTNodeRValue::Path path; - return this->parseRValue(path); - } - - // - std::unique_ptr Parser::parseRValue(ASTNodeRValue::Path &path) { - if (peek(IDENTIFIER, -1)) - path.push_back(getValue(-1).get()); - else if (peek(KEYWORD_PARENT, -1)) - path.emplace_back("parent"); - else if (peek(KEYWORD_THIS, -1)) - path.emplace_back("this"); - - if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN))) { - path.push_back(parseMathematicalExpression()); - if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) - throwParserError("expected closing ']' at end of array indexing"); - } - - if (MATCHES(sequence(SEPARATOR_DOT))) { - if (MATCHES(oneOf(IDENTIFIER, KEYWORD_PARENT))) - return this->parseRValue(path); - else - throwParserError("expected member name or 'parent' keyword", -1); - } else - return create(new ASTNodeRValue(std::move(path))); - } - - // - std::unique_ptr Parser::parseFactor() { - if (MATCHES(sequence(INTEGER))) - return create(new ASTNodeLiteral(getValue(-1))); - else if (peek(OPERATOR_PLUS) || peek(OPERATOR_MINUS) || peek(OPERATOR_BITNOT) || peek(OPERATOR_BOOLNOT)) - return this->parseMathematicalExpression(); - else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN))) { - auto node = this->parseMathematicalExpression(); - if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) - throwParserError("expected closing parenthesis"); - - return node; - } else if (MATCHES(sequence(IDENTIFIER))) { - auto originalPos = this->m_curr; - parseNamespaceResolution(); - bool isFunction = peek(SEPARATOR_ROUNDBRACKETOPEN); - this->m_curr = originalPos; - - - if (isFunction) { - return this->parseFunctionCall(); - } else if (peek(OPERATOR_SCOPERESOLUTION, 0)) { - return this->parseScopeResolution(); - } else { - return this->parseRValue(); - } - } else if (MATCHES(oneOf(KEYWORD_PARENT, KEYWORD_THIS))) { - return this->parseRValue(); - } else if (MATCHES(sequence(OPERATOR_DOLLAR))) { - return create(new ASTNodeRValue(hex::moveToVector("$"))); - } else if (MATCHES(oneOf(OPERATOR_ADDRESSOF, OPERATOR_SIZEOF) && sequence(SEPARATOR_ROUNDBRACKETOPEN))) { - auto op = getValue(-2); - - std::unique_ptr result; - - if (MATCHES(oneOf(IDENTIFIER, KEYWORD_PARENT, KEYWORD_THIS))) { - result = create(new ASTNodeTypeOperator(op, this->parseRValue())); - } else if (MATCHES(sequence(VALUETYPE_ANY))) { - auto type = getValue(-1); - - result = create(new ASTNodeLiteral(u128(Token::getTypeSize(type)))); - } else { - throwParserError("expected rvalue identifier or built-in type"); - } - - if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) - throwParserError("expected closing parenthesis"); - - return result; - } else - throwParserError("expected value or parenthesis"); - } - - std::unique_ptr Parser::parseCastExpression() { - if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY)) { - auto type = parseType(true); - auto builtinType = dynamic_cast(type->getType().get()); - - if (builtinType == nullptr) - throwParserError("invalid type used for pointer size", -1); - - if (!peek(SEPARATOR_ROUNDBRACKETOPEN)) - throwParserError("expected '(' before cast expression", -1); - - auto node = parseFactor(); - - return create(new ASTNodeCast(std::move(node), std::move(type))); - } else return parseFactor(); - } - - // <+|-|!|~> (parseFactor) - std::unique_ptr Parser::parseUnaryExpression() { - if (MATCHES(oneOf(OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_BOOLNOT, OPERATOR_BITNOT))) { - auto op = getValue(-1); - - return create(new ASTNodeMathematicalExpression(create(new ASTNodeLiteral(0)), this->parseCastExpression(), op)); - } else if (MATCHES(sequence(STRING))) { - return this->parseStringLiteral(); - } - - return this->parseCastExpression(); - } - - // (parseUnaryExpression) <*|/|%> (parseUnaryExpression) - std::unique_ptr Parser::parseMultiplicativeExpression() { - auto node = this->parseUnaryExpression(); - - while (MATCHES(oneOf(OPERATOR_STAR, OPERATOR_SLASH, OPERATOR_PERCENT))) { - auto op = getValue(-1); - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseUnaryExpression(), op)); - } - - return node; - } - - // (parseMultiplicativeExpression) <+|-> (parseMultiplicativeExpression) - std::unique_ptr Parser::parseAdditiveExpression() { - auto node = this->parseMultiplicativeExpression(); - - while (MATCHES(variant(OPERATOR_PLUS, OPERATOR_MINUS))) { - auto op = getValue(-1); - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseMultiplicativeExpression(), op)); - } - - return node; - } - - // (parseAdditiveExpression) < >>|<< > (parseAdditiveExpression) - std::unique_ptr Parser::parseShiftExpression() { - auto node = this->parseAdditiveExpression(); - - while (MATCHES(variant(OPERATOR_SHIFTLEFT, OPERATOR_SHIFTRIGHT))) { - auto op = getValue(-1); - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseAdditiveExpression(), op)); - } - - return node; - } - - // (parseShiftExpression) & (parseShiftExpression) - std::unique_ptr Parser::parseBinaryAndExpression() { - auto node = this->parseShiftExpression(); - - while (MATCHES(sequence(OPERATOR_BITAND))) { - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseShiftExpression(), Token::Operator::BitAnd)); - } - - return node; - } - - // (parseBinaryAndExpression) ^ (parseBinaryAndExpression) - std::unique_ptr Parser::parseBinaryXorExpression() { - auto node = this->parseBinaryAndExpression(); - - while (MATCHES(sequence(OPERATOR_BITXOR))) { - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseBinaryAndExpression(), Token::Operator::BitXor)); - } - - return node; - } - - // (parseBinaryXorExpression) | (parseBinaryXorExpression) - std::unique_ptr Parser::parseBinaryOrExpression() { - auto node = this->parseBinaryXorExpression(); - - while (MATCHES(sequence(OPERATOR_BITOR))) { - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseBinaryXorExpression(), Token::Operator::BitOr)); - } - - return node; - } - - // (parseBinaryOrExpression) < >=|<=|>|< > (parseBinaryOrExpression) - std::unique_ptr Parser::parseRelationExpression() { - auto node = this->parseBinaryOrExpression(); - - while (MATCHES(sequence(OPERATOR_BOOLGREATERTHAN) || sequence(OPERATOR_BOOLLESSTHAN) || sequence(OPERATOR_BOOLGREATERTHANOREQUALS) || sequence(OPERATOR_BOOLLESSTHANOREQUALS))) { - auto op = getValue(-1); - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseBinaryOrExpression(), op)); - } - - return node; - } - - // (parseRelationExpression) <==|!=> (parseRelationExpression) - std::unique_ptr Parser::parseEqualityExpression() { - auto node = this->parseRelationExpression(); - - while (MATCHES(sequence(OPERATOR_BOOLEQUALS) || sequence(OPERATOR_BOOLNOTEQUALS))) { - auto op = getValue(-1); - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseRelationExpression(), op)); - } - - return node; - } - - // (parseEqualityExpression) && (parseEqualityExpression) - std::unique_ptr Parser::parseBooleanAnd() { - auto node = this->parseEqualityExpression(); - - while (MATCHES(sequence(OPERATOR_BOOLAND))) { - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseEqualityExpression(), Token::Operator::BoolAnd)); - } - - return node; - } - - // (parseBooleanAnd) ^^ (parseBooleanAnd) - std::unique_ptr Parser::parseBooleanXor() { - auto node = this->parseBooleanAnd(); - - while (MATCHES(sequence(OPERATOR_BOOLXOR))) { - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseBooleanAnd(), Token::Operator::BoolXor)); - } - - return node; - } - - // (parseBooleanXor) || (parseBooleanXor) - std::unique_ptr Parser::parseBooleanOr() { - auto node = this->parseBooleanXor(); - - while (MATCHES(sequence(OPERATOR_BOOLOR))) { - node = create(new ASTNodeMathematicalExpression(std::move(node), this->parseBooleanXor(), Token::Operator::BoolOr)); - } - - return node; - } - - // (parseBooleanOr) ? (parseBooleanOr) : (parseBooleanOr) - std::unique_ptr Parser::parseTernaryConditional() { - auto node = this->parseBooleanOr(); - - while (MATCHES(sequence(OPERATOR_TERNARYCONDITIONAL))) { - auto second = this->parseBooleanOr(); - - if (!MATCHES(sequence(OPERATOR_INHERIT))) - throwParserError("expected ':' in ternary expression"); - - auto third = this->parseBooleanOr(); - node = create(new ASTNodeTernaryExpression(std::move(node), std::move(second), std::move(third), Token::Operator::TernaryConditional)); - } - - return node; - } - - // (parseTernaryConditional) - std::unique_ptr Parser::parseMathematicalExpression() { - return this->parseTernaryConditional(); - } - - // [[ ]] - void Parser::parseAttribute(Attributable *currNode) { - if (currNode == nullptr) - throwParserError("tried to apply attribute to invalid statement"); - - do { - if (!MATCHES(sequence(IDENTIFIER))) - throwParserError("expected attribute expression"); - - auto attribute = getValue(-1).get(); - - if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN, STRING, SEPARATOR_ROUNDBRACKETCLOSE))) { - auto value = getValue(-2); - auto string = std::get_if(&value); - - if (string == nullptr) - throwParserError("expected string attribute argument"); - - currNode->addAttribute(create(new ASTNodeAttribute(attribute, *string))); - } else - currNode->addAttribute(create(new ASTNodeAttribute(attribute))); - - } while (MATCHES(sequence(SEPARATOR_COMMA))); - - if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE, SEPARATOR_SQUAREBRACKETCLOSE))) - throwParserError("unfinished attribute. Expected ']]'"); - } - - /* Functions */ - - std::unique_ptr Parser::parseFunctionDefinition() { - const auto &functionName = getValue(-2).get(); - std::vector>> params; - std::optional parameterPack; - - // Parse parameter list - bool hasParams = !peek(SEPARATOR_ROUNDBRACKETCLOSE); - u32 unnamedParamCount = 0; - std::vector> defaultParameters; - - while (hasParams) { - if (MATCHES(sequence(VALUETYPE_AUTO, SEPARATOR_DOT, SEPARATOR_DOT, SEPARATOR_DOT, IDENTIFIER))) { - parameterPack = getValue(-1).get(); - - if (MATCHES(sequence(SEPARATOR_COMMA))) - throwParserError("parameter pack can only appear at end of parameter list"); - - break; - } else { - auto type = parseType(true); - - if (MATCHES(sequence(IDENTIFIER))) - params.emplace_back(getValue(-1).get(), std::move(type)); - else { - params.emplace_back(std::to_string(unnamedParamCount), std::move(type)); - unnamedParamCount++; - } - - if (MATCHES(sequence(OPERATOR_ASSIGNMENT))) { - // Parse default parameters - defaultParameters.push_back(parseMathematicalExpression()); - } else { - if (!defaultParameters.empty()) - throwParserError(hex::format("default argument missing for parameter {}", params.size())); - } - - if (!MATCHES(sequence(SEPARATOR_COMMA))) { - break; - } - } - } - - if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) - throwParserError("expected closing ')' after parameter list"); - - if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) - throwParserError("expected opening '{' after function definition"); - - - // Parse function body - std::vector> body; - - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - body.push_back(this->parseFunctionStatement()); - } - - return create(new ASTNodeFunctionDefinition(getNamespacePrefixedName(functionName), std::move(params), std::move(body), parameterPack, std::move(defaultParameters))); - } - - std::unique_ptr Parser::parseFunctionVariableDecl() { - std::unique_ptr statement; - auto type = parseType(true); - - if (MATCHES(sequence(IDENTIFIER))) { - auto identifier = getValue(-1).get(); - statement = parseMemberVariable(std::move(type)); - - if (MATCHES(sequence(OPERATOR_ASSIGNMENT))) { - auto expression = parseMathematicalExpression(); - - std::vector> compoundStatement; - { - compoundStatement.push_back(std::move(statement)); - compoundStatement.push_back(create(new ASTNodeAssignment(identifier, std::move(expression)))); - } - - statement = create(new ASTNodeCompoundStatement(std::move(compoundStatement))); - } - } else - throwParserError("invalid variable declaration"); - - return statement; - } - - std::unique_ptr Parser::parseFunctionStatement() { - bool needsSemicolon = true; - std::unique_ptr statement; - - if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) - statement = parseFunctionVariableAssignment(getValue(-2).get()); - else if (MATCHES(sequence(OPERATOR_DOLLAR, OPERATOR_ASSIGNMENT))) - statement = parseFunctionVariableAssignment("$"); - else if (MATCHES(oneOf(IDENTIFIER) && oneOf(OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_STAR, OPERATOR_SLASH, OPERATOR_PERCENT, OPERATOR_SHIFTLEFT, OPERATOR_SHIFTRIGHT, OPERATOR_BITOR, OPERATOR_BITAND, OPERATOR_BITXOR) && sequence(OPERATOR_ASSIGNMENT))) - statement = parseFunctionVariableCompoundAssignment(getValue(-3).get()); - 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))) - statement = parseFunctionVariableCompoundAssignment("$"); - else if (MATCHES(oneOf(KEYWORD_RETURN, KEYWORD_BREAK, KEYWORD_CONTINUE))) - statement = parseFunctionControlFlowStatement(); - else if (MATCHES(sequence(KEYWORD_IF, SEPARATOR_ROUNDBRACKETOPEN))) { - statement = parseFunctionConditional(); - needsSemicolon = false; - } else if (MATCHES(sequence(KEYWORD_WHILE, SEPARATOR_ROUNDBRACKETOPEN))) { - statement = parseFunctionWhileLoop(); - needsSemicolon = false; - } else if (MATCHES(sequence(KEYWORD_FOR, SEPARATOR_ROUNDBRACKETOPEN))) { - statement = parseFunctionForLoop(); - needsSemicolon = false; - } else if (MATCHES(sequence(IDENTIFIER))) { - auto originalPos = this->m_curr; - parseNamespaceResolution(); - bool isFunction = peek(SEPARATOR_ROUNDBRACKETOPEN); - - if (isFunction) { - this->m_curr = originalPos; - statement = parseFunctionCall(); - } else { - this->m_curr = originalPos - 1; - statement = parseFunctionVariableDecl(); - } - } else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY)) { - statement = parseFunctionVariableDecl(); - } else - throwParserError("invalid sequence", 0); - - if (needsSemicolon && !MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - throwParserError("missing ';' at end of expression", -1); - - // Consume superfluous semicolons - while (needsSemicolon && MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - ; - - return statement; - } - - std::unique_ptr Parser::parseFunctionVariableAssignment(const std::string &lvalue) { - auto rvalue = this->parseMathematicalExpression(); - - return create(new ASTNodeAssignment(lvalue, std::move(rvalue))); - } - - std::unique_ptr Parser::parseFunctionVariableCompoundAssignment(const std::string &lvalue) { - const auto &op = getValue(-2); - - auto rvalue = this->parseMathematicalExpression(); - - return create(new ASTNodeAssignment(lvalue, create(new ASTNodeMathematicalExpression(create(new ASTNodeRValue(hex::moveToVector(lvalue))), std::move(rvalue), op)))); - } - - std::unique_ptr Parser::parseFunctionControlFlowStatement() { - ControlFlowStatement type; - if (peek(KEYWORD_RETURN, -1)) - type = ControlFlowStatement::Return; - else if (peek(KEYWORD_BREAK, -1)) - type = ControlFlowStatement::Break; - else if (peek(KEYWORD_CONTINUE, -1)) - type = ControlFlowStatement::Continue; - else - throwParserError("invalid control flow statement. Expected 'return', 'break' or 'continue'"); - - if (peek(SEPARATOR_ENDOFEXPRESSION)) - return create(new ASTNodeControlFlowStatement(type, nullptr)); - else - return create(new ASTNodeControlFlowStatement(type, this->parseMathematicalExpression())); - } - - std::vector> Parser::parseStatementBody() { - std::vector> body; - - if (MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) { - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - body.push_back(parseFunctionStatement()); - } - } else { - body.push_back(parseFunctionStatement()); - } - - return body; - } - - std::unique_ptr Parser::parseFunctionConditional() { - auto condition = parseMathematicalExpression(); - std::vector> trueBody, falseBody; - - if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) - throwParserError("expected closing ')' after statement head"); - - trueBody = parseStatementBody(); - - if (MATCHES(sequence(KEYWORD_ELSE))) - falseBody = parseStatementBody(); - - return create(new ASTNodeConditionalStatement(std::move(condition), std::move(trueBody), std::move(falseBody))); - } - - std::unique_ptr Parser::parseFunctionWhileLoop() { - auto condition = parseMathematicalExpression(); - std::vector> body; - - if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) - throwParserError("expected closing ')' after statement head"); - - body = parseStatementBody(); - - return create(new ASTNodeWhileStatement(std::move(condition), std::move(body))); - } - - std::unique_ptr Parser::parseFunctionForLoop() { - auto variable = parseFunctionVariableDecl(); - - if (!MATCHES(sequence(SEPARATOR_COMMA))) - throwParserError("expected ',' after for loop variable declaration"); - - auto condition = parseMathematicalExpression(); - - if (!MATCHES(sequence(SEPARATOR_COMMA))) - throwParserError("expected ',' after for loop condition"); - - std::unique_ptr postExpression = nullptr; - if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) - postExpression = parseFunctionVariableAssignment(getValue(-2).get()); - else if (MATCHES(sequence(OPERATOR_DOLLAR, OPERATOR_ASSIGNMENT))) - postExpression = parseFunctionVariableAssignment("$"); - else if (MATCHES(oneOf(IDENTIFIER) && oneOf(OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_STAR, OPERATOR_SLASH, OPERATOR_PERCENT, OPERATOR_SHIFTLEFT, OPERATOR_SHIFTRIGHT, OPERATOR_BITOR, OPERATOR_BITAND, OPERATOR_BITXOR) && sequence(OPERATOR_ASSIGNMENT))) - postExpression = parseFunctionVariableCompoundAssignment(getValue(-3).get()); - 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))) - postExpression = parseFunctionVariableCompoundAssignment("$"); - else - throwParserError("expected variable assignment in for loop post expression"); - - std::vector> body; - - - if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) - throwParserError("expected closing ')' after statement head"); - - body = parseStatementBody(); - - std::vector> compoundStatement; - { - compoundStatement.push_back(std::move(variable)); - compoundStatement.push_back(create(new ASTNodeWhileStatement(std::move(condition), std::move(body), std::move(postExpression)))); - } - - return create(new ASTNodeCompoundStatement(std::move(compoundStatement), true)); - } - - /* Control flow */ - - // if ((parseMathematicalExpression)) { (parseMember) } - std::unique_ptr Parser::parseConditional() { - auto condition = parseMathematicalExpression(); - std::vector> trueBody, falseBody; - - if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE, SEPARATOR_CURLYBRACKETOPEN))) { - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - trueBody.push_back(parseMember()); - } - } else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) { - trueBody.push_back(parseMember()); - } else - throwParserError("expected body of conditional statement"); - - if (MATCHES(sequence(KEYWORD_ELSE, SEPARATOR_CURLYBRACKETOPEN))) { - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - falseBody.push_back(parseMember()); - } - } else if (MATCHES(sequence(KEYWORD_ELSE))) { - falseBody.push_back(parseMember()); - } - - return create(new ASTNodeConditionalStatement(std::move(condition), std::move(trueBody), std::move(falseBody))); - } - - // while ((parseMathematicalExpression)) - std::unique_ptr Parser::parseWhileStatement() { - auto condition = parseMathematicalExpression(); - - if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) - throwParserError("expected closing ')' after while head"); - - return create(new ASTNodeWhileStatement(std::move(condition), {})); - } - - /* Type declarations */ - - // [be|le] - std::unique_ptr Parser::parseType(bool allowFunctionTypes) { - std::optional endian; - - if (MATCHES(sequence(KEYWORD_LE))) - endian = std::endian::little; - else if (MATCHES(sequence(KEYWORD_BE))) - endian = std::endian::big; - - if (MATCHES(sequence(IDENTIFIER))) { // Custom type - std::string typeName = parseNamespaceResolution(); - - if (this->m_types.contains(typeName)) - return create(new ASTNodeTypeDecl({}, this->m_types[typeName], endian)); - else if (this->m_types.contains(getNamespacePrefixedName(typeName))) - return create(new ASTNodeTypeDecl({}, this->m_types[getNamespacePrefixedName(typeName)], endian)); - else - throwParserError(hex::format("unknown type '{}'", typeName)); - } else if (MATCHES(sequence(VALUETYPE_ANY))) { // Builtin type - auto type = getValue(-1); - if (!allowFunctionTypes) { - if (type == Token::ValueType::String) - throwParserError("cannot use 'str' in this context. Use a character array instead"); - else if (type == Token::ValueType::Auto) - throwParserError("cannot use 'auto' in this context"); - } - - return create(new ASTNodeTypeDecl({}, create(new ASTNodeBuiltinType(type)), endian)); - } else throwParserError("failed to parse type. Expected identifier or builtin type"); - } - - // using Identifier = (parseType) - std::shared_ptr Parser::parseUsingDeclaration() { - auto name = getNamespacePrefixedName(getValue(-2).get()); - - auto type = parseType(); - - auto endian = type->getEndian(); - return addType(name, std::move(type), endian); - } - - // padding[(parseMathematicalExpression)] - std::unique_ptr Parser::parsePadding() { - auto size = parseMathematicalExpression(); - - if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) - throwParserError("expected closing ']' at end of array declaration", -1); - - return create(new ASTNodeArrayVariableDecl({}, create(new ASTNodeTypeDecl({}, create(new ASTNodeBuiltinType(Token::ValueType::Padding)))), std::move(size))); - } - - // (parseType) Identifier - std::unique_ptr Parser::parseMemberVariable(const std::shared_ptr &type) { - if (peek(SEPARATOR_COMMA)) { - - std::vector> variables; - - do { - variables.push_back(create(new ASTNodeVariableDecl(getValue(-1).get(), type))); - } while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER))); - - return create(new ASTNodeMultiVariableDecl(std::move(variables))); - } else if (MATCHES(sequence(OPERATOR_AT))) - return create(new ASTNodeVariableDecl(getValue(-2).get(), type, parseMathematicalExpression())); - else - return create(new ASTNodeVariableDecl(getValue(-1).get(), type)); - } - - // (parseType) Identifier[(parseMathematicalExpression)] - std::unique_ptr Parser::parseMemberArrayVariable(const std::shared_ptr &type) { - auto name = getValue(-2).get(); - - std::unique_ptr size; - - if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) { - if (MATCHES(sequence(KEYWORD_WHILE, SEPARATOR_ROUNDBRACKETOPEN))) - size = parseWhileStatement(); - else - size = parseMathematicalExpression(); - - if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) - throwParserError("expected closing ']' at end of array declaration", -1); - } - - if (MATCHES(sequence(OPERATOR_AT))) - return create(new ASTNodeArrayVariableDecl(name, type, std::move(size), parseMathematicalExpression())); - else - return create(new ASTNodeArrayVariableDecl(name, type, std::move(size))); - } - - // (parseType) *Identifier : (parseType) - std::unique_ptr Parser::parseMemberPointerVariable(const std::shared_ptr &type) { - auto name = getValue(-2).get(); - - auto sizeType = parseType(); - - { - auto builtinType = dynamic_cast(sizeType->getType().get()); - - if (builtinType == nullptr || !Token::isUnsigned(builtinType->getType())) - throwParserError("invalid type used for pointer size", -1); - } - - if (MATCHES(sequence(OPERATOR_AT))) - return create(new ASTNodePointerVariableDecl(name, type, std::move(sizeType), parseMathematicalExpression())); - else - return create(new ASTNodePointerVariableDecl(name, type, std::move(sizeType))); - } - - // [(parsePadding)|(parseMemberVariable)|(parseMemberArrayVariable)|(parseMemberPointerVariable)] - std::unique_ptr Parser::parseMember() { - std::unique_ptr member; - - if (MATCHES(sequence(OPERATOR_DOLLAR, OPERATOR_ASSIGNMENT))) - member = parseFunctionVariableAssignment("$"); - else if (MATCHES(sequence(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("$"); - else if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) - member = parseFunctionVariableAssignment(getValue(-2).get()); - else if (MATCHES(sequence(IDENTIFIER) && 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(getValue(-3).get()); - else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY) || peek(IDENTIFIER)) { - // Some kind of variable definition - - bool isFunction = false; - - if (peek(IDENTIFIER)) { - auto originalPos = this->m_curr; - this->m_curr++; - parseNamespaceResolution(); - isFunction = peek(SEPARATOR_ROUNDBRACKETOPEN); - this->m_curr = originalPos; - - if (isFunction) { - this->m_curr++; - member = parseFunctionCall(); - } - } - - - if (!isFunction) { - auto type = parseType(); - - if (MATCHES(sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN) && sequence(SEPARATOR_SQUAREBRACKETOPEN))) - member = parseMemberArrayVariable(std::move(type)); - else if (MATCHES(sequence(IDENTIFIER))) - member = parseMemberVariable(std::move(type)); - else if (MATCHES(sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) - member = parseMemberPointerVariable(std::move(type)); - else - throwParserError("invalid variable declaration"); - } - } else if (MATCHES(sequence(VALUETYPE_PADDING, SEPARATOR_SQUAREBRACKETOPEN))) - member = parsePadding(); - else if (MATCHES(sequence(KEYWORD_IF, SEPARATOR_ROUNDBRACKETOPEN))) - return parseConditional(); - else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) - throwParserError("unexpected end of program", -2); - else if (MATCHES(sequence(KEYWORD_BREAK))) - member = create(new ASTNodeControlFlowStatement(ControlFlowStatement::Break, nullptr)); - else if (MATCHES(sequence(KEYWORD_CONTINUE))) - member = create(new ASTNodeControlFlowStatement(ControlFlowStatement::Continue, nullptr)); - else - throwParserError("invalid struct member", 0); - - if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN))) - parseAttribute(dynamic_cast(member.get())); - - if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - throwParserError("missing ';' at end of expression", -1); - - // Consume superfluous semicolons - while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - ; - - return member; - } - - // struct Identifier { <(parseMember)...> } - std::shared_ptr Parser::parseStruct() { - const auto &typeName = getValue(-1).get(); - - auto typeDecl = addType(typeName, create(new ASTNodeStruct())); - auto structNode = static_cast(typeDecl->getType().get()); - - if (MATCHES(sequence(OPERATOR_INHERIT, IDENTIFIER))) { - // Inheritance - - do { - auto inheritedTypeName = getValue(-1).get(); - if (!this->m_types.contains(inheritedTypeName)) - throwParserError(hex::format("cannot inherit from unknown type '{}'", inheritedTypeName), -1); - - structNode->addInheritance(this->m_types[inheritedTypeName]->clone()); - } while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER))); - - } else if (MATCHES(sequence(OPERATOR_INHERIT, VALUETYPE_ANY))) { - throwParserError("cannot inherit from builtin type"); - } - - if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) - throwParserError("expected '{' after struct definition", -1); - - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - structNode->addMember(parseMember()); - } - - return typeDecl; - } - - // union Identifier { <(parseMember)...> } - std::shared_ptr Parser::parseUnion() { - const auto &typeName = getValue(-2).get(); - - auto typeDecl = addType(typeName, create(new ASTNodeUnion())); - auto unionNode = static_cast(typeDecl->getType().get()); - - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - unionNode->addMember(parseMember()); - } - - return typeDecl; - } - - // enum Identifier : (parseType) { <...> } - std::shared_ptr Parser::parseEnum() { - auto typeName = getValue(-2).get(); - - auto underlyingType = parseType(); - if (underlyingType->getEndian().has_value()) throwParserError("underlying type may not have an endian specification", -2); - - auto typeDecl = addType(typeName, create(new ASTNodeEnum(std::move(underlyingType)))); - auto enumNode = static_cast(typeDecl->getType().get()); - - if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) - throwParserError("expected '{' after enum definition", -1); - - std::unique_ptr lastEntry; - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) { - auto name = getValue(-2).get(); - auto value = parseMathematicalExpression(); - - lastEntry = value->clone(); - enumNode->addEntry(name, std::move(value)); - } else if (MATCHES(sequence(IDENTIFIER))) { - std::unique_ptr valueExpr; - auto name = getValue(-1).get(); - if (enumNode->getEntries().empty()) - valueExpr = create(new ASTNodeLiteral(u128(0))); - else - valueExpr = create(new ASTNodeMathematicalExpression(lastEntry->clone(), create(new ASTNodeLiteral(u128(1))), Token::Operator::Plus)); - - lastEntry = valueExpr->clone(); - enumNode->addEntry(name, std::move(valueExpr)); - } else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) - throwParserError("unexpected end of program", -2); - else - throwParserError("invalid enum entry", -1); - - if (!MATCHES(sequence(SEPARATOR_COMMA))) { - if (MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) - break; - else - throwParserError("missing ',' between enum entries", -1); - } - } - - return typeDecl; - } - - // bitfield Identifier { } - std::shared_ptr Parser::parseBitfield() { - std::string typeName = getValue(-2).get(); - - auto typeDecl = addType(typeName, create(new ASTNodeBitfield())); - auto bitfieldNode = static_cast(typeDecl->getType().get()); - - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - if (MATCHES(sequence(IDENTIFIER, OPERATOR_INHERIT))) { - auto name = getValue(-2).get(); - bitfieldNode->addEntry(name, parseMathematicalExpression()); - } else if (MATCHES(sequence(VALUETYPE_PADDING, OPERATOR_INHERIT))) { - bitfieldNode->addEntry("padding", parseMathematicalExpression()); - } else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) - throwParserError("unexpected end of program", -2); - else - throwParserError("invalid bitfield member", 0); - - if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - throwParserError("missing ';' at end of expression", -1); - - // Consume superfluous semicolons - while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - ; - } - - return typeDecl; - } - - // using Identifier; - void Parser::parseForwardDeclaration() { - std::string typeName = getNamespacePrefixedName(getValue(-1).get()); - - if (this->m_types.contains(typeName)) - return; - - this->m_types.insert({ typeName, create(new ASTNodeTypeDecl(typeName) )}); - } - - // (parseType) Identifier @ Integer - std::unique_ptr Parser::parseVariablePlacement(const std::shared_ptr &type) { - bool inVariable = false; - bool outVariable = false; - - auto name = getValue(-1).get(); - - std::unique_ptr placementOffset; - if (MATCHES(sequence(OPERATOR_AT))) { - placementOffset = parseMathematicalExpression(); - } else if (MATCHES(sequence(KEYWORD_IN))) { - inVariable = true; - } else if (MATCHES(sequence(KEYWORD_OUT))) { - outVariable = true; - } - - return create(new ASTNodeVariableDecl(name, type, std::move(placementOffset), inVariable, outVariable)); - } - - // (parseType) Identifier[[(parseMathematicalExpression)]] @ Integer - std::unique_ptr Parser::parseArrayVariablePlacement(const std::shared_ptr &type) { - auto name = getValue(-2).get(); - - std::unique_ptr size; - - if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) { - if (MATCHES(sequence(KEYWORD_WHILE, SEPARATOR_ROUNDBRACKETOPEN))) - size = parseWhileStatement(); - else - size = parseMathematicalExpression(); - - if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) - throwParserError("expected closing ']' at end of array declaration", -1); - } - - if (!MATCHES(sequence(OPERATOR_AT))) - throwParserError("expected placement instruction", -1); - - auto placementOffset = parseMathematicalExpression(); - - return create(new ASTNodeArrayVariableDecl(name, type, std::move(size), std::move(placementOffset))); - } - - // (parseType) *Identifier : (parseType) @ Integer - std::unique_ptr Parser::parsePointerVariablePlacement(const std::shared_ptr &type) { - auto name = getValue(-2).get(); - - auto sizeType = parseType(); - - { - auto builtinType = dynamic_cast(sizeType->getType().get()); - - if (builtinType == nullptr || !Token::isUnsigned(builtinType->getType())) - throwParserError("invalid type used for pointer size", -1); - } - - if (!MATCHES(sequence(OPERATOR_AT))) - throwParserError("expected placement instruction", -1); - - auto placementOffset = parseMathematicalExpression(); - - return create(new ASTNodePointerVariableDecl(name, type, std::move(sizeType), std::move(placementOffset))); - } - - std::vector> Parser::parseNamespace() { - std::vector> statements; - - if (!MATCHES(sequence(IDENTIFIER))) - throwParserError("expected namespace identifier"); - - this->m_currNamespace.push_back(this->m_currNamespace.back()); - - while (true) { - this->m_currNamespace.back().push_back(getValue(-1).get()); - - if (MATCHES(sequence(OPERATOR_SCOPERESOLUTION, IDENTIFIER))) - continue; - else - break; - } - - if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) - throwParserError("expected '{' at start of namespace"); - - while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - auto newStatements = parseStatements(); - std::move(newStatements.begin(), newStatements.end(), std::back_inserter(statements)); - } - - this->m_currNamespace.pop_back(); - - return statements; - } - - std::unique_ptr Parser::parsePlacement() { - auto type = parseType(); - - if (MATCHES(sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) - return parseArrayVariablePlacement(std::move(type)); - else if (MATCHES(sequence(IDENTIFIER))) - return parseVariablePlacement(std::move(type)); - else if (MATCHES(sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) - return parsePointerVariablePlacement(std::move(type)); - else throwParserError("invalid sequence", 0); - } - - /* Program */ - - // <(parseUsingDeclaration)|(parseVariablePlacement)|(parseStruct)> - std::vector> Parser::parseStatements() { - std::shared_ptr statement; - - if (MATCHES(sequence(KEYWORD_USING, IDENTIFIER, OPERATOR_ASSIGNMENT))) - statement = parseUsingDeclaration(); - else if (MATCHES(sequence(KEYWORD_USING, IDENTIFIER))) - parseForwardDeclaration(); - else if (peek(IDENTIFIER)) { - auto originalPos = this->m_curr; - this->m_curr++; - parseNamespaceResolution(); - bool isFunction = peek(SEPARATOR_ROUNDBRACKETOPEN); - this->m_curr = originalPos; - - if (isFunction) { - this->m_curr++; - statement = parseFunctionCall(); - } else - statement = parsePlacement(); - } else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY)) - statement = parsePlacement(); - else if (MATCHES(sequence(KEYWORD_STRUCT, IDENTIFIER))) - statement = parseStruct(); - else if (MATCHES(sequence(KEYWORD_UNION, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN))) - statement = parseUnion(); - else if (MATCHES(sequence(KEYWORD_ENUM, IDENTIFIER, OPERATOR_INHERIT))) - statement = parseEnum(); - else if (MATCHES(sequence(KEYWORD_BITFIELD, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN))) - statement = parseBitfield(); - else if (MATCHES(sequence(KEYWORD_FUNCTION, IDENTIFIER, SEPARATOR_ROUNDBRACKETOPEN))) - statement = parseFunctionDefinition(); - else if (MATCHES(sequence(KEYWORD_NAMESPACE))) - return parseNamespace(); - else throwParserError("invalid sequence", 0); - - if (statement && MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN))) - parseAttribute(dynamic_cast(statement.get())); - - if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - throwParserError("missing ';' at end of expression", -1); - - // Consume superfluous semicolons - while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - ; - - if (!statement) - return { }; - - return hex::moveToVector(std::move(statement)); - } - - std::shared_ptr Parser::addType(const std::string &name, std::unique_ptr &&node, std::optional endian) { - auto typeName = getNamespacePrefixedName(name); - - if (this->m_types.contains(typeName) && this->m_types.at(typeName)->isForwardDeclared()) { - this->m_types.at(typeName)->setType(std::move(node)); - - return this->m_types.at(typeName); - } else { - if (this->m_types.contains(typeName)) - throwParserError(hex::format("redefinition of type '{}'", typeName)); - - std::shared_ptr typeDecl = create(new ASTNodeTypeDecl(typeName, std::move(node), endian)); - this->m_types.insert({ typeName, typeDecl }); - - return typeDecl; - } - } - - // <(parseNamespace)...> EndOfProgram - std::optional>> Parser::parse(const std::vector &tokens) { - this->m_curr = tokens.begin(); - - this->m_types.clear(); - - this->m_currNamespace.clear(); - this->m_currNamespace.emplace_back(); - - try { - auto program = parseTillToken(SEPARATOR_ENDOFPROGRAM); - - if (program.empty() || this->m_curr != tokens.end()) - throwParserError("program is empty!", -1); - - return program; - } catch (PatternLanguageError &e) { - this->m_error = e; - - return std::nullopt; - } - } - -} \ No newline at end of file diff --git a/lib/libimhex/source/pattern_language/pattern_language.cpp b/lib/libimhex/source/pattern_language/pattern_language.cpp deleted file mode 100644 index 1aab9b944..000000000 --- a/lib/libimhex/source/pattern_language/pattern_language.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace hex::pl { - - class Pattern; - - PatternLanguage::PatternLanguage() { - this->m_preprocessor = new Preprocessor(); - this->m_lexer = new Lexer(); - this->m_parser = new Parser(); - this->m_validator = new Validator(); - this->m_evaluator = new Evaluator(); - - this->m_preprocessor->addDefaultPragmaHandlers(); - - this->m_preprocessor->addPragmaHandler("endian", [this](std::string value) { - if (value == "big") { - this->m_evaluator->setDefaultEndian(std::endian::big); - return true; - } else if (value == "little") { - this->m_evaluator->setDefaultEndian(std::endian::little); - return true; - } else if (value == "native") { - this->m_evaluator->setDefaultEndian(std::endian::native); - return true; - } else - return false; - }); - - this->m_preprocessor->addPragmaHandler("eval_depth", [this](std::string value) { - auto limit = strtol(value.c_str(), nullptr, 0); - - if (limit <= 0) - return false; - - this->m_evaluator->setEvaluationDepth(limit); - return true; - }); - - this->m_preprocessor->addPragmaHandler("array_limit", [this](const std::string &value) { - auto limit = strtol(value.c_str(), nullptr, 0); - - if (limit <= 0) - return false; - - this->m_evaluator->setArrayLimit(limit); - return true; - }); - - this->m_preprocessor->addPragmaHandler("pattern_limit", [this](const std::string &value) { - auto limit = strtol(value.c_str(), nullptr, 0); - - if (limit <= 0) - return false; - - this->m_evaluator->setPatternLimit(limit); - return true; - }); - - this->m_preprocessor->addPragmaHandler("loop_limit", [this](const std::string &value) { - auto limit = strtol(value.c_str(), nullptr, 0); - - if (limit <= 0) - return false; - - this->m_evaluator->setLoopLimit(limit); - return true; - }); - - this->m_preprocessor->addPragmaHandler("base_address", [](const std::string &value) { - auto baseAddress = strtoull(value.c_str(), nullptr, 0); - - ImHexApi::Provider::get()->setBaseAddress(baseAddress); - return true; - }); - - this->m_preprocessor->addPragmaHandler("bitfield_order", [this](const std::string &value) { - if (value == "left_to_right") { - this->m_evaluator->setBitfieldOrder(BitfieldOrder::LeftToRight); - return true; - } else if (value == "right_to_left") { - this->m_evaluator->setBitfieldOrder(BitfieldOrder::RightToLeft); - return true; - } else { - return false; - } - }); - } - - PatternLanguage::~PatternLanguage() { - delete this->m_preprocessor; - delete this->m_lexer; - delete this->m_parser; - delete this->m_validator; - } - - std::optional>> PatternLanguage::parseString(const std::string &code) { - auto preprocessedCode = this->m_preprocessor->preprocess(code); - if (!preprocessedCode.has_value()) { - this->m_currError = this->m_preprocessor->getError(); - return std::nullopt; - } - - auto tokens = this->m_lexer->lex(preprocessedCode.value()); - if (!tokens.has_value()) { - this->m_currError = this->m_lexer->getError(); - return std::nullopt; - } - - auto ast = this->m_parser->parse(tokens.value()); - if (!ast.has_value()) { - this->m_currError = this->m_parser->getError(); - return std::nullopt; - } - - if (!this->m_validator->validate(*ast)) { - this->m_currError = this->m_validator->getError(); - - return std::nullopt; - } - - return ast; - } - - bool PatternLanguage::executeString(prv::Provider *provider, const std::string &code, const std::map &envVars, const std::map &inVariables, bool checkResult) { - this->m_running = true; - ON_SCOPE_EXIT { this->m_running = false; }; - - ON_SCOPE_EXIT { - if (this->m_currError.has_value()) { - const auto &error = this->m_currError.value(); - - if (error.getLineNumber() > 0) - this->m_evaluator->getConsole().log(LogConsole::Level::Error, hex::format("{}: {}", error.getLineNumber(), error.what())); - else - this->m_evaluator->getConsole().log(LogConsole::Level::Error, error.what()); - } - }; - - this->m_currError.reset(); - this->m_evaluator->getConsole().clear(); - this->m_evaluator->setProvider(provider); - this->m_evaluator->setDefaultEndian(std::endian::native); - this->m_evaluator->setEvaluationDepth(32); - this->m_evaluator->setArrayLimit(0x1000); - this->m_evaluator->setPatternLimit(0x2000); - this->m_evaluator->setLoopLimit(0x1000); - this->m_evaluator->setInVariables(inVariables); - - for (const auto &[name, value] : envVars) - this->m_evaluator->setEnvVariable(name, value); - - this->m_currAST.clear(); - - { - auto ast = this->parseString(code); - if (!ast) - return false; - - this->m_currAST = std::move(ast.value()); - } - - - auto patterns = this->m_evaluator->evaluate(this->m_currAST); - if (!patterns.has_value()) { - this->m_currError = this->m_evaluator->getConsole().getLastHardError(); - return false; - } - - if (auto mainResult = this->m_evaluator->getMainResult(); checkResult && mainResult.has_value()) { - auto returnCode = Token::literalToSigned(*mainResult); - - if (returnCode != 0) { - this->m_currError = PatternLanguageError(0, hex::format("non-success value returned from main: {}", returnCode)); - - return false; - } - } - - this->m_patterns = std::move(patterns.value()); - - return true; - } - - bool PatternLanguage::executeFile(prv::Provider *provider, const std::fs::path &path, const std::map &envVars, const std::map &inVariables) { - fs::File file(path, fs::File::Mode::Read); - - return this->executeString(provider, file.readString(), envVars, inVariables, true); - } - - std::pair> PatternLanguage::executeFunction(prv::Provider *provider, const std::string &code) { - - auto functionContent = hex::format("fn main() {{ {0} }};", code); - - auto success = this->executeString(provider, functionContent, {}, {}, false); - auto result = this->m_evaluator->getMainResult(); - - return { success, std::move(result) }; - } - - void PatternLanguage::abort() { - this->m_evaluator->abort(); - } - - const std::vector> &PatternLanguage::getCurrentAST() const { - return this->m_currAST; - } - - [[nodiscard]] std::map PatternLanguage::getOutVariables() const { - return this->m_evaluator->getOutVariables(); - } - - - const std::vector> &PatternLanguage::getConsoleLog() { - return this->m_evaluator->getConsole().getLog(); - } - - const std::optional &PatternLanguage::getError() { - return this->m_currError; - } - - u32 PatternLanguage::getCreatedPatternCount() { - return this->m_evaluator->getPatternCount(); - } - - u32 PatternLanguage::getMaximumPatternCount() { - return this->m_evaluator->getPatternLimit(); - } - - - void PatternLanguage::allowDangerousFunctions(bool allow) { - this->m_evaluator->allowDangerousFunctions(allow); - } - - bool PatternLanguage::hasDangerousFunctionBeenCalled() const { - return this->m_evaluator->hasDangerousFunctionBeenCalled(); - } - - void PatternLanguage::reset() { - this->m_patterns.clear(); - - this->m_currAST.clear(); - } - -} \ No newline at end of file diff --git a/lib/libimhex/source/pattern_language/preprocessor.cpp b/lib/libimhex/source/pattern_language/preprocessor.cpp deleted file mode 100644 index f4b7865e5..000000000 --- a/lib/libimhex/source/pattern_language/preprocessor.cpp +++ /dev/null @@ -1,276 +0,0 @@ -#include - -#include -#include -#include - -#include - -namespace hex::pl { - - std::optional Preprocessor::preprocess(std::string code, bool initialRun) { - u32 offset = 0; - u32 lineNumber = 1; - bool isInString = false; - - if (initialRun) { - this->m_defines.clear(); - this->m_pragmas.clear(); - } - - std::string output; - output.reserve(code.length()); - - try { - while (offset < code.length()) { - if (code.substr(offset, 2) == "//") { - while (code[offset] != '\n' && offset < code.length()) - offset += 1; - } else if (code.substr(offset, 2) == "/*") { - while (code.substr(offset, 2) != "*/" && offset < code.length()) { - if (code[offset] == '\n') { - output += '\n'; - lineNumber++; - } - - offset += 1; - } - - offset += 2; - if (offset >= code.length()) - throwPreprocessorError("unterminated comment", lineNumber - 1); - } else { - output += code[offset]; - offset++; - } - } - - offset = 0; - code = output; - output.clear(); - output.reserve(code.size()); - - bool startOfLine = true; - while (offset < code.length()) { - if (offset > 0 && code[offset - 1] != '\\' && code[offset] == '\"') - isInString = !isInString; - else if (isInString) { - output += code[offset]; - offset += 1; - continue; - } - - if (code[offset] == '#' && startOfLine) { - offset += 1; - - if (code.substr(offset, 7) == "include") { - offset += 7; - - while (std::isblank(code[offset]) || std::isspace(code[offset])) - offset += 1; - - if (code[offset] != '<' && code[offset] != '"') - throwPreprocessorError("expected '<' or '\"' before file name", lineNumber); - - char endChar = code[offset]; - if (endChar == '<') endChar = '>'; - - offset += 1; - - std::string includeFile; - while (code[offset] != endChar && code[offset] != '\n') { - includeFile += code[offset]; - offset += 1; - - if (offset >= code.length()) - throwPreprocessorError(hex::format("missing terminating '{0}' character", endChar), lineNumber); - } - offset += 1; - - std::fs::path includePath = includeFile; - - if (includeFile[0] != '/') { - for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::PatternsInclude)) { - std::fs::path tempPath = dir / includePath; - if (fs::isRegularFile(tempPath)) { - includePath = tempPath; - break; - } - } - } - - if (!fs::isRegularFile(includePath)) { - if (includePath.parent_path().filename().string() == "std") - throwPreprocessorError(hex::format("{0}: No such file.\n\nThis file might be part of the standard library.\nYou can install the standard library though\nthe Content Store found under Help -> Content Store.", includeFile.c_str()), lineNumber); - else - throwPreprocessorError(hex::format("{0}: No such file", includeFile.c_str()), lineNumber); - } - - fs::File file(includePath, fs::File::Mode::Read); - if (!file.isValid()) { - throwPreprocessorError(hex::format("{0}: Failed to open file", includeFile.c_str()), lineNumber); - } - - Preprocessor preprocessor; - preprocessor.addDefaultPragmaHandlers(); - preprocessor.m_defines = this->m_defines; - preprocessor.m_onceIncludedFiles = this->m_onceIncludedFiles; - - auto preprocessedInclude = preprocessor.preprocess(file.readString(), /*initialRun =*/false); - - if (!preprocessedInclude.has_value()) { - auto error = *preprocessor.m_error; - throw error; - } - - if (preprocessor.shouldOnlyIncludeOnce()) { - auto [iter, added] = this->m_onceIncludedFiles.insert(includePath); - if (added) { - auto content = preprocessedInclude.value(); - - std::replace(content.begin(), content.end(), '\n', ' '); - std::replace(content.begin(), content.end(), '\r', ' '); - - output += content; - } - } - - this->m_defines = preprocessor.m_defines; - this->m_onceIncludedFiles = preprocessor.m_onceIncludedFiles; - } else if (code.substr(offset, 6) == "define") { - offset += 6; - - while (std::isblank(code[offset])) { - offset += 1; - } - - std::string defineName; - while (!std::isblank(code[offset])) { - defineName += code[offset]; - - if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r') - throwPreprocessorError("no value given in #define directive", lineNumber); - offset += 1; - } - - while (std::isblank(code[offset])) { - offset += 1; - if (offset >= code.length()) - throwPreprocessorError("no value given in #define directive", lineNumber); - } - - std::string replaceValue; - while (code[offset] != '\n' && code[offset] != '\r') { - if (offset >= code.length()) - throwPreprocessorError("missing new line after #define directive", lineNumber); - - replaceValue += code[offset]; - offset += 1; - } - - if (replaceValue.empty()) - throwPreprocessorError("no value given in #define directive", lineNumber); - - this->m_defines.emplace(defineName, replaceValue, lineNumber); - } else if (code.substr(offset, 6) == "pragma") { - offset += 6; - - while (std::isblank(code[offset])) { - offset += 1; - - if (code[offset] == '\n' || code[offset] == '\r') - throwPreprocessorError("no instruction given in #pragma directive", lineNumber); - } - - std::string pragmaKey; - while (!std::isblank(code[offset]) && code[offset] != '\n' && code[offset] != '\r') { - pragmaKey += code[offset]; - - if (offset >= code.length()) - throwPreprocessorError("no instruction given in #pragma directive", lineNumber); - - offset += 1; - } - - while (std::isblank(code[offset])) - offset += 1; - - std::string pragmaValue; - while (code[offset] != '\n' && code[offset] != '\r') { - if (offset >= code.length()) - throwPreprocessorError("missing new line after #pragma directive", lineNumber); - - pragmaValue += code[offset]; - offset += 1; - } - - this->m_pragmas.emplace(pragmaKey, pragmaValue, lineNumber); - } else - throwPreprocessorError("unknown preprocessor directive", lineNumber); - } - - if (code[offset] == '\n') { - lineNumber++; - startOfLine = true; - } else if (!std::isspace(code[offset])) - startOfLine = false; - - output += code[offset]; - offset += 1; - } - - // Apply defines - std::vector> sortedDefines; - std::copy(this->m_defines.begin(), this->m_defines.end(), std::back_inserter(sortedDefines)); - std::sort(sortedDefines.begin(), sortedDefines.end(), [](const auto &left, const auto &right) { - return std::get<0>(left).size() > std::get<0>(right).size(); - }); - - for (const auto &[define, value, defineLine] : sortedDefines) { - size_t index = 0; - while ((index = output.find(define, index)) != std::string::npos) { - output.replace(index, define.length(), value); - index += value.length(); - } - } - - // Handle pragmas - for (const auto &[type, value, pragmaLine] : this->m_pragmas) { - if (this->m_pragmaHandlers.contains(type)) { - if (!this->m_pragmaHandlers[type](value)) - throwPreprocessorError(hex::format("invalid value provided to '{0}' #pragma directive", type.c_str()), pragmaLine); - } else - throwPreprocessorError(hex::format("no #pragma handler registered for type {0}", type.c_str()), pragmaLine); - } - } catch (PatternLanguageError &e) { - this->m_error = e; - - return std::nullopt; - } - - return output; - } - - void Preprocessor::addPragmaHandler(const std::string &pragmaType, const std::function &function) { - this->m_pragmaHandlers[pragmaType] = function; - } - - void Preprocessor::removePragmaHandler(const std::string &pragmaType) { - this->m_pragmaHandlers.erase(pragmaType); - } - - void Preprocessor::addDefaultPragmaHandlers() { - this->addPragmaHandler("MIME", [](const std::string &value) { - return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r'); - }); - this->addPragmaHandler("endian", [](const std::string &value) { - return value == "big" || value == "little" || value == "native"; - }); - this->addPragmaHandler("once", [this](const std::string &value) { - this->m_onlyIncludeOnce = true; - - return value.empty(); - }); - } - -} \ No newline at end of file diff --git a/lib/libimhex/source/pattern_language/validator.cpp b/lib/libimhex/source/pattern_language/validator.cpp deleted file mode 100644 index 0f6d71d94..000000000 --- a/lib/libimhex/source/pattern_language/validator.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -namespace hex::pl { - - bool Validator::validate(const std::vector> &ast) { - std::unordered_set identifiers; - std::unordered_set types; - - try { - - for (const auto &node : ast) { - if (node == nullptr) - throwValidatorError("nullptr in AST. This is a bug!", 1); - - if (auto variableDeclNode = dynamic_cast(node.get()); variableDeclNode != nullptr) { - if (!identifiers.insert(variableDeclNode->getName().data()).second) - throwValidatorError(hex::format("redefinition of identifier '{0}'", variableDeclNode->getName().data()), variableDeclNode->getLineNumber()); - - this->validate(hex::moveToVector>(variableDeclNode->getType()->clone())); - } else if (auto typeDeclNode = dynamic_cast(node.get()); typeDeclNode != nullptr) { - if (!types.insert(typeDeclNode->getName().data()).second) - throwValidatorError(hex::format("redefinition of type '{0}'", typeDeclNode->getName().data()), typeDeclNode->getLineNumber()); - - if (!typeDeclNode->isForwardDeclared()) - this->validate(hex::moveToVector>(typeDeclNode->getType()->clone())); - } else if (auto structNode = dynamic_cast(node.get()); structNode != nullptr) { - this->validate(structNode->getMembers()); - } else if (auto unionNode = dynamic_cast(node.get()); unionNode != nullptr) { - this->validate(unionNode->getMembers()); - } else if (auto enumNode = dynamic_cast(node.get()); enumNode != nullptr) { - std::unordered_set enumIdentifiers; - for (auto &[name, value] : enumNode->getEntries()) { - if (!enumIdentifiers.insert(name).second) - throwValidatorError(hex::format("redefinition of enum constant '{0}'", name.c_str()), value->getLineNumber()); - } - } - } - - } catch (PatternLanguageError &e) { - this->m_error = e; - return false; - } - - return true; - } -} \ No newline at end of file diff --git a/lib/libimhex/source/providers/provider.cpp b/lib/libimhex/source/providers/provider.cpp index ae563bfa5..71e7beedc 100644 --- a/lib/libimhex/source/providers/provider.cpp +++ b/lib/libimhex/source/providers/provider.cpp @@ -1,10 +1,8 @@ #include #include +#include #include -#include -#include - #include #include @@ -13,11 +11,13 @@ #include #include +#include + namespace hex::prv { Provider::Provider() { this->m_patches.emplace_back(); - this->m_patternLanguageRuntime = std::make_unique(); + this->m_patternLanguageRuntime = ContentRegistry::PatternLanguage::createDefaultRuntime(this); if (this->hasLoadInterface()) EventManager::post(View::toWindowName("hex.builtin.view.provider_settings.load_popup")); @@ -44,7 +44,7 @@ namespace hex::prv { } void Provider::resize(size_t newSize) { - hex::unused(newSize); + this->m_patternLanguageRuntime->setDataSize(newSize); } void Provider::insert(u64 offset, size_t size) { @@ -129,6 +129,7 @@ namespace hex::prv { void Provider::setBaseAddress(u64 address) { this->m_baseAddress = address; + this->m_patternLanguageRuntime->setDataBaseAddress(address); } u64 Provider::getBaseAddress() const { diff --git a/main/source/init/tasks.cpp b/main/source/init/tasks.cpp index cbe1154ec..a6d892b7c 100644 --- a/main/source/init/tasks.cpp +++ b/main/source/init/tasks.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -185,7 +184,6 @@ namespace hex::init { ContentRegistry::CommandPaletteCommands::getEntries().clear(); ContentRegistry::PatternLanguage::getFunctions().clear(); - ContentRegistry::PatternLanguage::getPalettes().clear(); for (auto &[name, view] : ContentRegistry::Views::getEntries()) delete view; diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 91ffc3ec9..f30a6e9d4 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(${PROJECT_NAME} SHARED source/content/command_palette_commands.cpp source/content/data_inspector.cpp source/content/pl_builtin_functions.cpp + source/content/pl_pragmas.cpp source/content/settings_entries.cpp source/content/tools_entries.cpp source/content/data_processor_nodes.cpp diff --git a/plugins/builtin/include/content/views/view_pattern_data.hpp b/plugins/builtin/include/content/views/view_pattern_data.hpp index 085b5406e..be7b91a46 100644 --- a/plugins/builtin/include/content/views/view_pattern_data.hpp +++ b/plugins/builtin/include/content/views/view_pattern_data.hpp @@ -22,7 +22,7 @@ namespace hex::plugin::builtin { private: std::map>> m_sortedPatterns; - hex::PatternDrawer m_drawer; + hex::PatternDrawer m_patternDrawer; }; } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index 3f238d117..f37cb29ba 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -1,8 +1,7 @@ #pragma once #include -#include -#include +#include #include #include @@ -79,6 +78,15 @@ namespace hex::plugin::builtin { u64 m_envVarIdCounter; std::list m_envVarEntries; + enum class DangerousFunctionPerms : u8 { + Ask, + Allow, + Deny + }; + + std::atomic m_dangerousFunctionCalled = false; + std::atomic m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask; + void drawConsole(ImVec2 size); void drawEnvVars(ImVec2 size); void drawVariableSettings(ImVec2 size); diff --git a/plugins/builtin/include/pattern_drawer.hpp b/plugins/builtin/include/pattern_drawer.hpp index 5462bf921..32d5381cd 100644 --- a/plugins/builtin/include/pattern_drawer.hpp +++ b/plugins/builtin/include/pattern_drawer.hpp @@ -1,22 +1,19 @@ #pragma once -#include -#include +#include +#include #include namespace hex { template concept ArrayPattern = requires(T pattern, std::function fn) { - { pattern.forEachArrayEntry(fn) } -> std::same_as; + { pattern.forEachArrayEntry(fn) } -> std::same_as; }; - class PatternDrawer : public pl::PatternVisitor - { + class PatternDrawer : public pl::PatternVisitor { public: - PatternDrawer(); - - void setProvider(prv::Provider *provider); + PatternDrawer() = default; void visit(pl::PatternArrayDynamic& pattern) override; void visit(pl::PatternArrayStatic& pattern) override; @@ -73,7 +70,6 @@ namespace hex { u64& getDisplayEnd(const pl::Pattern& pattern); private: - prv::Provider *m_provider; std::map m_displayEnd; }; }; \ No newline at end of file diff --git a/plugins/builtin/source/content/pl_builtin_functions.cpp b/plugins/builtin/source/content/pl_builtin_functions.cpp index 9032b0625..588dafddf 100644 --- a/plugins/builtin/source/content/pl_builtin_functions.cpp +++ b/plugins/builtin/source/content/pl_builtin_functions.cpp @@ -3,11 +3,12 @@ #include #include #include +#include -#include -#include -#include -#include +#include +#include +#include +#include #include @@ -15,7 +16,7 @@ namespace hex::plugin::builtin { - std::string format(pl::Evaluator *ctx, const auto ¶ms) { + std::string format(const auto ¶ms) { auto format = pl::Token::literalToString(params[0], true); std::string message; @@ -26,7 +27,7 @@ namespace hex::plugin::builtin { std::visit(overloaded { [&](pl::Pattern *value) { - formatArgs.push_back(value->toString(ctx->getProvider())); + formatArgs.push_back(value->toString()); }, [&](auto &&value) { formatArgs.push_back(value); @@ -37,32 +38,30 @@ namespace hex::plugin::builtin { try { return fmt::vformat(format, formatArgs); } catch (fmt::format_error &error) { - hex::pl::LogConsole::abortEvaluation(hex::format("format error: {}", error.what())); + pl::LogConsole::abortEvaluation(hex::format("format error: {}", error.what())); } } void registerPatternLanguageFunctions() { - using namespace hex::pl; - using ParameterCount = ContentRegistry::PatternLanguage::ParameterCount; + using namespace pl; + using FunctionParameterCount = pl::api::FunctionParameterCount; - ContentRegistry::PatternLanguage::addColorPalette("hex.builtin.palette.pastel", { 0x70B4771F, 0x700E7FFF, 0x702CA02C, 0x702827D6, 0x70BD6794, 0x704B568C, 0x70C277E3, 0x707F7F7F, 0x7022BDBC, 0x70CFBE17 }); - - ContentRegistry::PatternLanguage::Namespace nsStd = { "builtin", "std" }; + pl::api::Namespace nsStd = { "builtin", "std" }; { /* print(format, args...) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "print", ParameterCount::moreThan(0), [](Evaluator *ctx, auto params) -> std::optional { - ctx->getConsole().log(LogConsole::Level::Info, format(ctx, params)); + ContentRegistry::PatternLanguage::addFunction(nsStd, "print", FunctionParameterCount::moreThan(0), [](Evaluator *ctx, auto params) -> std::optional { + ctx->getConsole().log(LogConsole::Level::Info, format(params)); return std::nullopt; }); /* format(format, args...) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "format", ParameterCount::moreThan(0), [](Evaluator *ctx, auto params) -> std::optional { - return format(ctx, params); + ContentRegistry::PatternLanguage::addFunction(nsStd, "format", FunctionParameterCount::moreThan(0), [](Evaluator *, auto params) -> std::optional { + return format(params); }); /* env(name) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "env", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "env", FunctionParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { auto name = Token::literalToString(params[0], false); auto env = ctx->getEnvVariable(name); @@ -75,44 +74,44 @@ namespace hex::plugin::builtin { }); /* pack_size(...) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "sizeof_pack", ParameterCount::atLeast(0), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "sizeof_pack", FunctionParameterCount::atLeast(0), [](Evaluator *, auto params) -> std::optional { return u128(params.size()); }); /* error(message) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "error", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "error", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { LogConsole::abortEvaluation(Token::literalToString(params[0], true)); return std::nullopt; }); /* warning(message) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "warning", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "warning", FunctionParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { ctx->getConsole().log(LogConsole::Level::Warning, Token::literalToString(params[0], true)); return std::nullopt; }); } - ContentRegistry::PatternLanguage::Namespace nsStdMem = { "builtin", "std", "mem" }; + api::Namespace nsStdMem = { "builtin", "std", "mem" }; { /* base_address() */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "base_address", ParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "base_address", FunctionParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional { hex::unused(params); - return u128(ctx->getProvider()->getBaseAddress()); + return u128(ctx->getDataBaseAddress()); }); /* size() */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "size", ParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "size", FunctionParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional { hex::unused(params); - return u128(ctx->getProvider()->getActualSize()); + return u128(ctx->getDataSize()); }); /* find_sequence_in_range(occurrence_index, start_offset, end_offset, bytes...) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "find_sequence_in_range", ParameterCount::moreThan(3), [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "find_sequence_in_range", FunctionParameterCount::moreThan(3), [](Evaluator *ctx, auto params) -> std::optional { auto occurrenceIndex = Token::literalToUnsigned(params[0]); auto offsetFrom = Token::literalToUnsigned(params[1]); auto offsetTo = Token::literalToUnsigned(params[2]); @@ -129,10 +128,10 @@ namespace hex::plugin::builtin { std::vector bytes(sequence.size(), 0x00); u32 occurrences = 0; - const u64 bufferSize = ctx->getProvider()->getSize(); + const u64 bufferSize = ctx->getDataSize(); const u64 endOffset = offsetTo <= offsetFrom ? bufferSize : std::min(bufferSize, u64(offsetTo)); for (u64 offset = offsetFrom; offset < endOffset - sequence.size(); offset++) { - ctx->getProvider()->read(offset, bytes.data(), bytes.size()); + ctx->readData(offset, bytes.data(), bytes.size()); if (bytes == sequence) { if (occurrences < occurrenceIndex) { @@ -148,7 +147,7 @@ namespace hex::plugin::builtin { }); /* read_unsigned(address, size) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_unsigned", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_unsigned", FunctionParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { auto address = Token::literalToUnsigned(params[0]); auto size = Token::literalToUnsigned(params[1]); @@ -156,13 +155,13 @@ namespace hex::plugin::builtin { LogConsole::abortEvaluation("read size out of range"); u128 result = 0; - ctx->getProvider()->read(address, &result, size); + ctx->readData(address, &result, size); return result; }); /* read_signed(address, size) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_signed", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_signed", FunctionParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { auto address = Token::literalToUnsigned(params[0]); auto size = Token::literalToUnsigned(params[1]); @@ -170,33 +169,33 @@ namespace hex::plugin::builtin { LogConsole::abortEvaluation("read size out of range"); i128 value; - ctx->getProvider()->read(address, &value, size); + ctx->readData(address, &value, size); return hex::signExtend(size * 8, value); }); /* read_string(address, size) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_string", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_string", FunctionParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { auto address = Token::literalToUnsigned(params[0]); auto size = Token::literalToUnsigned(params[1]); std::string result(size, '\x00'); - ctx->getProvider()->read(address, result.data(), size); + ctx->readData(address, result.data(), size); return result; }); } - ContentRegistry::PatternLanguage::Namespace nsStdString = { "builtin", "std", "string" }; + api::Namespace nsStdString = { "builtin", "std", "string" }; { /* length(string) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "length", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "length", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); return u128(string.length()); }); /* at(string, index) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "at", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "at", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); auto index = Token::literalToSigned(params[1]); @@ -217,7 +216,7 @@ namespace hex::plugin::builtin { }); /* substr(string, pos, count) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "substr", ParameterCount::exactly(3), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "substr", FunctionParameterCount::exactly(3), [](Evaluator *, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); auto pos = Token::literalToUnsigned(params[1]); auto size = Token::literalToUnsigned(params[2]); @@ -229,7 +228,7 @@ namespace hex::plugin::builtin { }); /* parse_int(string, base) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_int", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_int", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); auto base = Token::literalToUnsigned(params[1]); @@ -237,17 +236,17 @@ namespace hex::plugin::builtin { }); /* parse_float(string) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_float", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_float", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); return double(std::strtod(string.c_str(), nullptr)); }); } - ContentRegistry::PatternLanguage::Namespace nsStdHttp = { "builtin", "std", "http" }; + api::Namespace nsStdHttp = { "builtin", "std", "http" }; { /* get(url) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdHttp, "get", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdHttp, "get", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { const auto url = Token::literalToString(params[0], false); hex::Net net; @@ -256,13 +255,13 @@ namespace hex::plugin::builtin { } - ContentRegistry::PatternLanguage::Namespace nsStdFile = { "builtin", "std", "file" }; + api::Namespace nsStdFile = { "builtin", "std", "file" }; { static u32 fileCounter = 0; static std::map openFiles; /* open(path, mode) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "open", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "open", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { const auto path = Token::literalToString(params[0], false); const auto modeEnum = Token::literalToUnsigned(params[1]); @@ -293,7 +292,7 @@ namespace hex::plugin::builtin { }); /* close(file) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "close", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "close", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); if (!openFiles.contains(file)) @@ -305,7 +304,7 @@ namespace hex::plugin::builtin { }); /* read(file, size) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "read", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "read", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); const auto size = Token::literalToUnsigned(params[1]); @@ -316,7 +315,7 @@ namespace hex::plugin::builtin { }); /* write(file, data) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "write", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "write", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); const auto data = Token::literalToString(params[1], true); @@ -329,7 +328,7 @@ namespace hex::plugin::builtin { }); /* seek(file, offset) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "seek", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "seek", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); const auto offset = Token::literalToUnsigned(params[1]); @@ -342,7 +341,7 @@ namespace hex::plugin::builtin { }); /* size(file) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "size", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "size", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); if (!openFiles.contains(file)) @@ -352,7 +351,7 @@ namespace hex::plugin::builtin { }); /* resize(file, size) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "resize", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "resize", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); const auto size = Token::literalToUnsigned(params[1]); @@ -365,7 +364,7 @@ namespace hex::plugin::builtin { }); /* flush(file) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "flush", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "flush", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); if (!openFiles.contains(file)) @@ -377,7 +376,7 @@ namespace hex::plugin::builtin { }); /* remove(file) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "remove", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "remove", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); if (!openFiles.contains(file)) @@ -390,129 +389,129 @@ namespace hex::plugin::builtin { } - ContentRegistry::PatternLanguage::Namespace nsStdMath = { "builtin", "std", "math" }; + api::Namespace nsStdMath = { "builtin", "std", "math" }; { /* floor(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "floor", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "floor", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::floor(Token::literalToFloatingPoint(params[0])); }); /* ceil(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ceil", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ceil", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::ceil(Token::literalToFloatingPoint(params[0])); }); /* round(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "round", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "round", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::round(Token::literalToFloatingPoint(params[0])); }); /* trunc(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "trunc", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "trunc", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::trunc(Token::literalToFloatingPoint(params[0])); }); /* log10(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log10", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log10", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::log10(Token::literalToFloatingPoint(params[0])); }); /* log2(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log2", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log2", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::log2(Token::literalToFloatingPoint(params[0])); }); /* ln(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ln", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ln", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::log(Token::literalToFloatingPoint(params[0])); }); /* fmod(x, y) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "fmod", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "fmod", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { return std::fmod(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1])); }); /* pow(base, exp) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "pow", ParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "pow", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional { return std::pow(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1])); }); /* sqrt(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sqrt", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sqrt", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::sqrt(Token::literalToFloatingPoint(params[0])); }); /* cbrt(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cbrt", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cbrt", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::cbrt(Token::literalToFloatingPoint(params[0])); }); /* sin(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sin", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sin", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::sin(Token::literalToFloatingPoint(params[0])); }); /* cos(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cos", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cos", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::cos(Token::literalToFloatingPoint(params[0])); }); /* tan(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tan", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tan", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::tan(Token::literalToFloatingPoint(params[0])); }); /* asin(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asin", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asin", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::asin(Token::literalToFloatingPoint(params[0])); }); /* acos(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acos", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acos", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::acos(Token::literalToFloatingPoint(params[0])); }); /* atan(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::atan(Token::literalToFloatingPoint(params[0])); }); /* atan2(y, x) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::atan2(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1])); }); /* sinh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sinh", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sinh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::sinh(Token::literalToFloatingPoint(params[0])); }); /* cosh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cosh", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cosh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::cosh(Token::literalToFloatingPoint(params[0])); }); /* tanh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tanh", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tanh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::tanh(Token::literalToFloatingPoint(params[0])); }); /* asinh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asinh", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asinh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::asinh(Token::literalToFloatingPoint(params[0])); }); /* acosh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acosh", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acosh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::acosh(Token::literalToFloatingPoint(params[0])); }); /* atanh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atanh", ParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atanh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { return std::atanh(Token::literalToFloatingPoint(params[0])); }); } diff --git a/plugins/builtin/source/content/pl_pragmas.cpp b/plugins/builtin/source/content/pl_pragmas.cpp new file mode 100644 index 000000000..19393f099 --- /dev/null +++ b/plugins/builtin/source/content/pl_pragmas.cpp @@ -0,0 +1,85 @@ +#include +#include + +#include + +namespace hex::plugin::builtin { + + void registerPatternLanguagePragmas() { + ContentRegistry::PatternLanguage::addPragma("endian", [](pl::PatternLanguage &runtime, const std::string &value) { + if (value == "big") { + runtime.getInternals().evaluator->setDefaultEndian(std::endian::big); + return true; + } else if (value == "little") { + runtime.getInternals().evaluator->setDefaultEndian(std::endian::little); + return true; + } else if (value == "native") { + runtime.getInternals().evaluator->setDefaultEndian(std::endian::native); + return true; + } else + return false; + }); + + ContentRegistry::PatternLanguage::addPragma("eval_depth", [](pl::PatternLanguage &runtime, const std::string &value) { + auto limit = strtol(value.c_str(), nullptr, 0); + + if (limit <= 0) + return false; + + runtime.getInternals().evaluator->setEvaluationDepth(limit); + return true; + }); + + ContentRegistry::PatternLanguage::addPragma("array_limit", [](pl::PatternLanguage &runtime, const std::string &value) { + auto limit = strtol(value.c_str(), nullptr, 0); + + if (limit <= 0) + return false; + + runtime.getInternals().evaluator->setArrayLimit(limit); + return true; + }); + + ContentRegistry::PatternLanguage::addPragma("pattern_limit", [](pl::PatternLanguage &runtime, const std::string &value) { + auto limit = strtol(value.c_str(), nullptr, 0); + + if (limit <= 0) + return false; + + runtime.getInternals().evaluator->setPatternLimit(limit); + return true; + }); + + ContentRegistry::PatternLanguage::addPragma("loop_limit", [](pl::PatternLanguage &runtime, const std::string &value) { + auto limit = strtol(value.c_str(), nullptr, 0); + + if (limit <= 0) + return false; + + runtime.getInternals().evaluator->setLoopLimit(limit); + return true; + }); + + ContentRegistry::PatternLanguage::addPragma("base_address", [](pl::PatternLanguage &runtime, const std::string &value) { + hex::unused(runtime); + + auto baseAddress = strtoull(value.c_str(), nullptr, 0); + + ImHexApi::Provider::get()->setBaseAddress(baseAddress); + return true; + }); + + ContentRegistry::PatternLanguage::addPragma("bitfield_order", [](pl::PatternLanguage &runtime, const std::string &value) { + if (value == "left_to_right") { + runtime.getInternals().evaluator->setBitfieldOrder(pl::BitfieldOrder::LeftToRight); + return true; + } else if (value == "right_to_left") { + runtime.getInternals().evaluator->setBitfieldOrder(pl::BitfieldOrder::RightToLeft); + return true; + } else { + return false; + } + }); + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/providers/disk_provider.cpp b/plugins/builtin/source/content/providers/disk_provider.cpp index ed5ecf744..7c00d6c2f 100644 --- a/plugins/builtin/source/content/providers/disk_provider.cpp +++ b/plugins/builtin/source/content/providers/disk_provider.cpp @@ -133,6 +133,8 @@ namespace hex::plugin::builtin::prv { #endif + Provider::resize(this->getActualSize()); + return true; } diff --git a/plugins/builtin/source/content/providers/file_provider.cpp b/plugins/builtin/source/content/providers/file_provider.cpp index 644057cfa..e3bded88a 100644 --- a/plugins/builtin/source/content/providers/file_provider.cpp +++ b/plugins/builtin/source/content/providers/file_provider.cpp @@ -264,6 +264,8 @@ namespace hex::plugin::builtin::prv { } #endif + Provider::resize(this->getActualSize()); + return true; } diff --git a/plugins/builtin/source/content/providers/gdb_provider.cpp b/plugins/builtin/source/content/providers/gdb_provider.cpp index 590084755..49f07481d 100644 --- a/plugins/builtin/source/content/providers/gdb_provider.cpp +++ b/plugins/builtin/source/content/providers/gdb_provider.cpp @@ -278,6 +278,8 @@ namespace hex::plugin::builtin::prv { } }); + Provider::resize(this->getActualSize()); + return true; } else { return false; diff --git a/plugins/builtin/source/content/settings_entries.cpp b/plugins/builtin/source/content/settings_entries.cpp index a1aa3ba91..4e848fa89 100644 --- a/plugins/builtin/source/content/settings_entries.cpp +++ b/plugins/builtin/source/content/settings_entries.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include diff --git a/plugins/builtin/source/content/views/view_pattern_data.cpp b/plugins/builtin/source/content/views/view_pattern_data.cpp index c1ca90ce2..581c456c3 100644 --- a/plugins/builtin/source/content/views/view_pattern_data.cpp +++ b/plugins/builtin/source/content/views/view_pattern_data.cpp @@ -2,8 +2,8 @@ #include -#include -#include +#include +#include namespace hex::plugin::builtin { @@ -20,6 +20,53 @@ namespace hex::plugin::builtin { EventManager::unsubscribe(this); } + static bool sortPatterns(prv::Provider *provider, const ImGuiTableSortSpecs* sortSpecs, const pl::Pattern * left, const pl::Pattern * right) { + if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getDisplayName() > right->getDisplayName(); + else + return left->getDisplayName() < right->getDisplayName(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getOffset() > right->getOffset(); + else + return left->getOffset() < right->getOffset(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getSize() > right->getSize(); + else + return left->getSize() < right->getSize(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) { + size_t biggerSize = std::max(left->getSize(), right->getSize()); + std::vector leftBuffer(biggerSize, 0x00), rightBuffer(biggerSize, 0x00); + + provider->read(left->getOffset(), leftBuffer.data(), left->getSize()); + provider->read(right->getOffset(), rightBuffer.data(), right->getSize()); + + if (left->getEndian() != std::endian::native) + std::reverse(leftBuffer.begin(), leftBuffer.end()); + if (right->getEndian() != std::endian::native) + std::reverse(rightBuffer.begin(), rightBuffer.end()); + + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return leftBuffer > rightBuffer; + else + return leftBuffer < rightBuffer; + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getTypeName() > right->getTypeName(); + else + return left->getTypeName() < right->getTypeName(); + } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) { + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) + return left->getColor() > right->getColor(); + else + return left->getColor() < right->getColor(); + } + + return false; + } + static bool beginPatternTable(prv::Provider *&provider, const std::vector> &patterns, std::vector> &sortedPatterns) { if (ImGui::BeginTable("##Patterntable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) { ImGui::TableSetupScrollFreeze(0, 1); @@ -36,11 +83,13 @@ namespace hex::plugin::builtin { sortedPatterns = patterns; std::sort(sortedPatterns.begin(), sortedPatterns.end(), [&sortSpecs, &provider](const std::shared_ptr &left, const std::shared_ptr &right) -> bool { - return pl::Pattern::sortPatternTable(sortSpecs, provider, left.get(), right.get()); + return sortPatterns(provider, sortSpecs, left.get(), right.get()); }); for (auto &pattern : sortedPatterns) - pattern->sort(sortSpecs, provider); + pattern->sort([&sortSpecs, &provider](const pl::Pattern *left, const pl::Pattern *right){ + return sortPatterns(provider, sortSpecs, left, right); + }); sortSpecs->SpecsDirty = false; } @@ -61,9 +110,8 @@ namespace hex::plugin::builtin { ImGui::TableHeadersRow(); if (!sortedPatterns.empty()) { - m_drawer.setProvider(provider); for (auto &patterns : sortedPatterns) - patterns->accept(m_drawer); + patterns->accept(this->m_patternDrawer); } ImGui::EndTable(); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index d52b51b5d..8d329829b 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -1,12 +1,12 @@ #include "content/views/view_pattern_editor.hpp" +#include +#include +#include +#include +#include -#include -#include -#include -#include -#include - +#include #include #include #include @@ -105,16 +105,18 @@ namespace hex::plugin::builtin { if (!ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", 1)) return; - pl::Preprocessor preprocessor; - preprocessor.addDefaultPragmaHandlers(); - if (!ImHexApi::Provider::isValid()) return; - std::string mimeType = magic::getMIMEType(ImHexApi::Provider::get()); + auto provider = ImHexApi::Provider::get(); + auto runtime = provider->getPatternLanguageRuntime(); + + auto mimeType = magic::getMIMEType(ImHexApi::Provider::get()); bool foundCorrectType = false; - preprocessor.addPragmaHandler("MIME", [&mimeType, &foundCorrectType](std::string value) { + runtime.addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) { + hex::unused(runtime); + if (value == mimeType) { foundCorrectType = true; return true; @@ -135,13 +137,14 @@ namespace hex::plugin::builtin { if (!file.isValid()) continue; - preprocessor.preprocess(file.readString()); + runtime.getInternals().preprocessor->preprocess(runtime, file.readString()); if (foundCorrectType) this->m_possiblePatternFiles.push_back(entry.path()); } } + runtime.removePragma("MIME"); if (!this->m_possiblePatternFiles.empty()) { this->m_selectedPatternFile = 0; @@ -329,7 +332,7 @@ namespace hex::plugin::builtin { } } - if (provider->getPatternLanguageRuntime().hasDangerousFunctionBeenCalled() && !ImGui::IsPopupOpen(View::toWindowName("hex.builtin.view.pattern_editor.dangerous_function.name").c_str())) { + if (this->m_dangerousFunctionCalled && !ImGui::IsPopupOpen(View::toWindowName("hex.builtin.view.pattern_editor.dangerous_function.name").c_str())) { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.pattern_editor.dangerous_function.name").c_str()); } @@ -339,11 +342,14 @@ namespace hex::plugin::builtin { ImGui::NewLine(); View::confirmButtons( - "hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [] { - ImHexApi::Provider::get()->getPatternLanguageRuntime().allowDangerousFunctions(true); - ImGui::CloseCurrentPopup(); }, [] { - ImHexApi::Provider::get()->getPatternLanguageRuntime().allowDangerousFunctions(false); - ImGui::CloseCurrentPopup(); }); + "hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, + [this] { + this->m_dangerousFunctionsAllowed = DangerousFunctionPerms::Allow; + ImGui::CloseCurrentPopup(); + }, [this] { + this->m_dangerousFunctionsAllowed = DangerousFunctionPerms::Deny; + ImGui::CloseCurrentPopup(); + }); ImGui::EndPopup(); } @@ -616,7 +622,6 @@ namespace hex::plugin::builtin { if (!ImHexApi::Provider::isValid()) return; ImHexApi::Provider::get()->getPatternLanguageRuntime().reset(); - ContentRegistry::PatternLanguage::resetPalette(); } @@ -679,7 +684,17 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); auto &runtime = provider->getPatternLanguageRuntime(); - this->m_lastEvaluationResult = runtime.executeString(provider, code, envVars, inVariables); + runtime.setDangerousFunctionCallHandler([this]{ + this->m_dangerousFunctionCalled = true; + + while (this->m_dangerousFunctionsAllowed == DangerousFunctionPerms::Ask) { + std::this_thread::yield(); + } + + return this->m_dangerousFunctionsAllowed == DangerousFunctionPerms::Allow; + }); + + this->m_lastEvaluationResult = runtime.executeString(code, envVars, inVariables); if (!this->m_lastEvaluationResult) { this->m_lastEvaluationError = runtime.getError(); } diff --git a/plugins/builtin/source/pattern_drawer.cpp b/plugins/builtin/source/pattern_drawer.cpp index 90a6865a5..44e2f9e17 100644 --- a/plugins/builtin/source/pattern_drawer.cpp +++ b/plugins/builtin/source/pattern_drawer.cpp @@ -1,24 +1,30 @@ #include "pattern_drawer.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include + +#include +#include + namespace { constexpr static auto DisplayEndDefault = 50u; constexpr static auto DisplayEndStep = 50u; @@ -28,14 +34,6 @@ namespace { namespace hex { - PatternDrawer::PatternDrawer() - : m_provider{nullptr} - { } - - void PatternDrawer::setProvider(prv::Provider *provider) { - m_provider = provider; - } - void PatternDrawer::visit(pl::PatternArrayDynamic& pattern) { this->drawArray(pattern); } @@ -67,12 +65,12 @@ namespace hex { ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "bits"); ImGui::TableNextColumn(); - u64 extractedValue = pattern.getValue(m_provider); + u64 extractedValue = pattern.getValue(); ImGui::TextFormatted("{}", pattern.formatDisplayValue(hex::format("{0} (0x{1:X})", extractedValue, extractedValue), &pattern)); } void PatternDrawer::visit(pl::PatternBitfield& pattern) { - std::vector value = pattern.getValue(m_provider); + std::vector value = pattern.getValue(); bool open = true; if (!pattern.isInlined()) { @@ -108,7 +106,7 @@ namespace hex { } void PatternDrawer::visit(pl::PatternBoolean& pattern) { - u8 boolean = pattern.getValue(m_provider); + u8 boolean = pattern.getValue(); if (boolean == 0) this->createDefaultEntry(pattern, "false", false); @@ -119,12 +117,12 @@ namespace hex { } void PatternDrawer::visit(pl::PatternCharacter& pattern) { - char character = pattern.getValue(m_provider); + char character = pattern.getValue(); this->createDefaultEntry(pattern, hex::format("'{0}'", character), character); } void PatternDrawer::visit(pl::PatternEnum& pattern) { - u64 value = pattern.getValue(m_provider); + u64 value = pattern.getValue(); std::string valueString = pattern.getTypeName() + "::"; @@ -168,12 +166,12 @@ namespace hex { void PatternDrawer::visit(pl::PatternFloat& pattern) { if (pattern.getSize() == 4) { - float f32 = static_cast(pattern.getValue(m_provider)); + float f32 = static_cast(pattern.getValue()); u32 integerResult = 0; std::memcpy(&integerResult, &f32, sizeof(float)); this->createDefaultEntry(pattern, hex::format("{:e} (0x{:0{}X})", f32, integerResult, pattern.getSize() * 2), f32); } else if (pattern.getSize() == 8) { - double f64 = pattern.getValue(m_provider); + double f64 = pattern.getValue(); u64 integerResult = 0; std::memcpy(&integerResult, &f64, sizeof(double)); this->createDefaultEntry(pattern, hex::format("{:e} (0x{:0{}X})", f64, integerResult, pattern.getSize() * 2), f64); @@ -186,7 +184,7 @@ namespace hex { } void PatternDrawer::visit(pl::PatternPointer& pattern) { - u64 data = pattern.getValue(m_provider); + u64 data = pattern.getValue(); bool open = true; @@ -217,7 +215,7 @@ namespace hex { } void PatternDrawer::visit(pl::PatternSigned& pattern) { - i128 data = pattern.getValue(m_provider); + i128 data = pattern.getValue(); this->createDefaultEntry(pattern, hex::format("{:d} (0x{:0{}X})", data, data, 1 * 2), data); } @@ -227,7 +225,7 @@ namespace hex { if (size == 0) return; - std::string displayString = pattern.getValue(m_provider, size); + std::string displayString = pattern.getValue(size); this->createDefaultEntry(pattern, hex::format("\"{0}\" {1}", displayString, size > pattern.getSize() ? "(truncated)" : ""), displayString); } @@ -290,12 +288,12 @@ namespace hex { } void PatternDrawer::visit(pl::PatternUnsigned& pattern) { - u128 data = pattern.getValue(m_provider); + u128 data = pattern.getValue(); this->createDefaultEntry(pattern, hex::format("{:d} (0x{:0{}X})", data, data, pattern.getSize() * 2), data); } void PatternDrawer::visit(pl::PatternWideCharacter& pattern) { - char16_t character = pattern.getValue(m_provider); + char16_t character = pattern.getValue(); u128 literal = character; auto str = std::wstring_convert, char16_t> {}.to_bytes(character); this->createDefaultEntry(pattern, hex::format("'{0}'", str), literal); @@ -307,7 +305,7 @@ namespace hex { if (size == 0) return; - std::string utf8String = pattern.getValue(m_provider, size); + std::string utf8String = pattern.getValue(size); this->createDefaultEntry(pattern, hex::format("\"{0}\" {1}", utf8String, size > pattern.getSize() ? "(truncated)" : ""), utf8String); } diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index a6c5bf64a..6cf9c3745 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -1,13 +1,12 @@ #include -#include - namespace hex::plugin::builtin { void registerViews(); void registerDataInspectorEntries(); void registerToolEntries(); void registerPatternLanguageFunctions(); + void registerPatternLanguagePragmas(); void registerCommandPaletteCommands(); void registerSettings(); void registerDataProcessorNodes(); @@ -42,6 +41,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { registerDataInspectorEntries(); registerToolEntries(); registerPatternLanguageFunctions(); + registerPatternLanguagePragmas(); registerCommandPaletteCommands(); registerSettings(); registerDataProcessorNodes(); diff --git a/tests/pattern_language/include/test_patterns/test_pattern_arrays.hpp b/tests/pattern_language/include/test_patterns/test_pattern_arrays.hpp index 150b1088e..d7b3eaab0 100644 --- a/tests/pattern_language/include/test_patterns/test_pattern_arrays.hpp +++ b/tests/pattern_language/include/test_patterns/test_pattern_arrays.hpp @@ -20,7 +20,7 @@ namespace hex::test { second->setEntries(create("u8", "", 0x4, sizeof(u8)), 4); auto testStruct = create("Signature", "sign", 0x0, sizeof(u8[8])); - std::vector> structMembers; + std::vector> structMembers; { structMembers.push_back(std::move(first)); structMembers.push_back(std::move(second)); diff --git a/tests/pattern_language/include/test_patterns/test_pattern_bitfields.hpp b/tests/pattern_language/include/test_patterns/test_pattern_bitfields.hpp index 85a3c1ef4..50751112d 100644 --- a/tests/pattern_language/include/test_patterns/test_pattern_bitfields.hpp +++ b/tests/pattern_language/include/test_patterns/test_pattern_bitfields.hpp @@ -12,7 +12,7 @@ namespace hex::test { auto testBitfield = create("TestBitfield", "testBitfield", 0x12, (4 * 4) / 8); testBitfield->setEndian(std::endian::big); - std::vector> bitfieldFields; + std::vector> bitfieldFields; { bitfieldFields.push_back(create("", "a", 0x12, 0, 4, testBitfield.get())); bitfieldFields.push_back(create("", "b", 0x12, 4, 4, testBitfield.get())); diff --git a/tests/pattern_language/include/test_patterns/test_pattern_nested_structs.hpp b/tests/pattern_language/include/test_patterns/test_pattern_nested_structs.hpp index cb034281f..0919a90d4 100644 --- a/tests/pattern_language/include/test_patterns/test_pattern_nested_structs.hpp +++ b/tests/pattern_language/include/test_patterns/test_pattern_nested_structs.hpp @@ -22,7 +22,7 @@ namespace hex::test { { auto hdr = create("Header", "hdr", HEADER_START, HEADER_SIZE); { - std::vector> hdrMembers { + std::vector> hdrMembers { std::shared_ptr(create("u8", "len", HEADER_START, sizeof(u8))) }; hdr->setMembers(std::move(hdrMembers)); @@ -32,13 +32,13 @@ namespace hex::test { { auto bodyArray = create("u8", "arr", BODY_START, BODY_SIZE); bodyArray->setEntries(create("u8", "", BODY_START, sizeof(u8)), BODY_SIZE); - std::vector> bodyMembers { + std::vector> bodyMembers { std::shared_ptr(std::move(bodyArray)) }; body->setMembers(std::move(bodyMembers)); } - std::vector> dataMembers { + std::vector> dataMembers { std::shared_ptr(std::move(hdr)), std::shared_ptr(std::move(body)) }; diff --git a/tests/pattern_language/include/test_patterns/test_pattern_padding.hpp b/tests/pattern_language/include/test_patterns/test_pattern_padding.hpp index b6a8d995f..9fb4d92bb 100644 --- a/tests/pattern_language/include/test_patterns/test_pattern_padding.hpp +++ b/tests/pattern_language/include/test_patterns/test_pattern_padding.hpp @@ -20,7 +20,7 @@ namespace hex::test { auto array = create("u8", "array", 0x100 + sizeof(i32) + 20, sizeof(u8[0x10])); array->setEntries(create("u8", "", 0x100 + sizeof(i32) + 20, sizeof(u8)), 0x10); - std::vector> structMembers; + std::vector> structMembers; { structMembers.push_back(std::move(variable)); structMembers.push_back(std::move(padding)); diff --git a/tests/pattern_language/include/test_patterns/test_pattern_structs.hpp b/tests/pattern_language/include/test_patterns/test_pattern_structs.hpp index 6517b17ec..4912ba947 100644 --- a/tests/pattern_language/include/test_patterns/test_pattern_structs.hpp +++ b/tests/pattern_language/include/test_patterns/test_pattern_structs.hpp @@ -18,7 +18,7 @@ namespace hex::test { auto array = create("u8", "array", 0x100 + sizeof(i32), sizeof(u8[0x10])); array->setEntries(create("u8", "", 0x100 + sizeof(i32), sizeof(u8)), 0x10); - std::vector> structMembers; + std::vector> structMembers; { structMembers.push_back(std::move(variable)); structMembers.push_back(std::move(array)); diff --git a/tests/pattern_language/include/test_patterns/test_pattern_unions.hpp b/tests/pattern_language/include/test_patterns/test_pattern_unions.hpp index 2c44cec7b..16b09f54c 100644 --- a/tests/pattern_language/include/test_patterns/test_pattern_unions.hpp +++ b/tests/pattern_language/include/test_patterns/test_pattern_unions.hpp @@ -18,7 +18,7 @@ namespace hex::test { array->setEntries(create("s32", "", 0x200, sizeof(i32)), 2); auto variable = create("u128", "variable", 0x200, sizeof(u128)); - std::vector> unionMembers; + std::vector> unionMembers; { unionMembers.push_back(std::move(array)); unionMembers.push_back(std::move(variable)); diff --git a/tests/pattern_language/source/main.cpp b/tests/pattern_language/source/main.cpp index 825ee752f..18fa6809e 100644 --- a/tests/pattern_language/source/main.cpp +++ b/tests/pattern_language/source/main.cpp @@ -18,8 +18,8 @@ using namespace hex::test; -static std::string format(hex::pl::Evaluator *ctx, const auto ¶ms) { - auto format = hex::pl::Token::literalToString(params[0], true); +static std::string format(pl::Evaluator *ctx, const auto ¶ms) { + auto format = pl::Token::literalToString(params[0], true); std::string message; fmt::dynamic_format_arg_store formatArgs; @@ -28,7 +28,7 @@ static std::string format(hex::pl::Evaluator *ctx, const auto ¶ms) { auto ¶m = params[i]; std::visit(hex::overloaded { - [&](hex::pl::Pattern *value) { + [&](pl::Pattern *value) { formatArgs.push_back(value->toString(ctx->getProvider())); }, [&](auto &&value) { @@ -40,7 +40,7 @@ static std::string format(hex::pl::Evaluator *ctx, const auto ¶ms) { try { return fmt::vformat(format, formatArgs); } catch (fmt::format_error &error) { - hex::pl::LogConsole::abortEvaluation(hex::format("format error: {}", error.what())); + pl::LogConsole::abortEvaluation(hex::format("format error: {}", error.what())); } } @@ -91,7 +91,7 @@ int test(int argc, char **argv) { return EXIT_FAILURE; } - hex::pl::PatternLanguage language; + pl::PatternLanguage language; // Check if compilation succeeded auto result = language.executeString(provider, testPatterns[testName]->getSourceCode());