patterns: Added basic support for in/out variables
This commit is contained in:
parent
c56408640f
commit
ea92e17ca0
@ -25,11 +25,15 @@ namespace hex::plugin::builtin {
|
|||||||
void drawContent() override;
|
void drawContent() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pl::PatternLanguage *m_patternLanguageRuntime;
|
pl::PatternLanguage *m_parserRuntime, *m_evaluatorRuntime;
|
||||||
|
|
||||||
std::vector<std::filesystem::path> m_possiblePatternFiles;
|
std::vector<std::filesystem::path> m_possiblePatternFiles;
|
||||||
u32 m_selectedPatternFile = 0;
|
u32 m_selectedPatternFile = 0;
|
||||||
bool m_runAutomatically = false;
|
bool m_runAutomatically = false;
|
||||||
|
|
||||||
bool m_evaluatorRunning = false;
|
bool m_evaluatorRunning = false;
|
||||||
|
bool m_parserRunning = false;
|
||||||
|
|
||||||
bool m_hasUnevaluatedChanges = false;
|
bool m_hasUnevaluatedChanges = false;
|
||||||
|
|
||||||
bool m_acceptPatternWindowOpen = false;
|
bool m_acceptPatternWindowOpen = false;
|
||||||
@ -37,6 +41,17 @@ namespace hex::plugin::builtin {
|
|||||||
TextEditor m_textEditor;
|
TextEditor m_textEditor;
|
||||||
std::vector<std::pair<pl::LogConsole::Level, std::string>> m_console;
|
std::vector<std::pair<pl::LogConsole::Level, std::string>> m_console;
|
||||||
|
|
||||||
|
struct PatternVariable {
|
||||||
|
bool inVariable;
|
||||||
|
bool outVariable;
|
||||||
|
|
||||||
|
pl::Token::ValueType type;
|
||||||
|
pl::Token::Literal value;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, PatternVariable> m_patternVariables;
|
||||||
|
std::vector<std::string> m_patternTypes;
|
||||||
|
|
||||||
enum class EnvVarType {
|
enum class EnvVarType {
|
||||||
Integer,
|
Integer,
|
||||||
Float,
|
Float,
|
||||||
@ -45,16 +60,28 @@ namespace hex::plugin::builtin {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct EnvVar {
|
struct EnvVar {
|
||||||
|
u64 id;
|
||||||
std::string name;
|
std::string name;
|
||||||
pl::Token::Literal value;
|
pl::Token::Literal value;
|
||||||
EnvVarType type;
|
EnvVarType type;
|
||||||
|
|
||||||
|
bool operator==(const EnvVar &other) const {
|
||||||
|
return this->id == other.id;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<EnvVar> m_envVarEntries;
|
u64 m_envVarIdCounter;
|
||||||
|
std::list<EnvVar> m_envVarEntries;
|
||||||
|
|
||||||
|
void drawConsole(ImVec2 size);
|
||||||
|
void drawEnvVars(ImVec2 size);
|
||||||
|
void drawVariableSettings(ImVec2 size);
|
||||||
|
|
||||||
void loadPatternFile(const std::string &path);
|
void loadPatternFile(const std::string &path);
|
||||||
void clearPatternData();
|
void clearPatternData();
|
||||||
void parsePattern(char *buffer);
|
|
||||||
|
void parsePattern(const std::string &code);
|
||||||
|
void evaluatePattern(const std::string &code);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -3,6 +3,7 @@
|
|||||||
#include <hex/helpers/project_file_handler.hpp>
|
#include <hex/helpers/project_file_handler.hpp>
|
||||||
#include <hex/pattern_language/preprocessor.hpp>
|
#include <hex/pattern_language/preprocessor.hpp>
|
||||||
#include <hex/pattern_language/pattern_data.hpp>
|
#include <hex/pattern_language/pattern_data.hpp>
|
||||||
|
#include <hex/pattern_language/ast_node.hpp>
|
||||||
#include <hex/helpers/paths.hpp>
|
#include <hex/helpers/paths.hpp>
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
#include <hex/helpers/file.hpp>
|
#include <hex/helpers/file.hpp>
|
||||||
@ -24,7 +25,7 @@ namespace hex::plugin::builtin {
|
|||||||
static TextEditor::LanguageDefinition langDef;
|
static TextEditor::LanguageDefinition langDef;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
static const char* const keywords[] = {
|
static const char* const keywords[] = {
|
||||||
"using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "false", "true", "this", "parent", "addressof", "sizeof", "$", "while", "for", "fn", "return", "namespace"
|
"using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "false", "true", "this", "parent", "addressof", "sizeof", "$", "while", "for", "fn", "return", "namespace", "in", "out"
|
||||||
};
|
};
|
||||||
for (auto& k : keywords)
|
for (auto& k : keywords)
|
||||||
langDef.mKeywords.insert(k);
|
langDef.mKeywords.insert(k);
|
||||||
@ -83,12 +84,14 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
|
|
||||||
ViewPatternEditor::ViewPatternEditor() : View("hex.builtin.view.pattern_editor.name") {
|
ViewPatternEditor::ViewPatternEditor() : View("hex.builtin.view.pattern_editor.name") {
|
||||||
this->m_patternLanguageRuntime = new pl::PatternLanguage();
|
this->m_evaluatorRuntime = new pl::PatternLanguage();
|
||||||
|
this->m_parserRuntime = new pl::PatternLanguage();
|
||||||
|
|
||||||
this->m_textEditor.SetLanguageDefinition(PatternLanguage());
|
this->m_textEditor.SetLanguageDefinition(PatternLanguage());
|
||||||
this->m_textEditor.SetShowWhitespaces(false);
|
this->m_textEditor.SetShowWhitespaces(false);
|
||||||
|
|
||||||
this->m_envVarEntries = { { "", s128(0), EnvVarType::Integer } };
|
this->m_envVarEntries.push_back({ 0, "", 0, EnvVarType::Integer });
|
||||||
|
this->m_envVarIdCounter = 1;
|
||||||
|
|
||||||
EventManager::subscribe<EventProjectFileStore>(this, [this]() {
|
EventManager::subscribe<EventProjectFileStore>(this, [this]() {
|
||||||
ProjectFile::setPattern(this->m_textEditor.GetText());
|
ProjectFile::setPattern(this->m_textEditor.GetText());
|
||||||
@ -96,7 +99,7 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
EventManager::subscribe<EventProjectFileLoad>(this, [this]() {
|
EventManager::subscribe<EventProjectFileLoad>(this, [this]() {
|
||||||
this->m_textEditor.SetText(ProjectFile::getPattern());
|
this->m_textEditor.SetText(ProjectFile::getPattern());
|
||||||
this->parsePattern(this->m_textEditor.GetText().data());
|
this->evaluatePattern(this->m_textEditor.GetText());
|
||||||
});
|
});
|
||||||
|
|
||||||
EventManager::subscribe<RequestSetPatternLanguageCode>(this, [this](std::string code) {
|
EventManager::subscribe<RequestSetPatternLanguageCode>(this, [this](std::string code) {
|
||||||
@ -156,7 +159,7 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
EventManager::subscribe<EventFileUnloaded>(this, [this]{
|
EventManager::subscribe<EventFileUnloaded>(this, [this]{
|
||||||
this->m_textEditor.SetText("");
|
this->m_textEditor.SetText("");
|
||||||
this->m_patternLanguageRuntime->abort();
|
this->m_evaluatorRuntime->abort();
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Settings */
|
/* Settings */
|
||||||
@ -181,7 +184,8 @@ namespace hex::plugin::builtin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ViewPatternEditor::~ViewPatternEditor() {
|
ViewPatternEditor::~ViewPatternEditor() {
|
||||||
delete this->m_patternLanguageRuntime;
|
delete this->m_evaluatorRuntime;
|
||||||
|
delete this->m_parserRuntime;
|
||||||
|
|
||||||
EventManager::unsubscribe<EventProjectFileStore>(this);
|
EventManager::unsubscribe<EventProjectFileStore>(this);
|
||||||
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
||||||
@ -232,49 +236,38 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
if (ImHexApi::Provider::isValid() && provider->isAvailable()) {
|
if (ImHexApi::Provider::isValid() && provider->isAvailable()) {
|
||||||
auto textEditorSize = ImGui::GetContentRegionAvail();
|
auto textEditorSize = ImGui::GetContentRegionAvail();
|
||||||
textEditorSize.y *= 4.0/5.0;
|
textEditorSize.y *= 3.75/5.0;
|
||||||
textEditorSize.y -= ImGui::GetTextLineHeightWithSpacing();
|
textEditorSize.y -= ImGui::GetTextLineHeightWithSpacing();
|
||||||
this->m_textEditor.Render("hex.builtin.view.pattern_editor.name"_lang, textEditorSize, true);
|
this->m_textEditor.Render("hex.builtin.view.pattern_editor.name"_lang, textEditorSize, true);
|
||||||
|
|
||||||
auto consoleSize = ImGui::GetContentRegionAvail();
|
auto size = ImGui::GetContentRegionAvail();
|
||||||
consoleSize.y -= ImGui::GetTextLineHeightWithSpacing();
|
size.y -= ImGui::GetTextLineHeightWithSpacing() * 2.5;
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Background)]);
|
if (ImGui::BeginTabBar("settings")) {
|
||||||
if (ImGui::BeginChild("##console", consoleSize, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
if (ImGui::BeginTabItem("Console")) {
|
||||||
for (auto &[level, message] : this->m_console) {
|
this->drawConsole(size);
|
||||||
switch (level) {
|
ImGui::EndTabItem();
|
||||||
case pl::LogConsole::Level::Debug:
|
}
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Comment)]);
|
if (ImGui::BeginTabItem("Environment Variables")) {
|
||||||
break;
|
this->drawEnvVars(size);
|
||||||
case pl::LogConsole::Level::Info:
|
ImGui::EndTabItem();
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Default)]);
|
}
|
||||||
break;
|
if (ImGui::BeginTabItem("Settings")) {
|
||||||
case pl::LogConsole::Level::Warning:
|
this->drawVariableSettings(size);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Preprocessor)]);
|
ImGui::EndTabItem();
|
||||||
break;
|
|
||||||
case pl::LogConsole::Level::Error:
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::ErrorMarker)]);
|
|
||||||
break;
|
|
||||||
default: continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::TextUnformatted(message.c_str());
|
|
||||||
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabBar();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
|
||||||
ImGui::PopStyleColor(1);
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
|
||||||
|
|
||||||
if (this->m_evaluatorRunning) {
|
if (this->m_evaluatorRunning) {
|
||||||
if (ImGui::IconButton(ICON_VS_DEBUG_STOP, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed)))
|
if (ImGui::IconButton(ICON_VS_DEBUG_STOP, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed)))
|
||||||
this->m_patternLanguageRuntime->abort();
|
this->m_evaluatorRuntime->abort();
|
||||||
} else {
|
} else {
|
||||||
if (ImGui::IconButton(ICON_VS_DEBUG_START, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen)))
|
if (ImGui::IconButton(ICON_VS_DEBUG_START, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen)))
|
||||||
this->parsePattern(this->m_textEditor.GetText().data());
|
this->evaluatePattern(this->m_textEditor.GetText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -294,87 +287,25 @@ namespace hex::plugin::builtin {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
ImGui::TextUnformatted(hex::format("{} / {}",
|
ImGui::TextUnformatted(hex::format("{} / {}",
|
||||||
this->m_patternLanguageRuntime->getCreatedPatternCount(),
|
this->m_evaluatorRuntime->getCreatedPatternCount(),
|
||||||
this->m_patternLanguageRuntime->getMaximumPatternCount()
|
this->m_evaluatorRuntime->getMaximumPatternCount()
|
||||||
).c_str()
|
).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("hex.builtin.view.pattern_editor.env_vars"_lang);
|
|
||||||
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()) {
|
if (this->m_textEditor.IsTextChanged()) {
|
||||||
ProjectFile::markDirty();
|
ProjectFile::markDirty();
|
||||||
|
this->m_hasUnevaluatedChanges = true;
|
||||||
if (this->m_runAutomatically)
|
|
||||||
this->m_hasUnevaluatedChanges = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->m_hasUnevaluatedChanges && !this->m_evaluatorRunning) {
|
if (this->m_hasUnevaluatedChanges && !this->m_evaluatorRunning && !this->m_parserRunning) {
|
||||||
this->m_hasUnevaluatedChanges = false;
|
this->m_hasUnevaluatedChanges = false;
|
||||||
this->parsePattern(this->m_textEditor.GetText().data());
|
|
||||||
|
if (this->m_runAutomatically)
|
||||||
|
this->evaluatePattern(this->m_textEditor.GetText());
|
||||||
|
else
|
||||||
|
this->parsePattern(this->m_textEditor.GetText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,6 +314,179 @@ namespace hex::plugin::builtin {
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewPatternEditor::drawConsole(ImVec2 size) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Background)]);
|
||||||
|
if (ImGui::BeginChild("##console", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||||
|
for (auto &[level, message] : this->m_console) {
|
||||||
|
switch (level) {
|
||||||
|
case pl::LogConsole::Level::Debug:
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Comment)]);
|
||||||
|
break;
|
||||||
|
case pl::LogConsole::Level::Info:
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Default)]);
|
||||||
|
break;
|
||||||
|
case pl::LogConsole::Level::Warning:
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Preprocessor)]);
|
||||||
|
break;
|
||||||
|
case pl::LogConsole::Level::Error:
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::ErrorMarker)]);
|
||||||
|
break;
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TextUnformatted(message.c_str());
|
||||||
|
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::PopStyleColor(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewPatternEditor::drawEnvVars(ImVec2 size) {
|
||||||
|
if (ImGui::BeginChild("##env_vars", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||||
|
int index = 0;
|
||||||
|
if (ImGui::BeginTable("##env_vars_table", 4, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_BordersInnerH)) {
|
||||||
|
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthStretch, 0.1F);
|
||||||
|
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.4F);
|
||||||
|
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch, 0.38F);
|
||||||
|
ImGui::TableSetupColumn("Remove", ImGuiTableColumnFlags_WidthStretch, 0.12F);
|
||||||
|
|
||||||
|
for (auto iter = this->m_envVarEntries.begin(); iter != this->m_envVarEntries.end(); iter++) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
auto &[id, name, value, type] = *iter;
|
||||||
|
|
||||||
|
ImGui::PushID(index++);
|
||||||
|
ON_SCOPE_EXIT { ImGui::PopID(); };
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
|
||||||
|
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::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
|
||||||
|
ImGui::InputText("###name", name.data(), name.capacity(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &name);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
|
||||||
|
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::PopItemWidth();
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
if (ImGui::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||||
|
iter++;
|
||||||
|
this->m_envVarEntries.insert(iter, { this->m_envVarIdCounter++, "", s128(0), EnvVarType::Integer });
|
||||||
|
iter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(this->m_envVarEntries.size() <= 1);
|
||||||
|
{
|
||||||
|
if (ImGui::IconButton(ICON_VS_REMOVE, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||||
|
bool isFirst = iter == this->m_envVarEntries.begin();
|
||||||
|
this->m_envVarEntries.erase(iter);
|
||||||
|
|
||||||
|
if (isFirst)
|
||||||
|
iter = this->m_envVarEntries.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewPatternEditor::drawVariableSettings(ImVec2 size) {
|
||||||
|
if (ImGui::BeginChild("##settings", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||||
|
if (ImGui::BeginTable("##env_vars_table", 2, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_BordersInnerH)) {
|
||||||
|
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.4F);
|
||||||
|
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch, 0.6F);
|
||||||
|
|
||||||
|
for (auto &[name, variable] : this->m_patternVariables) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::TextUnformatted(name.c_str());
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
if (variable.outVariable) {
|
||||||
|
ImGui::TextUnformatted(pl::Token::literalToString(variable.value, true).c_str());
|
||||||
|
} else if (variable.inVariable) {
|
||||||
|
if (pl::Token::isSigned(variable.type)) {
|
||||||
|
s64 value = hex::get_or<s128>(variable.value, 0);
|
||||||
|
ImGui::InputScalar("", ImGuiDataType_S64, &value);
|
||||||
|
variable.value = s128(value);
|
||||||
|
} else if (pl::Token::isUnsigned(variable.type)) {
|
||||||
|
u64 value = hex::get_or<u128>(variable.value, 0);
|
||||||
|
ImGui::InputScalar("", ImGuiDataType_U64, &value);
|
||||||
|
variable.value = u128(value);
|
||||||
|
} else if (pl::Token::isFloatingPoint(variable.type)) {
|
||||||
|
double value = hex::get_or<double>(variable.value, 0.0);
|
||||||
|
ImGui::InputScalar("", ImGuiDataType_Double, &value);
|
||||||
|
variable.value = value;
|
||||||
|
} else if (variable.type == pl::Token::ValueType::Boolean) {
|
||||||
|
bool value = hex::get_or<bool>(variable.value, false);
|
||||||
|
ImGui::Checkbox("", &value);
|
||||||
|
variable.value = value;
|
||||||
|
} else if (variable.type == pl::Token::ValueType::Character) {
|
||||||
|
char buffer[2];
|
||||||
|
ImGui::InputText("", buffer, 2);
|
||||||
|
variable.value = buffer[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
void ViewPatternEditor::drawAlwaysVisible() {
|
void ViewPatternEditor::drawAlwaysVisible() {
|
||||||
|
|
||||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
|
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
|
||||||
@ -476,7 +580,7 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
this->parsePattern(buffer);
|
this->evaluatePattern(buffer);
|
||||||
this->m_textEditor.SetText(buffer);
|
this->m_textEditor.SetText(buffer);
|
||||||
|
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
@ -491,7 +595,43 @@ namespace hex::plugin::builtin {
|
|||||||
pl::PatternData::resetPalette();
|
pl::PatternData::resetPalette();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewPatternEditor::parsePattern(char *buffer) {
|
|
||||||
|
void ViewPatternEditor::parsePattern(const std::string &code) {
|
||||||
|
this->m_parserRunning = true;
|
||||||
|
std::thread([this, code] {
|
||||||
|
auto ast = this->m_parserRuntime->parseString(code);
|
||||||
|
|
||||||
|
this->m_patternVariables.clear();
|
||||||
|
this->m_patternTypes.clear();
|
||||||
|
|
||||||
|
if (ast) {
|
||||||
|
for (auto node : *ast) {
|
||||||
|
if (auto variableDecl = dynamic_cast<pl::ASTNodeVariableDecl*>(node)) {
|
||||||
|
auto type = dynamic_cast<pl::ASTNodeTypeDecl*>(variableDecl->getType());
|
||||||
|
if (type == nullptr) continue;
|
||||||
|
|
||||||
|
auto builtinType = dynamic_cast<pl::ASTNodeBuiltinType*>(type->getType());
|
||||||
|
if (builtinType == nullptr) continue;
|
||||||
|
|
||||||
|
PatternVariable variable = {
|
||||||
|
.inVariable = variableDecl->isInVariable(),
|
||||||
|
.outVariable = variableDecl->isOutVariable(),
|
||||||
|
.type = builtinType->getType()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (variable.inVariable || variable.outVariable) {
|
||||||
|
if (!this->m_patternVariables.contains(variableDecl->getName()))
|
||||||
|
this->m_patternVariables[variableDecl->getName()] = variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_parserRunning = false;
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewPatternEditor::evaluatePattern(const std::string &code) {
|
||||||
this->m_evaluatorRunning = true;
|
this->m_evaluatorRunning = true;
|
||||||
|
|
||||||
this->m_textEditor.SetErrorMarkers({ });
|
this->m_textEditor.SetErrorMarkers({ });
|
||||||
@ -499,25 +639,35 @@ namespace hex::plugin::builtin {
|
|||||||
this->clearPatternData();
|
this->clearPatternData();
|
||||||
EventManager::post<EventPatternChanged>();
|
EventManager::post<EventPatternChanged>();
|
||||||
|
|
||||||
std::thread([this, buffer = std::string(buffer)] {
|
std::thread([this, code] {
|
||||||
std::map<std::string, pl::Token::Literal> envVars;
|
std::map<std::string, pl::Token::Literal> envVars;
|
||||||
for (const auto &[name, value, type] : this->m_envVarEntries)
|
for (const auto &[id, name, value, type] : this->m_envVarEntries)
|
||||||
envVars.insert({ name, value });
|
envVars.insert({ name, value });
|
||||||
|
|
||||||
auto result = this->m_patternLanguageRuntime->executeString(ImHexApi::Provider::get(), buffer, envVars);
|
std::map<std::string, pl::Token::Literal> inVariables;
|
||||||
|
for (auto &[name, variable] : this->m_patternVariables) {
|
||||||
|
if (variable.inVariable)
|
||||||
|
inVariables[name] = variable.value;
|
||||||
|
}
|
||||||
|
|
||||||
auto error = this->m_patternLanguageRuntime->getError();
|
auto result = this->m_evaluatorRuntime->executeString(ImHexApi::Provider::get(), code, envVars, inVariables);
|
||||||
|
|
||||||
|
auto error = this->m_evaluatorRuntime->getError();
|
||||||
if (error.has_value()) {
|
if (error.has_value()) {
|
||||||
this->m_textEditor.SetErrorMarkers({ error.value() });
|
this->m_textEditor.SetErrorMarkers({ error.value() });
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_console = this->m_patternLanguageRuntime->getConsoleLog();
|
this->m_console = this->m_evaluatorRuntime->getConsoleLog();
|
||||||
|
|
||||||
|
auto outVariables = this->m_evaluatorRuntime->getOutVariables();
|
||||||
|
for (auto &[name, variable] : this->m_patternVariables) {
|
||||||
|
if (variable.outVariable && outVariables.contains(name))
|
||||||
|
variable.value = outVariables.at(name);
|
||||||
|
}
|
||||||
|
|
||||||
if (result.has_value()) {
|
if (result.has_value()) {
|
||||||
SharedData::patternData = std::move(result.value());
|
SharedData::patternData = std::move(result.value());
|
||||||
//View::doLater([]{
|
EventManager::post<EventPatternChanged>();
|
||||||
EventManager::post<EventPatternChanged>();
|
|
||||||
//});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_evaluatorRunning = false;
|
this->m_evaluatorRunning = false;
|
||||||
|
@ -714,8 +714,8 @@ namespace hex::pl {
|
|||||||
|
|
||||||
class ASTNodeVariableDecl : public ASTNode, public Attributable {
|
class ASTNodeVariableDecl : public ASTNode, public Attributable {
|
||||||
public:
|
public:
|
||||||
ASTNodeVariableDecl(std::string name, ASTNode *type, ASTNode *placementOffset = nullptr)
|
ASTNodeVariableDecl(std::string name, ASTNode *type, ASTNode *placementOffset = nullptr, bool inVariable = false, bool outVariable = false)
|
||||||
: ASTNode(), m_name(std::move(name)), m_type(type), m_placementOffset(placementOffset) { }
|
: ASTNode(), m_name(std::move(name)), m_type(type), m_placementOffset(placementOffset), m_inVariable(inVariable), m_outVariable(outVariable) { }
|
||||||
|
|
||||||
ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other), Attributable(other) {
|
ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other), Attributable(other) {
|
||||||
this->m_name = other.m_name;
|
this->m_name = other.m_name;
|
||||||
@ -740,6 +740,9 @@ namespace hex::pl {
|
|||||||
[[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; }
|
[[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; }
|
||||||
[[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; }
|
[[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool isInVariable() const { return this->m_inVariable; }
|
||||||
|
[[nodiscard]] constexpr bool isOutVariable() const { return this->m_outVariable; }
|
||||||
|
|
||||||
[[nodiscard]] std::vector<PatternData*> createPatterns(Evaluator *evaluator) const override {
|
[[nodiscard]] std::vector<PatternData*> createPatterns(Evaluator *evaluator) const override {
|
||||||
if (this->m_placementOffset != nullptr) {
|
if (this->m_placementOffset != nullptr) {
|
||||||
auto offset = dynamic_cast<ASTNodeLiteral *>(this->m_placementOffset->evaluate(evaluator));
|
auto offset = dynamic_cast<ASTNodeLiteral *>(this->m_placementOffset->evaluate(evaluator));
|
||||||
@ -770,6 +773,8 @@ namespace hex::pl {
|
|||||||
std::string m_name;
|
std::string m_name;
|
||||||
ASTNode *m_type;
|
ASTNode *m_type;
|
||||||
ASTNode *m_placementOffset;
|
ASTNode *m_placementOffset;
|
||||||
|
|
||||||
|
bool m_inVariable, m_outVariable;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ASTNodeArrayVariableDecl : public ASTNode, public Attributable {
|
class ASTNodeArrayVariableDecl : public ASTNode, public Attributable {
|
||||||
@ -1459,7 +1464,8 @@ namespace hex::pl {
|
|||||||
|
|
||||||
std::visit(overloaded {
|
std::visit(overloaded {
|
||||||
[&](std::string &assignmentValue) { },
|
[&](std::string &assignmentValue) { },
|
||||||
[&](auto &&assignmentValue) { std::memcpy(&value, &assignmentValue, pattern->getSize()); }
|
[&](PatternData *assignmentValue) { },
|
||||||
|
[&](auto &&assignmentValue) { value = assignmentValue; }
|
||||||
}, literal);
|
}, literal);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -64,6 +64,21 @@ namespace hex::pl {
|
|||||||
this->m_provider = provider;
|
this->m_provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setInVariables(const std::map<std::string, Token::Literal> &inVariables) {
|
||||||
|
this->m_inVariables = inVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::map<std::string, Token::Literal> getOutVariables() const {
|
||||||
|
std::map<std::string, Token::Literal> result;
|
||||||
|
|
||||||
|
for (const auto &[name, offset] : this->m_outVariables) {
|
||||||
|
result.insert({ name, this->getStack()[offset] });
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
prv::Provider *getProvider() const {
|
prv::Provider *getProvider() const {
|
||||||
return this->m_provider;
|
return this->m_provider;
|
||||||
@ -137,7 +152,12 @@ namespace hex::pl {
|
|||||||
return this->m_stack;
|
return this->m_stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt);
|
[[nodiscard]]
|
||||||
|
const std::vector<Token::Literal>& getStack() const {
|
||||||
|
return this->m_stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt, bool outVariable = false);
|
||||||
void setVariable(const std::string &name, const Token::Literal& value);
|
void setVariable(const std::string &name, const Token::Literal& value);
|
||||||
|
|
||||||
void abort() {
|
void abort() {
|
||||||
@ -185,7 +205,10 @@ namespace hex::pl {
|
|||||||
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function> m_customFunctions;
|
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function> m_customFunctions;
|
||||||
std::vector<ASTNode*> m_customFunctionDefinitions;
|
std::vector<ASTNode*> m_customFunctionDefinitions;
|
||||||
std::vector<Token::Literal> m_stack;
|
std::vector<Token::Literal> m_stack;
|
||||||
|
|
||||||
std::map<std::string, Token::Literal> m_envVariables;
|
std::map<std::string, Token::Literal> m_envVariables;
|
||||||
|
std::map<std::string, Token::Literal> m_inVariables;
|
||||||
|
std::map<std::string, size_t> m_outVariables;
|
||||||
|
|
||||||
friend class PatternCreationLimiter;
|
friend class PatternCreationLimiter;
|
||||||
};
|
};
|
||||||
|
@ -30,15 +30,27 @@ namespace hex::pl {
|
|||||||
PatternLanguage();
|
PatternLanguage();
|
||||||
~PatternLanguage();
|
~PatternLanguage();
|
||||||
|
|
||||||
std::optional<std::vector<PatternData*>> executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars = { });
|
[[nodiscard]]
|
||||||
std::optional<std::vector<PatternData*>> executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars = { });
|
std::optional<std::vector<ASTNode*>> parseString(const std::string &code);
|
||||||
|
[[nodiscard]]
|
||||||
|
std::optional<std::vector<PatternData*>> executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars = { }, const std::map<std::string, Token::Literal> &inVariables = { });
|
||||||
|
[[nodiscard]]
|
||||||
|
std::optional<std::vector<PatternData*>> executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars = { }, const std::map<std::string, Token::Literal> &inVariables = { });
|
||||||
|
[[nodiscard]]
|
||||||
|
const std::vector<ASTNode*>& getCurrentAST() const;
|
||||||
|
|
||||||
void abort();
|
void abort();
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
const std::vector<std::pair<LogConsole::Level, std::string>>& getConsoleLog();
|
const std::vector<std::pair<LogConsole::Level, std::string>>& getConsoleLog();
|
||||||
|
[[nodiscard]]
|
||||||
const std::optional<std::pair<u32, std::string>>& getError();
|
const std::optional<std::pair<u32, std::string>>& getError();
|
||||||
|
[[nodiscard]]
|
||||||
|
std::map<std::string, Token::Literal> getOutVariables() const;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
u32 getCreatedPatternCount();
|
u32 getCreatedPatternCount();
|
||||||
|
[[nodiscard]]
|
||||||
u32 getMaximumPatternCount();
|
u32 getMaximumPatternCount();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -40,7 +40,9 @@ namespace hex::pl {
|
|||||||
For,
|
For,
|
||||||
Function,
|
Function,
|
||||||
Return,
|
Return,
|
||||||
Namespace
|
Namespace,
|
||||||
|
In,
|
||||||
|
Out
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Operator {
|
enum class Operator {
|
||||||
@ -285,6 +287,8 @@ namespace hex::pl {
|
|||||||
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
|
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
|
||||||
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
|
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
|
||||||
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
|
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
|
||||||
|
#define KEYWORD_IN COMPONENT(Keyword, In)
|
||||||
|
#define KEYWORD_OUT COMPONENT(Keyword, Out)
|
||||||
|
|
||||||
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0))
|
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0))
|
||||||
#define IDENTIFIER hex::pl::Token::Type::Identifier, ""
|
#define IDENTIFIER hex::pl::Token::Type::Identifier, ""
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace hex::pl {
|
namespace hex::pl {
|
||||||
|
|
||||||
void Evaluator::createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value) {
|
void Evaluator::createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value, bool outVariable) {
|
||||||
auto &variables = *this->getScope(0).scope;
|
auto &variables = *this->getScope(0).scope;
|
||||||
for (auto &variable : variables) {
|
for (auto &variable : variables) {
|
||||||
if (variable->getVariableName() == name) {
|
if (variable->getVariableName() == name) {
|
||||||
@ -44,6 +44,9 @@ namespace hex::pl {
|
|||||||
|
|
||||||
this->getStack().emplace_back();
|
this->getStack().emplace_back();
|
||||||
variables.push_back(pattern);
|
variables.push_back(pattern);
|
||||||
|
|
||||||
|
if (outVariable)
|
||||||
|
this->m_outVariables[name] = pattern->getOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Evaluator::setVariable(const std::string &name, const Token::Literal& value) {
|
void Evaluator::setVariable(const std::string &name, const Token::Literal& value) {
|
||||||
@ -115,6 +118,7 @@ namespace hex::pl {
|
|||||||
}, value);
|
}, value);
|
||||||
|
|
||||||
this->getStack()[pattern->getOffset()] = castedLiteral;
|
this->getStack()[pattern->getOffset()] = castedLiteral;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode*> &ast) {
|
std::optional<std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode*> &ast) {
|
||||||
@ -153,7 +157,12 @@ namespace hex::pl {
|
|||||||
auto type = varDeclNode->getType()->evaluate(this);
|
auto type = varDeclNode->getType()->evaluate(this);
|
||||||
ON_SCOPE_EXIT { delete type; };
|
ON_SCOPE_EXIT { delete type; };
|
||||||
|
|
||||||
this->createVariable(pattern->getVariableName(), type);
|
auto &name = pattern->getVariableName();
|
||||||
|
this->createVariable(name, type, std::nullopt, varDeclNode->isOutVariable());
|
||||||
|
|
||||||
|
if (varDeclNode->isInVariable() && this->m_inVariables.contains(name))
|
||||||
|
this->setVariable(name, this->m_inVariables[name]);
|
||||||
|
|
||||||
delete pattern;
|
delete pattern;
|
||||||
} else {
|
} else {
|
||||||
patterns.push_back(pattern);
|
patterns.push_back(pattern);
|
||||||
|
@ -416,6 +416,10 @@ namespace hex::pl {
|
|||||||
tokens.emplace_back(TOKEN(Keyword, Return));
|
tokens.emplace_back(TOKEN(Keyword, Return));
|
||||||
else if (identifier == "namespace")
|
else if (identifier == "namespace")
|
||||||
tokens.emplace_back(TOKEN(Keyword, Namespace));
|
tokens.emplace_back(TOKEN(Keyword, Namespace));
|
||||||
|
else if (identifier == "in")
|
||||||
|
tokens.emplace_back(TOKEN(Keyword, In));
|
||||||
|
else if (identifier == "out")
|
||||||
|
tokens.emplace_back(TOKEN(Keyword, Out));
|
||||||
|
|
||||||
// Check for built-in types
|
// Check for built-in types
|
||||||
else if (identifier == "u8")
|
else if (identifier == "u8")
|
||||||
|
@ -1024,16 +1024,22 @@ namespace hex::pl {
|
|||||||
|
|
||||||
// (parseType) Identifier @ Integer
|
// (parseType) Identifier @ Integer
|
||||||
ASTNode* Parser::parseVariablePlacement(ASTNodeTypeDecl *type) {
|
ASTNode* Parser::parseVariablePlacement(ASTNodeTypeDecl *type) {
|
||||||
|
bool inVariable = false;
|
||||||
|
bool outVariable = false;
|
||||||
|
|
||||||
auto name = getValue<Token::Identifier>(-1).get();
|
auto name = getValue<Token::Identifier>(-1).get();
|
||||||
|
|
||||||
ASTNode *placementOffset;
|
ASTNode *placementOffset = nullptr;
|
||||||
if (MATCHES(sequence(OPERATOR_AT))) {
|
if (MATCHES(sequence(OPERATOR_AT))) {
|
||||||
placementOffset = parseMathematicalExpression();
|
placementOffset = parseMathematicalExpression();
|
||||||
} else {
|
} else if (MATCHES(sequence(KEYWORD_IN))) {
|
||||||
placementOffset = nullptr;
|
inVariable = true;
|
||||||
|
}
|
||||||
|
else if (MATCHES(sequence(KEYWORD_OUT))) {
|
||||||
|
outVariable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return create(new ASTNodeVariableDecl(name, type, placementOffset));
|
return create(new ASTNodeVariableDecl(name, type, placementOffset, inVariable, outVariable));
|
||||||
}
|
}
|
||||||
|
|
||||||
// (parseType) Identifier[[(parseMathematicalExpression)]] @ Integer
|
// (parseType) Identifier[[(parseMathematicalExpression)]] @ Integer
|
||||||
|
@ -94,25 +94,8 @@ namespace hex::pl {
|
|||||||
delete this->m_validator;
|
delete this->m_validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::vector<ASTNode*>> PatternLanguage::parseString(const std::string &code) {
|
||||||
std::optional<std::vector<PatternData*>> PatternLanguage::executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars) {
|
auto preprocessedCode = this->m_preprocessor->preprocess(code);
|
||||||
this->m_currError.reset();
|
|
||||||
this->m_evaluator->getConsole().clear();
|
|
||||||
this->m_evaluator->setProvider(provider);
|
|
||||||
this->m_evaluator->setDefaultEndian(std::endian::native);
|
|
||||||
this->m_evaluator->setEvaluationDepth(32);
|
|
||||||
this->m_evaluator->setArrayLimit(0x1000);
|
|
||||||
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();
|
|
||||||
|
|
||||||
auto preprocessedCode = this->m_preprocessor->preprocess(string);
|
|
||||||
if (!preprocessedCode.has_value()) {
|
if (!preprocessedCode.has_value()) {
|
||||||
this->m_currError = this->m_preprocessor->getError();
|
this->m_currError = this->m_preprocessor->getError();
|
||||||
return { };
|
return { };
|
||||||
@ -130,6 +113,31 @@ namespace hex::pl {
|
|||||||
return { };
|
return { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::vector<PatternData*>> PatternLanguage::executeString(prv::Provider *provider, const std::string &code, const std::map<std::string, Token::Literal> &envVars, const std::map<std::string, Token::Literal> &inVariables) {
|
||||||
|
this->m_currError.reset();
|
||||||
|
this->m_evaluator->getConsole().clear();
|
||||||
|
this->m_evaluator->setProvider(provider);
|
||||||
|
this->m_evaluator->setDefaultEndian(std::endian::native);
|
||||||
|
this->m_evaluator->setEvaluationDepth(32);
|
||||||
|
this->m_evaluator->setArrayLimit(0x1000);
|
||||||
|
this->m_evaluator->setPatternLimit(0x2000);
|
||||||
|
this->m_evaluator->setLoopLimit(0x1000);
|
||||||
|
this->m_evaluator->setInVariables(inVariables);
|
||||||
|
|
||||||
|
for (const auto &[name, value] : envVars)
|
||||||
|
this->m_evaluator->setEnvVariable(name, value);
|
||||||
|
|
||||||
|
for (auto &node : this->m_currAST)
|
||||||
|
delete node;
|
||||||
|
this->m_currAST.clear();
|
||||||
|
|
||||||
|
auto ast = this->parseString(code);
|
||||||
|
if (!ast)
|
||||||
|
return { };
|
||||||
|
|
||||||
this->m_currAST = ast.value();
|
this->m_currAST = ast.value();
|
||||||
|
|
||||||
auto patterns = this->m_evaluator->evaluate(ast.value());
|
auto patterns = this->m_evaluator->evaluate(ast.value());
|
||||||
@ -141,16 +149,25 @@ namespace hex::pl {
|
|||||||
return patterns;
|
return patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::vector<PatternData*>> PatternLanguage::executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars) {
|
std::optional<std::vector<PatternData*>> PatternLanguage::executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars, const std::map<std::string, Token::Literal> &inVariables) {
|
||||||
File file(path, File::Mode::Read);
|
File file(path, File::Mode::Read);
|
||||||
|
|
||||||
return this->executeString(provider, file.readString(), envVars);
|
return this->executeString(provider, file.readString(), envVars, inVariables);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatternLanguage::abort() {
|
void PatternLanguage::abort() {
|
||||||
this->m_evaluator->abort();
|
this->m_evaluator->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<ASTNode*> &PatternLanguage::getCurrentAST() const {
|
||||||
|
return this->m_currAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::map<std::string, Token::Literal> PatternLanguage::getOutVariables() const {
|
||||||
|
return this->m_evaluator->getOutVariables();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::vector<std::pair<LogConsole::Level, std::string>>& PatternLanguage::getConsoleLog() {
|
const std::vector<std::pair<LogConsole::Level, std::string>>& PatternLanguage::getConsoleLog() {
|
||||||
return this->m_evaluator->getConsole().getLog();
|
return this->m_evaluator->getConsole().getLog();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user