From 368c943040888513d7207d6e376030e205426457 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 24 Mar 2022 20:31:45 +0100 Subject: [PATCH] patterns: Added default parameters --- .../include/hex/api/content_registry.hpp | 51 +++++++-- .../ast/ast_node_attribute.hpp | 10 +- .../ast/ast_node_function_call.hpp | 30 ++--- .../ast/ast_node_function_definition.hpp | 32 +++++- .../ast/ast_node_type_decl.hpp | 2 +- .../hex/pattern_language/evaluator.hpp | 4 +- lib/libimhex/source/api/content_registry.cpp | 8 +- .../source/pattern_language/evaluator.cpp | 4 +- .../source/pattern_language/parser.cpp | 12 +- .../pattern_language/pattern_language.cpp | 16 ++- .../source/content/pl_builtin_functions.cpp | 103 +++++++++--------- tests/pattern_language/source/main.cpp | 8 +- 12 files changed, 181 insertions(+), 99 deletions(-) diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index f4367cc54..49c32873d 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -124,23 +124,58 @@ namespace hex { } - constexpr static u32 UnlimitedParameters = 0xFFFF'FFFF; - constexpr static u32 MoreParametersThan = 0x8000'0000; - constexpr static u32 LessParametersThan = 0x4000'0000; - constexpr static u32 ExactlyOrMoreParametersThan = 0x2000'0000; - constexpr static u32 NoParameters = 0x0000'0000; + struct ParameterCount { + ParameterCount() = default; + + constexpr bool operator==(const ParameterCount &other) const { + return this->min == other.min && this->max == other.max; + } + + [[nodiscard]] static ParameterCount unlimited() { + return ParameterCount { 0, 0xFFFF'FFFF }; + } + + [[nodiscard]] static ParameterCount none() { + return ParameterCount { 0, 0 }; + } + + [[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 { - u32 parameterCount; + ParameterCount parameterCount; + std::vector defaultParameters; Callback func; bool dangerous; }; - void addFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func); - void addDangerousFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func); + 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(); 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 index 93d4dda91..017f6cac9 100644 --- a/lib/libimhex/include/hex/pattern_language/ast/ast_node_attribute.hpp +++ b/lib/libimhex/include/hex/pattern_language/ast/ast_node_attribute.hpp @@ -105,13 +105,15 @@ namespace hex::pl { 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 != 1) + if (function.parameterCount != ParameterCount::exactly(1)) LogConsole::abortEvaluation("formatter function needs exactly one parameter", node); pattern->setFormatterFunction(function); @@ -123,7 +125,7 @@ namespace hex::pl { LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node); const auto &function = functions[*value]; - if (function.parameterCount != 1) + if (function.parameterCount != ParameterCount::exactly(1)) LogConsole::abortEvaluation("formatter function needs exactly one parameter", node); auto array = dynamic_cast(pattern); @@ -141,7 +143,7 @@ namespace hex::pl { LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node); const auto &function = functions[*value]; - if (function.parameterCount != 1) + if (function.parameterCount != ParameterCount::exactly(1)) LogConsole::abortEvaluation("transform function needs exactly one parameter", node); pattern->setTransformFunction(function); @@ -153,7 +155,7 @@ namespace hex::pl { LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node); const auto &function = functions[*value]; - if (function.parameterCount != 1) + if (function.parameterCount != ParameterCount::exactly(1)) LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node); if (auto pointerPattern = dynamic_cast(pattern)) { 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 index a3a32ec38..a12019f2d 100644 --- 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 @@ -71,22 +71,26 @@ namespace hex::pl { LogConsole::abortEvaluation(hex::format("call to unknown function '{}'", this->m_functionName), this); } + using namespace ContentRegistry::PatternLanguage; + auto function = functions[this->m_functionName]; - if (function.parameterCount == ContentRegistry::PatternLanguage::UnlimitedParameters) { - ; // Don't check parameter count - } else if (function.parameterCount & ContentRegistry::PatternLanguage::LessParametersThan) { - if (evaluatedParams.size() >= (function.parameterCount & ~ContentRegistry::PatternLanguage::LessParametersThan)) - LogConsole::abortEvaluation(hex::format("too many parameters for function '{0}'. Expected less than {1}", this->m_functionName, function.parameterCount & ~ContentRegistry::PatternLanguage::LessParametersThan), this); - } else if (function.parameterCount & ContentRegistry::PatternLanguage::MoreParametersThan) { - if (evaluatedParams.size() <= (function.parameterCount & ~ContentRegistry::PatternLanguage::MoreParametersThan)) - LogConsole::abortEvaluation(hex::format("too few parameters for function '{0}'. Expected more than {1}", this->m_functionName, function.parameterCount & ~ContentRegistry::PatternLanguage::MoreParametersThan), this); - } else if (function.parameterCount & ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan) { - if (evaluatedParams.size() < (function.parameterCount & ~ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan)) - LogConsole::abortEvaluation(hex::format("too few parameters for function '{0}'. Expected more than {1}", this->m_functionName, (function.parameterCount - 1) & ~ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan), this); - } else if (function.parameterCount != evaluatedParams.size()) { - LogConsole::abortEvaluation(hex::format("invalid number of parameters for function '{0}'. Expected {1}", this->m_functionName, function.parameterCount), this); + const auto &[min, max] = function.parameterCount; + + if (evaluatedParams.size() >= min && evaluatedParams.size() < max && evaluatedParams.size() + function.defaultParameters.size() >= max) { + while (true) { + auto remainingParams = max - evaluatedParams.size(); + if (remainingParams <= 0) break; + + auto offset = evaluatedParams.size() - min; + evaluatedParams.push_back(function.defaultParameters[offset]); + } } + if (evaluatedParams.size() < min) + LogConsole::abortEvaluation(hex::format("too many parameters for function '{0}'. Expected {1} at least", this->m_functionName, min), this); + else if (evaluatedParams.size() > max) + LogConsole::abortEvaluation(hex::format("too few parameters for function '{0}'. Expected {1} at most", this->m_functionName, max), this); + try { if (function.dangerous && evaluator->getDangerousFunctionPermission() != DangerousFunctionPermission::Allow) { evaluator->dangerousFunctionCalled(); 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 index cc275b786..bc544fbc6 100644 --- 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 @@ -6,12 +6,13 @@ namespace hex::pl { class ASTNodeFunctionDefinition : public ASTNode { public: - ASTNodeFunctionDefinition(std::string name, std::vector>> &¶ms, std::vector> &&body, std::optional parameterPack) - : m_name(std::move(name)), m_params(std::move(params)), m_body(std::move(body)), m_parameterPack(std::move(parameterPack)) { + 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()); @@ -20,6 +21,10 @@ namespace hex::pl { 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 { @@ -39,13 +44,29 @@ namespace hex::pl { } [[nodiscard]] std::unique_ptr evaluate(Evaluator *evaluator) const override { + using namespace ContentRegistry::PatternLanguage; - size_t paramCount = this->m_params.size(); + ParameterCount paramCount; if (this->m_parameterPack.has_value()) - paramCount |= ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan; + 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()); - evaluator->addCustomFunction(this->m_name, paramCount, [this](Evaluator *ctx, const std::vector ¶ms) -> std::optional { + 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(); @@ -100,6 +121,7 @@ namespace hex::pl { 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_type_decl.hpp b/lib/libimhex/include/hex/pattern_language/ast/ast_node_type_decl.hpp index 9922eddd8..984d3478e 100644 --- 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 @@ -8,7 +8,7 @@ namespace hex::pl { class ASTNodeTypeDecl : public ASTNode, public Attributable { public: - ASTNodeTypeDecl(std::string name) : m_forwardDeclared(true), m_name(std::move(name)) { } + 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) { } diff --git a/lib/libimhex/include/hex/pattern_language/evaluator.hpp b/lib/libimhex/include/hex/pattern_language/evaluator.hpp index 59e628fb6..ec1603853 100644 --- a/lib/libimhex/include/hex/pattern_language/evaluator.hpp +++ b/lib/libimhex/include/hex/pattern_language/evaluator.hpp @@ -177,9 +177,9 @@ namespace hex::pl { u64 &dataOffset() { return this->m_currOffset; } - bool addCustomFunction(const std::string &name, u32 numParams, const ContentRegistry::PatternLanguage::Callback &function) { + 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, function} + name, {numParams, std::move(defaultParameters), function} }); return inserted; diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index 993880427..b6141e6f6 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -230,16 +230,16 @@ namespace hex { return functionName; } - void addFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func) { + void addFunction(const Namespace &ns, const std::string &name, ParameterCount parameterCount, const Callback &func) { log::info("Registered new pattern language function: {}", getFunctionName(ns, name)); - getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, func, false }; + getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, { }, func, false }; } - void addDangerousFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func) { + void addDangerousFunction(const Namespace &ns, const std::string &name, ParameterCount parameterCount, const Callback &func) { log::info("Registered new dangerous pattern language function: {}", getFunctionName(ns, name)); - getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, func, true }; + getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, { }, func, true }; } std::map &getFunctions() { diff --git a/lib/libimhex/source/pattern_language/evaluator.cpp b/lib/libimhex/source/pattern_language/evaluator.cpp index 79034ad83..81246bb45 100644 --- a/lib/libimhex/source/pattern_language/evaluator.cpp +++ b/lib/libimhex/source/pattern_language/evaluator.cpp @@ -217,14 +217,12 @@ namespace hex::pl { if (this->m_customFunctions.contains("main")) { auto mainFunction = this->m_customFunctions["main"]; - if (mainFunction.parameterCount > 0) + if (mainFunction.parameterCount.max > 0) LogConsole::abortEvaluation("main function may not accept any arguments"); this->m_mainResult = mainFunction.func(this, {}); } } catch (PatternLanguageError &error) { - this->m_console.log(LogConsole::Level::Error, error.what()); - if (error.getLineNumber() != 0) this->m_console.setHardError(error); diff --git a/lib/libimhex/source/pattern_language/parser.cpp b/lib/libimhex/source/pattern_language/parser.cpp index 99413737e..49ac9a548 100644 --- a/lib/libimhex/source/pattern_language/parser.cpp +++ b/lib/libimhex/source/pattern_language/parser.cpp @@ -406,6 +406,8 @@ namespace hex::pl { // 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(); @@ -424,6 +426,14 @@ namespace hex::pl { 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; } @@ -444,7 +454,7 @@ namespace hex::pl { body.push_back(this->parseFunctionStatement()); } - return create(new ASTNodeFunctionDefinition(getNamespacePrefixedName(functionName), std::move(params), std::move(body), parameterPack)); + return create(new ASTNodeFunctionDefinition(getNamespacePrefixedName(functionName), std::move(params), std::move(body), parameterPack, std::move(defaultParameters))); } std::unique_ptr Parser::parseFunctionVariableDecl() { diff --git a/lib/libimhex/source/pattern_language/pattern_language.cpp b/lib/libimhex/source/pattern_language/pattern_language.cpp index 2bf252a32..1aab9b944 100644 --- a/lib/libimhex/source/pattern_language/pattern_language.cpp +++ b/lib/libimhex/source/pattern_language/pattern_language.cpp @@ -136,6 +136,17 @@ namespace hex::pl { 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); @@ -170,10 +181,7 @@ namespace hex::pl { auto returnCode = Token::literalToSigned(*mainResult); if (returnCode != 0) { - auto errorMessage = hex::format("non-success value returned from main: {}", returnCode); - - this->m_evaluator->getConsole().log(LogConsole::Level::Error, errorMessage); - this->m_currError = PatternLanguageError(0, errorMessage); + this->m_currError = PatternLanguageError(0, hex::format("non-success value returned from main: {}", returnCode)); return false; } diff --git a/plugins/builtin/source/content/pl_builtin_functions.cpp b/plugins/builtin/source/content/pl_builtin_functions.cpp index c52dabc2a..3c16b4552 100644 --- a/plugins/builtin/source/content/pl_builtin_functions.cpp +++ b/plugins/builtin/source/content/pl_builtin_functions.cpp @@ -43,25 +43,26 @@ namespace hex::plugin::builtin { void registerPatternLanguageFunctions() { using namespace hex::pl; + using ParameterCount = ContentRegistry::PatternLanguage::ParameterCount; ContentRegistry::PatternLanguage::addColorPalette("hex.builtin.palette.pastel", { 0x70B4771F, 0x700E7FFF, 0x702CA02C, 0x702827D6, 0x70BD6794, 0x704B568C, 0x70C277E3, 0x707F7F7F, 0x7022BDBC, 0x70CFBE17 }); ContentRegistry::PatternLanguage::Namespace nsStd = { "builtin", "std" }; { /* print(format, args...) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "print", ContentRegistry::PatternLanguage::MoreParametersThan | 0, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "print", ParameterCount::moreThan(0), [](Evaluator *ctx, auto params) -> std::optional { ctx->getConsole().log(LogConsole::Level::Info, format(ctx, params)); return std::nullopt; }); /* format(format, args...) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "format", ContentRegistry::PatternLanguage::MoreParametersThan | 0, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "format", ParameterCount::moreThan(0), [](Evaluator *ctx, auto params) -> std::optional { return format(ctx, params); }); /* env(name) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "env", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "env", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { auto name = Token::literalToString(params[0], false); auto env = ctx->getEnvVariable(name); @@ -74,19 +75,19 @@ namespace hex::plugin::builtin { }); /* pack_size(...) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "sizeof_pack", 0 | ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "sizeof_pack", ParameterCount::atLeast(0), [](Evaluator *ctx, auto params) -> std::optional { return u128(params.size()); }); /* error(message) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "error", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "error", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { LogConsole::abortEvaluation(Token::literalToString(params[0], true)); return std::nullopt; }); /* warning(message) */ - ContentRegistry::PatternLanguage::addFunction(nsStd, "warning", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStd, "warning", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { ctx->getConsole().log(LogConsole::Level::Warning, Token::literalToString(params[0], true)); return std::nullopt; @@ -97,17 +98,17 @@ namespace hex::plugin::builtin { { /* base_address() */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "base_address", ContentRegistry::PatternLanguage::NoParameters, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "base_address", ParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional { return u128(ctx->getProvider()->getBaseAddress()); }); /* size() */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "size", ContentRegistry::PatternLanguage::NoParameters, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "size", ParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional { return u128(ctx->getProvider()->getActualSize()); }); /* find_sequence_in_range(occurrence_index, start_offset, end_offset, bytes...) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "find_sequence_in_range", ContentRegistry::PatternLanguage::MoreParametersThan | 3, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "find_sequence_in_range", ParameterCount::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]); @@ -143,7 +144,7 @@ namespace hex::plugin::builtin { }); /* read_unsigned(address, size) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_unsigned", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_unsigned", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { auto address = Token::literalToUnsigned(params[0]); auto size = Token::literalToUnsigned(params[1]); @@ -157,7 +158,7 @@ namespace hex::plugin::builtin { }); /* read_signed(address, size) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_signed", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_signed", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { auto address = Token::literalToUnsigned(params[0]); auto size = Token::literalToUnsigned(params[1]); @@ -170,7 +171,7 @@ namespace hex::plugin::builtin { }); /* read_string(address, size) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_string", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_string", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { auto address = Token::literalToUnsigned(params[0]); auto size = Token::literalToUnsigned(params[1]); @@ -184,14 +185,14 @@ namespace hex::plugin::builtin { ContentRegistry::PatternLanguage::Namespace nsStdString = { "builtin", "std", "string" }; { /* length(string) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "length", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "length", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); return u128(string.length()); }); /* at(string, index) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "at", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "at", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); auto index = Token::literalToSigned(params[1]); @@ -212,7 +213,7 @@ namespace hex::plugin::builtin { }); /* substr(string, pos, count) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "substr", 3, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "substr", ParameterCount::exactly(3), [](Evaluator *ctx, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); auto pos = Token::literalToUnsigned(params[1]); auto size = Token::literalToUnsigned(params[2]); @@ -224,7 +225,7 @@ namespace hex::plugin::builtin { }); /* parse_int(string, base) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_int", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_int", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); auto base = Token::literalToUnsigned(params[1]); @@ -232,7 +233,7 @@ namespace hex::plugin::builtin { }); /* parse_float(string) */ - ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_float", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_float", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { auto string = Token::literalToString(params[0], false); return double(std::strtod(string.c_str(), nullptr)); @@ -242,7 +243,7 @@ namespace hex::plugin::builtin { ContentRegistry::PatternLanguage::Namespace nsStdHttp = { "builtin", "std", "http" }; { /* get(url) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdHttp, "get", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdHttp, "get", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { const auto url = Token::literalToString(params[0], false); hex::Net net; @@ -257,7 +258,7 @@ namespace hex::plugin::builtin { static std::map openFiles; /* open(path, mode) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "open", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "open", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { const auto path = Token::literalToString(params[0], false); const auto modeEnum = Token::literalToUnsigned(params[1]); @@ -288,7 +289,7 @@ namespace hex::plugin::builtin { }); /* close(file) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "close", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "close", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); if (!openFiles.contains(file)) @@ -300,7 +301,7 @@ namespace hex::plugin::builtin { }); /* read(file, size) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "read", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "read", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); const auto size = Token::literalToUnsigned(params[1]); @@ -311,7 +312,7 @@ namespace hex::plugin::builtin { }); /* write(file, data) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "write", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "write", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); const auto data = Token::literalToString(params[1], true); @@ -324,7 +325,7 @@ namespace hex::plugin::builtin { }); /* seek(file, offset) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "seek", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "seek", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); const auto offset = Token::literalToUnsigned(params[1]); @@ -337,7 +338,7 @@ namespace hex::plugin::builtin { }); /* size(file) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "size", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "size", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); if (!openFiles.contains(file)) @@ -347,7 +348,7 @@ namespace hex::plugin::builtin { }); /* resize(file, size) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "resize", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "resize", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); const auto size = Token::literalToUnsigned(params[1]); @@ -360,7 +361,7 @@ namespace hex::plugin::builtin { }); /* flush(file) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "flush", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "flush", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); if (!openFiles.contains(file)) @@ -372,7 +373,7 @@ namespace hex::plugin::builtin { }); /* remove(file) */ - ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "remove", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "remove", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { const auto file = Token::literalToUnsigned(params[0]); if (!openFiles.contains(file)) @@ -388,126 +389,126 @@ namespace hex::plugin::builtin { ContentRegistry::PatternLanguage::Namespace nsStdMath = { "builtin", "std", "math" }; { /* floor(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "floor", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "floor", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::floor(Token::literalToFloatingPoint(params[0])); }); /* ceil(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ceil", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ceil", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::ceil(Token::literalToFloatingPoint(params[0])); }); /* round(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "round", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "round", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::round(Token::literalToFloatingPoint(params[0])); }); /* trunc(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "trunc", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "trunc", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::trunc(Token::literalToFloatingPoint(params[0])); }); /* log10(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log10", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log10", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::log10(Token::literalToFloatingPoint(params[0])); }); /* log2(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log2", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log2", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::log2(Token::literalToFloatingPoint(params[0])); }); /* ln(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ln", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ln", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::log(Token::literalToFloatingPoint(params[0])); }); /* fmod(x, y) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "fmod", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "fmod", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { return std::fmod(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1])); }); /* pow(base, exp) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "pow", 2, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "pow", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional { return std::pow(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1])); }); /* sqrt(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sqrt", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sqrt", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::sqrt(Token::literalToFloatingPoint(params[0])); }); /* cbrt(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cbrt", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cbrt", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::cbrt(Token::literalToFloatingPoint(params[0])); }); /* sin(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sin", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sin", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::sin(Token::literalToFloatingPoint(params[0])); }); /* cos(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cos", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cos", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::cos(Token::literalToFloatingPoint(params[0])); }); /* tan(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tan", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tan", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::tan(Token::literalToFloatingPoint(params[0])); }); /* asin(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asin", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asin", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::asin(Token::literalToFloatingPoint(params[0])); }); /* acos(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acos", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acos", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::acos(Token::literalToFloatingPoint(params[0])); }); /* atan(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::atan(Token::literalToFloatingPoint(params[0])); }); /* atan2(y, x) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::atan2(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1])); }); /* sinh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sinh", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sinh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::sinh(Token::literalToFloatingPoint(params[0])); }); /* cosh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cosh", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cosh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::cosh(Token::literalToFloatingPoint(params[0])); }); /* tanh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tanh", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tanh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::tanh(Token::literalToFloatingPoint(params[0])); }); /* asinh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asinh", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asinh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::asinh(Token::literalToFloatingPoint(params[0])); }); /* acosh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acosh", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acosh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::acosh(Token::literalToFloatingPoint(params[0])); }); /* atanh(value) */ - ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atanh", 1, [](Evaluator *ctx, auto params) -> std::optional { + ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atanh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional { return std::atanh(Token::literalToFloatingPoint(params[0])); }); } diff --git a/tests/pattern_language/source/main.cpp b/tests/pattern_language/source/main.cpp index 066871971..825ee752f 100644 --- a/tests/pattern_language/source/main.cpp +++ b/tests/pattern_language/source/main.cpp @@ -45,8 +45,10 @@ static std::string format(hex::pl::Evaluator *ctx, const auto ¶ms) { } void addFunctions() { - hex::ContentRegistry::PatternLanguage::Namespace nsStd = { "std" }; - hex::ContentRegistry::PatternLanguage::addFunction(nsStd, "assert", 2, [](Evaluator *ctx, auto params) -> Token::Literal { + using namespace hex::ContentRegistry::PatternLanguage; + + Namespace nsStd = { "std" }; + hex::ContentRegistry::PatternLanguage::addFunction(nsStd, "assert", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> Token::Literal { auto condition = Token::literalToBoolean(params[0]); auto message = Token::literalToString(params[1], false); @@ -56,7 +58,7 @@ void addFunctions() { return {}; }); - hex::ContentRegistry::PatternLanguage::addFunction(nsStd, "print", hex::ContentRegistry::PatternLanguage::MoreParametersThan | 0, [](Evaluator *ctx, auto params) -> std::optional { + hex::ContentRegistry::PatternLanguage::addFunction(nsStd, "print", ParameterCount::atLeast(1), [](Evaluator *ctx, auto params) -> std::optional { ctx->getConsole().log(LogConsole::Level::Info, format(ctx, params)); return std::nullopt;