1
0
mirror of synced 2025-01-18 00:56:49 +01:00

patterns: Move builtin functions to namespace. Add string functions

This commit is contained in:
WerWolv 2021-08-27 09:56:20 +02:00
parent b7003d499c
commit d0aec62997
4 changed files with 171 additions and 133 deletions

View File

@ -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<u8> 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<u8> 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<u8> 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<u8> 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<u8*>(value));
case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast<u16*>(value));
case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast<u32*>(value));
case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast<u64*>(value));
case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast<u128*>(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<u8*>(value));
case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast<u16*>(value));
case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast<u32*>(value));
case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast<u64*>(value));
case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast<u128*>(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<s8*>(value));
case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast<s16*>(value));
case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast<s32*>(value));
case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast<s64*>(value));
case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast<s128*>(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<s8*>(value));
case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast<s16*>(value));
case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast<s32*>(value));
case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast<s64*>(value));
case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast<s128*>(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<ASTNodeIntegerLiteral*>(param); integerLiteral != nullptr) {
std::visit([&](auto &&value) {
using Type = std::remove_cvref_t<decltype(value)>;
if constexpr (std::is_same_v<Type, char>)
message += (char)value;
else if constexpr (std::is_same_v<Type, bool>)
message += value == 0 ? "false" : "true";
else if constexpr (std::is_unsigned_v<Type>)
message += std::to_string(static_cast<u64>(value));
else if constexpr (std::is_signed_v<Type>)
message += std::to_string(static_cast<s64>(value));
else if constexpr (std::is_floating_point_v<Type>)
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<ASTNodeIntegerLiteral*>(param); integerLiteral != nullptr) {
std::visit([&](auto &&value) {
using Type = std::remove_cvref_t<decltype(value)>;
if constexpr (std::is_same_v<Type, char>)
message += (char)value;
else if constexpr (std::is_same_v<Type, bool>)
message += value == 0 ? "false" : "true";
else if constexpr (std::is_unsigned_v<Type>)
message += std::to_string(static_cast<u64>(value));
else if constexpr (std::is_signed_v<Type>)
message += std::to_string(static_cast<s64>(value));
else if constexpr (std::is_floating_point_v<Type>)
message += std::to_string(value);
else
message += "< Custom Type >";
}, integerLiteral->getValue());
}
else if (auto stringLiteral = dynamic_cast<ASTNodeStringLiteral*>(param); stringLiteral != nullptr)
message += stringLiteral->getString();
}
else if (auto stringLiteral = dynamic_cast<ASTNodeStringLiteral*>(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));
});
}
}
}

View File

@ -85,12 +85,14 @@ namespace hex {
constexpr static u32 LessParametersThan = 0x4000'0000;
constexpr static u32 NoParameters = 0x0000'0000;
using Namespace = std::vector<std::string>;
struct Function {
u32 parameterCount;
std::function<hex::lang::ASTNode*(hex::lang::Evaluator&, std::vector<hex::lang::ASTNode*>&)> func;
};
static void add(std::string_view name, u32 parameterCount, const std::function<hex::lang::ASTNode*(hex::lang::Evaluator&, std::vector<hex::lang::ASTNode*>&)> &func);
static void add(const Namespace &ns, const std::string &name, u32 parameterCount, const std::function<hex::lang::ASTNode*(hex::lang::Evaluator&, std::vector<hex::lang::ASTNode*>&)> &func);
static std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function>& getEntries();
};

View File

@ -151,8 +151,15 @@ namespace hex {
/* Pattern Language Functions */
void ContentRegistry::PatternLanguageFunctions::add(std::string_view name, u32 parameterCount, const std::function<hex::lang::ASTNode*(hex::lang::Evaluator&, std::vector<hex::lang::ASTNode*>&)> &func) {
getEntries()[name.data()] = Function{ parameterCount, func };
void ContentRegistry::PatternLanguageFunctions::add(const Namespace &ns, const std::string &name, u32 parameterCount, const std::function<hex::lang::ASTNode*(hex::lang::Evaluator&, std::vector<hex::lang::ASTNode*>&)> &func) {
std::string functionName;
for (auto &scope : ns)
functionName += scope + "::";
functionName += name;
getEntries()[functionName] = Function { parameterCount, func };
}
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function>& ContentRegistry::PatternLanguageFunctions::getEntries() {

View File

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