1
0
mirror of synced 2025-02-01 12:07:55 +01:00

patterns: Added std::env and ability to pass parameters to patterns from the UI

This commit is contained in:
WerWolv 2021-12-10 11:55:27 +01:00
parent 6a0ad22774
commit 8f2e382c8a
8 changed files with 133 additions and 8 deletions

View File

@ -37,6 +37,21 @@ namespace hex::plugin::builtin {
TextEditor m_textEditor;
std::vector<std::pair<pl::LogConsole::Level, std::string>> m_console;
enum class EnvVarType {
Integer,
Float,
String,
Bool
};
struct EnvVar {
std::string name;
pl::Token::Literal value;
EnvVarType type;
};
std::vector<EnvVar> m_envVarEntries;
void loadPatternFile(const std::string &path);
void clearPatternData();
void parsePattern(char *buffer);

View File

@ -51,7 +51,7 @@ namespace hex::plugin::builtin {
/* assert(condition, message) */
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto condition = Token::literalToBoolean(params[0]);
auto message = std::get<std::string>(params[1]);
auto message = Token::literalToString(params[1], false);
if (!condition)
LogConsole::abortEvaluation(hex::format("assertion failed \"{0}\"", message));
@ -62,7 +62,7 @@ namespace hex::plugin::builtin {
/* assert_warn(condition, message) */
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert_warn", 2, [](auto *ctx, auto params) -> std::optional<Token::Literal> {
auto condition = Token::literalToBoolean(params[0]);
auto message = std::get<std::string>(params[1]);
auto message = Token::literalToString(params[1], false);
if (!condition)
ctx->getConsole().log(LogConsole::Level::Warning, hex::format("assertion failed \"{0}\"", message));
@ -82,6 +82,13 @@ namespace hex::plugin::builtin {
return format(ctx, params);
});
/* env(name) */
ContentRegistry::PatternLanguageFunctions::add(nsStd, "env", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto name = Token::literalToString(params[0], false);
return ctx->getEnvVariable(name);
});
}
ContentRegistry::PatternLanguageFunctions::Namespace nsStdMem = { "std", "mem" };

View File

