1
0
mirror of synced 2024-11-28 01:20:51 +01:00

patterns: Added default parameters

This commit is contained in:
WerWolv 2022-03-24 20:31:45 +01:00
parent a16e387dff
commit 368c943040
12 changed files with 181 additions and 99 deletions

View File

@ -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>(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<std::string>;
using Callback = std::function<std::optional<hex::pl::Token::Literal>(hex::pl::Evaluator *, const std::vector<hex::pl::Token::Literal> &)>;
struct Function {
u32 parameterCount;
ParameterCount parameterCount;
std::vector<pl::Token::Literal> 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<std::string, ContentRegistry::PatternLanguage::Function> &getFunctions();
std::vector<impl::ColorPalette> &getPalettes();

View File

@ -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<PatternArrayDynamic *>(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<PatternPointer *>(pattern)) {

View File

@ -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();

View File

@ -6,12 +6,13 @@ namespace hex::pl {
class ASTNodeFunctionDefinition : public ASTNode {
public:
ASTNodeFunctionDefinition(std::string name, std::vector<std::pair<std::string, std::unique_ptr<ASTNode>>> &&params, std::vector<std::unique_ptr<ASTNode>> &&body, std::optional<std::string> 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<std::pair<std::string, std::unique_ptr<ASTNode>>> &&params, std::vector<std::unique_ptr<ASTNode>> &&body, std::optional<std::string> parameterPack, std::vector<std::unique_ptr<ASTNode>> &&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<ASTNode> clone() const override {
@ -39,13 +44,29 @@ namespace hex::pl {
}
[[nodiscard]] std::unique_ptr<ASTNode> 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<Token::Literal> &params) -> std::optional<Token::Literal> {
std::vector<Token::Literal> evaluatedDefaultParams;
for (const auto &param : this->m_defaultParameters) {
const auto expression = param->evaluate(evaluator)->evaluate(evaluator);
if (auto literal = dynamic_cast<ASTNodeLiteral *>(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<Token::Literal> &params) -> std::optional<Token::Literal> {
std::vector<std::shared_ptr<Pattern>> variables;
auto startOffset = ctx->dataOffset();
@ -100,6 +121,7 @@ namespace hex::pl {
std::vector<std::pair<std::string, std::unique_ptr<ASTNode>>> m_params;
std::vector<std::unique_ptr<ASTNode>> m_body;
std::optional<std::string> m_parameterPack;
std::vector<std::unique_ptr<ASTNode>> m_defaultParameters;
};
}

View File

@ -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<ASTNode> type, std::optional<std::endian> endian = std::nullopt)
: ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_endian(endian) { }

View File

@ -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<Token::Literal> 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;

View File

@ -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<std::string, Function> &getFunctions() {

View File

@ -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);

View File

@ -406,6 +406,8 @@ namespace hex::pl {
// Parse parameter list
bool hasParams = !peek(SEPARATOR_ROUNDBRACKETCLOSE);
u32 unnamedParamCount = 0;
std::vector<std::unique_ptr<ASTNode>> defaultParameters;
while (hasParams) {
if (MATCHES(sequence(VALUETYPE_AUTO, SEPARATOR_DOT, SEPARATOR_DOT, SEPARATOR_DOT, IDENTIFIER))) {
parameterPack = getValue<Token::Identifier>(-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<ASTNode> Parser::parseFunctionVariableDecl() {

View File

@ -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;
}

View File

@ -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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStd, "print", ParameterCount::moreThan(0), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStd, "format", ParameterCount::moreThan(0), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return format(ctx, params);
});
/* env(name) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "env", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStd, "env", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStd, "sizeof_pack", ParameterCount::atLeast(0), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return u128(params.size());
});
/* error(message) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "error", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStd, "error", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
LogConsole::abortEvaluation(Token::literalToString(params[0], true));
return std::nullopt;
});
/* warning(message) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "warning", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStd, "warning", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "base_address", ParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return u128(ctx->getProvider()->getBaseAddress());
});
/* size() */
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "size", ContentRegistry::PatternLanguage::NoParameters, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "size", ParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "find_sequence_in_range", ParameterCount::moreThan(3), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_unsigned", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_signed", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_string", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdString, "length", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdString, "at", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdString, "substr", ParameterCount::exactly(3), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_int", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_float", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdHttp, "get", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
const auto url = Token::literalToString(params[0], false);
hex::Net net;
@ -257,7 +258,7 @@ namespace hex::plugin::builtin {
static std::map<u32, fs::File> openFiles;
/* open(path, mode) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "open", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "open", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "close", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "read", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "write", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "seek", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "size", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "resize", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "flush", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "remove", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "floor", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::floor(Token::literalToFloatingPoint(params[0]));
});
/* ceil(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ceil", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ceil", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::ceil(Token::literalToFloatingPoint(params[0]));
});
/* round(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "round", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "round", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::round(Token::literalToFloatingPoint(params[0]));
});
/* trunc(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "trunc", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "trunc", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::trunc(Token::literalToFloatingPoint(params[0]));
});
/* log10(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log10", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log10", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::log10(Token::literalToFloatingPoint(params[0]));
});
/* log2(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log2", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log2", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::log2(Token::literalToFloatingPoint(params[0]));
});
/* ln(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ln", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ln", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::log(Token::literalToFloatingPoint(params[0]));
});
/* fmod(x, y) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "fmod", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "fmod", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "pow", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sqrt", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::sqrt(Token::literalToFloatingPoint(params[0]));
});
/* cbrt(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cbrt", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cbrt", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::cbrt(Token::literalToFloatingPoint(params[0]));
});
/* sin(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sin", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sin", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::sin(Token::literalToFloatingPoint(params[0]));
});
/* cos(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cos", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cos", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::cos(Token::literalToFloatingPoint(params[0]));
});
/* tan(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tan", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tan", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::tan(Token::literalToFloatingPoint(params[0]));
});
/* asin(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asin", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asin", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::asin(Token::literalToFloatingPoint(params[0]));
});
/* acos(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acos", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acos", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::acos(Token::literalToFloatingPoint(params[0]));
});
/* atan(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::atan(Token::literalToFloatingPoint(params[0]));
});
/* atan2(y, x) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
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<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sinh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::sinh(Token::literalToFloatingPoint(params[0]));
});
/* cosh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cosh", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cosh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::cosh(Token::literalToFloatingPoint(params[0]));
});
/* tanh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tanh", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tanh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::tanh(Token::literalToFloatingPoint(params[0]));
});
/* asinh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asinh", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asinh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::asinh(Token::literalToFloatingPoint(params[0]));
});
/* acosh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acosh", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acosh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::acosh(Token::literalToFloatingPoint(params[0]));
});
/* atanh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atanh", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atanh", ParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return std::atanh(Token::literalToFloatingPoint(params[0]));
});
}

View File

@ -45,8 +45,10 @@ static std::string format(hex::pl::Evaluator *ctx, const auto &params) {
}
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<Token::Literal> {
hex::ContentRegistry::PatternLanguage::addFunction(nsStd, "print", ParameterCount::atLeast(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ctx->getConsole().log(LogConsole::Level::Info, format(ctx, params));
return std::nullopt;