From d0aec62997965bee653f5c8cbc223ec219b010cc Mon Sep 17 00:00:00 2001 From: WerWolv Date: Fri, 27 Aug 2021 09:56:20 +0200 Subject: [PATCH] patterns: Move builtin functions to namespace. Add string functions --- .../source/content/lang_builtin_functions.cpp | 284 ++++++++++-------- .../include/hex/api/content_registry.hpp | 4 +- .../libimhex/source/api/content_registry.cpp | 11 +- source/views/view_pattern.cpp | 5 +- 4 files changed, 171 insertions(+), 133 deletions(-) diff --git a/plugins/builtin/source/content/lang_builtin_functions.cpp b/plugins/builtin/source/content/lang_builtin_functions.cpp index e063344f2..940a0c19a 100644 --- a/plugins/builtin/source/content/lang_builtin_functions.cpp +++ b/plugins/builtin/source/content/lang_builtin_functions.cpp @@ -16,158 +16,190 @@ namespace hex::plugin::builtin { void registerPatternLanguageFunctions() { using namespace hex::lang; - /* findSequence(occurrenceIndex, byte...) */ - ContentRegistry::PatternLanguageFunctions::add("findSequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [](auto &ctx, auto params) { - auto& occurrenceIndex = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); - std::vector sequence; - for (u32 i = 1; i < params.size(); i++) { - sequence.push_back(std::visit([&](auto &&value) -> u8 { - if (value <= 0xFF) - return value; - else - ctx.getConsole().abortEvaluation("sequence bytes need to fit into 1 byte"); - }, AS_TYPE(ASTNodeIntegerLiteral, params[i])->getValue())); - } - - std::vector bytes(sequence.size(), 0x00); - u32 occurrences = 0; - for (u64 offset = 0; offset < SharedData::currentProvider->getSize() - sequence.size(); offset++) { - SharedData::currentProvider->read(offset, bytes.data(), bytes.size()); - - if (bytes == sequence) { - if (LITERAL_COMPARE(occurrenceIndex, occurrences < occurrenceIndex)) { - occurrences++; - continue; - } - - return new ASTNodeIntegerLiteral(offset); + ContentRegistry::PatternLanguageFunctions::Namespace nsStd = { "std" }; + { + /* findSequence(occurrenceIndex, byte...) */ + ContentRegistry::PatternLanguageFunctions::add(nsStd, "findSequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [](auto &ctx, auto params) { + auto& occurrenceIndex = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); + std::vector sequence; + for (u32 i = 1; i < params.size(); i++) { + sequence.push_back(std::visit([&](auto &&value) -> u8 { + if (value <= 0xFF) + return value; + else + ctx.getConsole().abortEvaluation("sequence bytes need to fit into 1 byte"); + }, AS_TYPE(ASTNodeIntegerLiteral, params[i])->getValue())); } - } - ctx.getConsole().abortEvaluation("failed to find sequence"); - }); + std::vector bytes(sequence.size(), 0x00); + u32 occurrences = 0; + for (u64 offset = 0; offset < SharedData::currentProvider->getSize() - sequence.size(); offset++) { + SharedData::currentProvider->read(offset, bytes.data(), bytes.size()); - /* readUnsigned(address, size) */ - ContentRegistry::PatternLanguageFunctions::add("readUnsigned", 2, [](auto &ctx, auto params) { - auto address = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); - auto size = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue(); + if (bytes == sequence) { + if (LITERAL_COMPARE(occurrenceIndex, occurrences < occurrenceIndex)) { + occurrences++; + continue; + } - if (LITERAL_COMPARE(address, address >= SharedData::currentProvider->getActualSize())) - ctx.getConsole().abortEvaluation("address out of range"); + return new ASTNodeIntegerLiteral(offset); + } + } - return std::visit([&](auto &&address, auto &&size) { - if (size <= 0 || size > 16) - ctx.getConsole().abortEvaluation("invalid read size"); + ctx.getConsole().abortEvaluation("failed to find sequence"); + }); - u8 value[(u8)size]; - SharedData::currentProvider->read(address, value, size); + /* readUnsigned(address, size) */ + ContentRegistry::PatternLanguageFunctions::add(nsStd, "readUnsigned", 2, [](auto &ctx, auto params) { + auto address = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); + auto size = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue(); - switch ((u8)size) { - case 1: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - default: ctx.getConsole().abortEvaluation("invalid read size"); - } - }, address, size); - }); + if (LITERAL_COMPARE(address, address >= SharedData::currentProvider->getActualSize())) + ctx.getConsole().abortEvaluation("address out of range"); - /* readSigned(address, size) */ - ContentRegistry::PatternLanguageFunctions::add("readSigned", 2, [](auto &ctx, auto params) { - auto address = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); - auto size = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue(); + return std::visit([&](auto &&address, auto &&size) { + if (size <= 0 || size > 16) + ctx.getConsole().abortEvaluation("invalid read size"); - if (LITERAL_COMPARE(address, address >= SharedData::currentProvider->getActualSize())) - ctx.getConsole().abortEvaluation("address out of range"); + u8 value[(u8)size]; + SharedData::currentProvider->read(address, value, size); - return std::visit([&](auto &&address, auto &&size) { - if (size <= 0 || size > 16) - ctx.getConsole().abortEvaluation("invalid read size"); + switch ((u8)size) { + case 1: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + default: ctx.getConsole().abortEvaluation("invalid read size"); + } + }, address, size); + }); - u8 value[(u8)size]; - SharedData::currentProvider->read(address, value, size); + /* readSigned(address, size) */ + ContentRegistry::PatternLanguageFunctions::add(nsStd, "readSigned", 2, [](auto &ctx, auto params) { + auto address = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); + auto size = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue(); - switch ((u8)size) { - case 1: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); - default: ctx.getConsole().abortEvaluation("invalid read size"); - } - }, address, size); - }); + if (LITERAL_COMPARE(address, address >= SharedData::currentProvider->getActualSize())) + ctx.getConsole().abortEvaluation("address out of range"); - /* assert(condition, message) */ - ContentRegistry::PatternLanguageFunctions::add("assert", 2, [](auto &ctx, auto params) { - auto condition = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); - auto message = AS_TYPE(ASTNodeStringLiteral, params[1])->getString(); + return std::visit([&](auto &&address, auto &&size) { + if (size <= 0 || size > 16) + ctx.getConsole().abortEvaluation("invalid read size"); - if (LITERAL_COMPARE(condition, condition == 0)) - ctx.getConsole().abortEvaluation(hex::format("assert failed \"{0}\"", message.data())); + u8 value[(u8)size]; + SharedData::currentProvider->read(address, value, size); - return nullptr; - }); + switch ((u8)size) { + case 1: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast(value)); + default: ctx.getConsole().abortEvaluation("invalid read size"); + } + }, address, size); + }); - /* warnAssert(condition, message) */ - ContentRegistry::PatternLanguageFunctions::add("warnAssert", 2, [](auto ctx, auto params) { - auto condition = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); - auto message = AS_TYPE(ASTNodeStringLiteral, params[1])->getString(); + /* assert(condition, message) */ + ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](auto &ctx, auto params) { + auto condition = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); + auto message = AS_TYPE(ASTNodeStringLiteral, params[1])->getString(); - if (LITERAL_COMPARE(condition, condition == 0)) - ctx.getConsole().log(LogConsole::Level::Warning, hex::format("assert failed \"{0}\"", message)); + if (LITERAL_COMPARE(condition, condition == 0)) + ctx.getConsole().abortEvaluation(hex::format("assert failed \"{0}\"", message.data())); - return nullptr; - }); + return nullptr; + }); - /* print(values...) */ - ContentRegistry::PatternLanguageFunctions::add("print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](auto &ctx, auto params) { - std::string message; - for (auto& param : params) { - if (auto integerLiteral = dynamic_cast(param); integerLiteral != nullptr) { - std::visit([&](auto &&value) { - using Type = std::remove_cvref_t; - if constexpr (std::is_same_v) - message += (char)value; - else if constexpr (std::is_same_v) - message += value == 0 ? "false" : "true"; - else if constexpr (std::is_unsigned_v) - message += std::to_string(static_cast(value)); - else if constexpr (std::is_signed_v) - message += std::to_string(static_cast(value)); - else if constexpr (std::is_floating_point_v) - message += std::to_string(value); - else - message += "< Custom Type >"; - }, integerLiteral->getValue()); + /* warnAssert(condition, message) */ + ContentRegistry::PatternLanguageFunctions::add(nsStd, "warnAssert", 2, [](auto ctx, auto params) { + auto condition = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); + auto message = AS_TYPE(ASTNodeStringLiteral, params[1])->getString(); + + if (LITERAL_COMPARE(condition, condition == 0)) + ctx.getConsole().log(LogConsole::Level::Warning, hex::format("assert failed \"{0}\"", message)); + + return nullptr; + }); + + /* print(values...) */ + ContentRegistry::PatternLanguageFunctions::add(nsStd, "print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](auto &ctx, auto params) { + std::string message; + for (auto& param : params) { + if (auto integerLiteral = dynamic_cast(param); integerLiteral != nullptr) { + std::visit([&](auto &&value) { + using Type = std::remove_cvref_t; + if constexpr (std::is_same_v) + message += (char)value; + else if constexpr (std::is_same_v) + message += value == 0 ? "false" : "true"; + else if constexpr (std::is_unsigned_v) + message += std::to_string(static_cast(value)); + else if constexpr (std::is_signed_v) + message += std::to_string(static_cast(value)); + else if constexpr (std::is_floating_point_v) + message += std::to_string(value); + else + message += "< Custom Type >"; + }, integerLiteral->getValue()); + } + else if (auto stringLiteral = dynamic_cast(param); stringLiteral != nullptr) + message += stringLiteral->getString(); } - else if (auto stringLiteral = dynamic_cast(param); stringLiteral != nullptr) - message += stringLiteral->getString(); - } - ctx.getConsole().log(LogConsole::Level::Info, message); + ctx.getConsole().log(LogConsole::Level::Info, message); - return nullptr; - }); + return nullptr; + }); - /* alignTo(alignment, value) */ - ContentRegistry::PatternLanguageFunctions::add("alignTo", 2, [](auto &ctx, auto params) -> ASTNode* { - auto alignment = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); - auto value = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue(); + /* alignTo(alignment, value) */ + ContentRegistry::PatternLanguageFunctions::add(nsStd, "alignTo", 2, [](auto &ctx, auto params) -> ASTNode* { + auto alignment = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue(); + auto value = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue(); - auto result = std::visit([](auto &&alignment, auto &&value) { - u64 remainder = u64(value) % u64(alignment); - return remainder != 0 ? u64(value) + (u64(alignment) - remainder) : u64(value); - }, alignment, value); + auto result = std::visit([](auto &&alignment, auto &&value) { + u64 remainder = u64(value) % u64(alignment); + return remainder != 0 ? u64(value) + (u64(alignment) - remainder) : u64(value); + }, alignment, value); - return new ASTNodeIntegerLiteral(u64(result)); - }); + return new ASTNodeIntegerLiteral(u64(result)); + }); - /* dataSize() */ - ContentRegistry::PatternLanguageFunctions::add("dataSize", ContentRegistry::PatternLanguageFunctions::NoParameters, [](auto &ctx, auto params) -> ASTNode* { - return new ASTNodeIntegerLiteral(u64(SharedData::currentProvider->getActualSize())); - }); + /* dataSize() */ + ContentRegistry::PatternLanguageFunctions::add(nsStd, "dataSize", ContentRegistry::PatternLanguageFunctions::NoParameters, [](auto &ctx, auto params) -> ASTNode* { + return new ASTNodeIntegerLiteral(u64(SharedData::currentProvider->getActualSize())); + }); + } + + ContentRegistry::PatternLanguageFunctions::Namespace nsStdStr = { "std", "str" }; + { + /* length(string) */ + ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "length", 1, [](auto &ctx, auto params) { + auto string = AS_TYPE(ASTNodeStringLiteral, params[1])->getString(); + + return new ASTNodeIntegerLiteral(u32(string.length())); + }); + + /* at(string, index) */ + ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "at", 2, [](auto &ctx, auto params) { + auto string = AS_TYPE(ASTNodeStringLiteral, params[0])->getString(); + auto index = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue(); + + if (LITERAL_COMPARE(index, index >= string.length() || index < 0)) + ctx.getConsole().abortEvaluation("character index out of bounds"); + + return std::visit([&](auto &&value) { return new ASTNodeIntegerLiteral(char(string[u32(value)])); }, index); + }); + + /* compare(left, right) */ + ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "compare", 2, [](auto &ctx, auto params) { + auto left = AS_TYPE(ASTNodeStringLiteral, params[0])->getString(); + auto right = AS_TYPE(ASTNodeStringLiteral, params[1])->getString(); + + return new ASTNodeIntegerLiteral(bool(left == right)); + }); + } } } \ No newline at end of file diff --git a/plugins/libimhex/include/hex/api/content_registry.hpp b/plugins/libimhex/include/hex/api/content_registry.hpp index 4fc18e558..bee234c60 100644 --- a/plugins/libimhex/include/hex/api/content_registry.hpp +++ b/plugins/libimhex/include/hex/api/content_registry.hpp @@ -85,12 +85,14 @@ namespace hex { constexpr static u32 LessParametersThan = 0x4000'0000; constexpr static u32 NoParameters = 0x0000'0000; + using Namespace = std::vector; + struct Function { u32 parameterCount; std::function&)> func; }; - static void add(std::string_view name, u32 parameterCount, const std::function&)> &func); + static void add(const Namespace &ns, const std::string &name, u32 parameterCount, const std::function&)> &func); static std::map& getEntries(); }; diff --git a/plugins/libimhex/source/api/content_registry.cpp b/plugins/libimhex/source/api/content_registry.cpp index d2301cb20..b952f111d 100644 --- a/plugins/libimhex/source/api/content_registry.cpp +++ b/plugins/libimhex/source/api/content_registry.cpp @@ -151,8 +151,15 @@ namespace hex { /* Pattern Language Functions */ - void ContentRegistry::PatternLanguageFunctions::add(std::string_view name, u32 parameterCount, const std::function&)> &func) { - getEntries()[name.data()] = Function{ parameterCount, func }; + + void ContentRegistry::PatternLanguageFunctions::add(const Namespace &ns, const std::string &name, u32 parameterCount, const std::function&)> &func) { + std::string functionName; + for (auto &scope : ns) + functionName += scope + "::"; + + functionName += name; + + getEntries()[functionName] = Function { parameterCount, func }; } std::map& ContentRegistry::PatternLanguageFunctions::getEntries() { diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 0007513f8..9bd26f35d 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -45,10 +45,7 @@ namespace hex { paletteIndex = TextEditor::PaletteIndex::Default; } else if (TokenizeCStyleIdentifier(inBegin, inEnd, outBegin, outEnd)) { - if (SharedData::patternLanguageFunctions.contains(std::string(outBegin, outEnd - outBegin))) - paletteIndex = TextEditor::PaletteIndex::LineNumber; - else - paletteIndex = TextEditor::PaletteIndex::Identifier; + paletteIndex = TextEditor::PaletteIndex::Identifier; } else if (TokenizeCStyleNumber(inBegin, inEnd, outBegin, outEnd)) paletteIndex = TextEditor::PaletteIndex::Number;