@ -88,6 +88,8 @@ namespace hex::plugin::builtin {
this->m_textEditor.SetLanguageDefinition(PatternLanguage());
this->m_textEditor.SetShowWhitespaces(false);
this->m_envVarEntries = { { "", s128(0), EnvVarType::Integer } };
EventManager::subscribe<EventProjectFileStore>(this, [this]() {
ProjectFile::setPattern(this->m_textEditor.GetText());
});
@ -284,6 +286,71 @@ namespace hex::plugin::builtin {
this->m_patternLanguageRuntime->getMaximumPatternCount()
).c_str()
);
ImGui::SameLine();
if (ImGui::IconButton(ICON_VS_GLOBE, ImGui::GetStyleColorVec4(ImGuiCol_Text)))
ImGui::OpenPopup("env_vars");
if (ImGui::BeginPopup("env_vars")) {
ImGui::TextUnformatted("Environment Variables");
ImGui::SameLine();
if (ImGui::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) this->m_envVarEntries.push_back({ "", s128(0), EnvVarType::Integer });
ImGui::Separator();
int index = 0;
for (auto &[name, value, type] : this->m_envVarEntries) {
ImGui::PushID(index++);
ImGui::PushItemWidth(ImGui::GetTextLineHeightWithSpacing() * 2);
constexpr const char* Types[] = { "I", "F", "S", "B" };
if (ImGui::BeginCombo("", Types[static_cast<int>(type)])) {
for (auto i = 0; i < IM_ARRAYSIZE(Types); i++) {
if (ImGui::Selectable(Types[i]))
type = static_cast<EnvVarType>(i);
}
ImGui::EndCombo();
}
ImGui::PopItemWidth();
ImGui::SameLine();
ImGui::InputText("###name", name.data(), name.capacity(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &name);
ImGui::SameLine();
switch (type) {
case EnvVarType::Integer: {
s64 displayValue = hex::get_or<s128>(value, 0);
ImGui::InputScalar("###value", ImGuiDataType_S64, &displayValue);
value = s128(displayValue);
break;
}
case EnvVarType::Float: {
auto displayValue = hex::get_or<double>(value, 0.0);
ImGui::InputDouble("###value", &displayValue);
value = displayValue;
break;
}
case EnvVarType::Bool: {
auto displayValue = hex::get_or<bool>(value, false);
ImGui::Checkbox("###value", &displayValue);
value = displayValue;
break;
}
case EnvVarType::String: {
auto displayValue = hex::get_or<std::string>(value, "");
ImGui::InputText("###value", displayValue.data(), displayValue.capacity(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &displayValue);
value = displayValue;
break;
}
}
ImGui::PopID();
}
ImGui::EndPopup();
}
}
if (this->m_textEditor.IsTextChanged()) {
@ -418,7 +485,11 @@ namespace hex::plugin::builtin {
EventManager::post<EventPatternChanged>();
std::thread([this, buffer = std::string(buffer)] {
auto result = this->m_patternLanguageRuntime->executeString(ImHexApi::Provider::get(), buffer);
std::map<std::string, pl::Token::Literal> envVars;
for (const auto &[name, value, type] : this->m_envVarEntries)
envVars.insert({ name, value });
auto result = this->m_patternLanguageRuntime->executeString(ImHexApi::Provider::get(), buffer, envVars);
auto error = this->m_patternLanguageRuntime->getError();
if (error.has_value()) {

View File

@ -14,6 +14,7 @@
#include <optional>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
#include <nfd.hpp>
@ -227,6 +228,15 @@ namespace hex {
return iter != a.end();
}
template<typename T, typename ... VariantTypes>
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
const T *value = std::get_if<T>(&variant);
if (value == nullptr)
return alt;
else
return *value;
}
namespace scope_guard {
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()

View File

@ -149,6 +149,18 @@ namespace hex::pl {
LogConsole::abortEvaluation("evaluation aborted by user");
}
[[nodiscard]]
std::optional<Token::Literal> getEnvVariable(const std::string &name) const {
if (this->m_envVariables.contains(name))
return this->m_envVariables.at(name);
else
return std::nullopt;
}
void setEnvVariable(const std::string &name, const Token::Literal &value) {
this->m_envVariables[name] = value;
}
private:
void patternCreated();
@ -173,6 +185,7 @@ namespace hex::pl {
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function> m_customFunctions;
std::vector<ASTNode*> m_customFunctionDefinitions;
std::vector<Token::Literal> m_stack;
std::map<std::string, Token::Literal> m_envVariables;
friend class PatternCreationLimiter;
};

View File

@ -3,12 +3,14 @@
#include <hex.hpp>
#include <bit>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include <hex/pattern_language/log_console.hpp>
#include <hex/pattern_language/token.hpp>
namespace hex::prv { class Provider; }
@ -28,8 +30,8 @@ namespace hex::pl {
PatternLanguage();
~PatternLanguage();
std::optional<std::vector<PatternData*>> executeString(prv::Provider *provider, const std::string &string);
std::optional<std::vector<PatternData*>> executeFile(prv::Provider *provider, const std::string &path);
std::optional<std::vector<PatternData*>> executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars = { });
std::optional<std::vector<PatternData*>> executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars = { });
void abort();

View File

@ -123,6 +123,10 @@ namespace hex::pl {
this->m_scopes.clear();
this->m_aborted = false;
ON_SCOPE_EXIT {
this->m_envVariables.clear();
};
this->dataOffset() = 0x00;
this->m_currPatternCount = 0;

View File

@ -95,7 +95,7 @@ namespace hex::pl {
}
std::optional<std::vector<PatternData*>> PatternLanguage::executeString(prv::Provider *provider, const std::string &string) {
std::optional<std::vector<PatternData*>> PatternLanguage::executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars) {
this->m_currError.reset();
this->m_evaluator->getConsole().clear();
this->m_evaluator->setProvider(provider);
@ -105,6 +105,9 @@ namespace hex::pl {
this->m_evaluator->setPatternLimit(0x2000);
this->m_evaluator->setLoopLimit(0x1000);
for (const auto &[name, value] : envVars)
this->m_evaluator->setEnvVariable(name, value);
for (auto &node : this->m_currAST)
delete node;
this->m_currAST.clear();
@ -138,10 +141,10 @@ namespace hex::pl {
return patterns;
}
std::optional<std::vector<PatternData*>> PatternLanguage::executeFile(prv::Provider *provider, const std::string &path) {
std::optional<std::vector<PatternData*>> PatternLanguage::executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars) {
File file(path, File::Mode::Read);
return this->executeString(provider, file.readString());
return this->executeString(provider, file.readString(), envVars);
}
void PatternLanguage::abort() {