patterns: Added button to abort evaluation

This commit is contained in:
WerWolv 2021-10-07 11:34:46 +02:00
parent 3e30f75e7b
commit 6d8b7bef09
9 changed files with 137 additions and 32 deletions

View File

@ -61,7 +61,8 @@ namespace ImGui {
void InfoTooltip(const char *text);
bool TitleBarButton(const char* label, ImVec2 size_arg);
bool ToolBarButton(const char* symbol, ImVec4 color, ImVec2 size_arg);
bool ToolBarButton(const char* symbol, ImVec4 color);
bool IconButton(const char* symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
inline bool HasSecondPassed() {
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);

View File

@ -401,7 +401,7 @@ namespace ImGui {
return pressed;
}
bool ToolBarButton(const char* symbol, ImVec4 color, ImVec2 size_arg) {
bool ToolBarButton(const char* symbol, ImVec4 color) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
@ -415,7 +415,7 @@ namespace ImGui {
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
ImVec2 size = CalcItemSize(ImVec2(1, 1) * ImGui::GetCurrentWindow()->MenuBarHeight(), label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
@ -443,4 +443,46 @@ namespace ImGui {
return pressed;
}
bool IconButton(const char* symbol, ImVec4 color, ImVec2 size_arg) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
color.w = 1.0F;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(symbol);
const ImVec2 label_size = CalcTextSize(symbol, NULL, true);
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held);
PushStyleColor(ImGuiCol_Text, color);
// Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, NULL, &label_size, style.ButtonTextAlign, &bb);
PopStyleColor();
// Automatically close popups
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
// CloseCurrentPopup();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
return pressed;
}
}

View File

@ -26,19 +26,17 @@ namespace hex::plugin::builtin {
void addToolbarItems() {
ContentRegistry::Interface::addToolbarItem([] {
const static auto buttonSize = ImVec2(ImGui::GetCurrentWindow()->MenuBarHeight(), ImGui::GetCurrentWindow()->MenuBarHeight());
auto provider = ImHexApi::Provider::get();
// Undo
ImGui::Disabled([&provider] {
if (ImGui::ToolBarButton(ICON_VS_DISCARD, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
if (ImGui::ToolBarButton(ICON_VS_DISCARD, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
provider->undo();
}, !ImHexApi::Provider::isValid() || !provider->canUndo());
// Redo
ImGui::Disabled([&provider] {
if (ImGui::ToolBarButton(ICON_VS_REDO, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
if (ImGui::ToolBarButton(ICON_VS_REDO, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
provider->redo();
}, !ImHexApi::Provider::isValid() || !provider->canRedo());
@ -46,11 +44,11 @@ namespace hex::plugin::builtin {
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
// Create new file
if (ImGui::ToolBarButton(ICON_VS_FILE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGray), buttonSize))
if (ImGui::ToolBarButton(ICON_VS_FILE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGray)))
EventManager::post<RequestOpenWindow>("Create File");
// Open file
if (ImGui::ToolBarButton(ICON_VS_FOLDER_OPENED, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBrown), buttonSize))
if (ImGui::ToolBarButton(ICON_VS_FOLDER_OPENED, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBrown)))
EventManager::post<RequestOpenWindow>("Open File");
@ -58,13 +56,13 @@ namespace hex::plugin::builtin {
// Save file
ImGui::Disabled([&provider] {
if (ImGui::ToolBarButton(ICON_VS_SAVE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
if (ImGui::ToolBarButton(ICON_VS_SAVE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
provider->save();
}, !ImHexApi::Provider::isValid() || !provider->isWritable() || !provider->isSavable());
// Save file as
ImGui::Disabled([&provider] {
if (ImGui::ToolBarButton(ICON_VS_SAVE_AS, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
if (ImGui::ToolBarButton(ICON_VS_SAVE_AS, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
hex::openFileBrowser("hex.view.hexeditor.save_as"_lang, DialogMode::Save, { }, [&provider](auto path) {
provider->saveAs(path);
});
@ -76,7 +74,7 @@ namespace hex::plugin::builtin {
// Create bookmark
ImGui::Disabled([] {
if (ImGui::ToolBarButton(ICON_VS_BOOKMARK, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen), buttonSize)) {
if (ImGui::ToolBarButton(ICON_VS_BOOKMARK, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
Region region = { 0 };
EventManager::post<QuerySelection>(region);

View File

@ -516,7 +516,10 @@ namespace hex::pl {
FunctionResult execute(Evaluator *evaluator) override {
u64 loopIterations = 0;
while (evaluateCondition(evaluator)) {
evaluator->handleAbort();
auto variables = *evaluator->getScope(0).scope;
u32 startVariableCount = variables.size();
ON_SCOPE_EXIT {
@ -538,6 +541,12 @@ namespace hex::pl {
return { true, result };
}
}
loopIterations++;
if (loopIterations >= evaluator->getLoopLimit())
LogConsole::abortEvaluation(hex::format("loop iterations exceeded limit of {}", evaluator->getLoopLimit()), this);
evaluator->handleAbort();
}
return { false, { } };
@ -807,6 +816,7 @@ namespace hex::pl {
while (whileStatement->evaluateCondition(evaluator)) {
entryCount++;
evaluator->dataOffset() += templatePattern->getSize();
evaluator->handleAbort();
}
}
} else {
@ -829,6 +839,7 @@ namespace hex::pl {
}
if (reachedEnd) break;
evaluator->handleAbort();
}
}
@ -901,6 +912,8 @@ namespace hex::pl {
entries.push_back(pattern);
size += pattern->getSize();
evaluator->handleAbort();
}
} else if (auto whileStatement = dynamic_cast<ASTNodeWhileStatement*>(sizeNode)) {
while (whileStatement->evaluateCondition(evaluator)) {
@ -917,6 +930,8 @@ namespace hex::pl {
entryCount++;
size += pattern->getSize();
evaluator->handleAbort();
}
}
} else {
@ -951,6 +966,7 @@ namespace hex::pl {
}
if (reachedEnd) break;
evaluator->handleAbort();
}
}
@ -1380,6 +1396,10 @@ namespace hex::pl {
std::visit(overloaded {
[&](std::string &assignmentValue) { },
[&](s128 assignmentValue) {
std::memcpy(&value, &assignmentValue, pattern->getSize());
value = hex::signExtend(pattern->getSize() * 8, value);
},
[&](auto &&assignmentValue) { std::memcpy(&value, &assignmentValue, pattern->getSize()); }
}, literal);
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <atomic>
#include <bit>
#include <map>
#include <optional>
@ -31,8 +32,10 @@ namespace hex::pl {
struct Scope { PatternData *parent; std::vector<PatternData*>* scope; };
void pushScope(PatternData *parent, std::vector<PatternData*> &scope) {
if (this->m_scopes.size() > this->m_evalDepth)
LogConsole::abortEvaluation(hex::format("recursion limit of {} reached", this->m_evalDepth));
if (this->m_scopes.size() > this->getEvaluationDepth())
LogConsole::abortEvaluation(hex::format("evaluation depth exceeded set limit of {}", this->getEvaluationDepth()));
this->handleAbort();
this->m_scopes.push_back({ parent, &scope });
}
@ -70,38 +73,47 @@ namespace hex::pl {
return this->m_defaultEndian;
}
void setEvaluationDepth(u32 evalDepth) {
void setEvaluationDepth(u64 evalDepth) {
this->m_evalDepth = evalDepth;
}
[[nodiscard]]
u32 getEvaluationDepth() const {
u64 getEvaluationDepth() const {
return this->m_evalDepth;
}
void setArrayLimit(u32 arrayLimit) {
void setArrayLimit(u64 arrayLimit) {
this->m_arrayLimit = arrayLimit;
}
[[nodiscard]]
u32 getArrayLimit() const {
u64 getArrayLimit() const {
return this->m_arrayLimit;
}
void setPatternLimit(u32 limit) {
void setPatternLimit(u64 limit) {
this->m_patternLimit = limit;
}
[[nodiscard]]
u32 getPatternLimit() {
u64 getPatternLimit() {
return this->m_patternLimit;
}
[[nodiscard]]
u32 getPatternCount() {
u64 getPatternCount() {
return this->m_currPatternCount;
}
void setLoopLimit(u64 limit) {
this->m_loopLimit = limit;
}
[[nodiscard]]
u64 getLoopLimit() {
return this->m_loopLimit;
}
u64& dataOffset() { return this->m_currOffset; }
bool addCustomFunction(const std::string &name, u32 numParams, const ContentRegistry::PatternLanguageFunctions::Callback &function) {
@ -123,6 +135,15 @@ namespace hex::pl {
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt);
void setVariable(const std::string &name, const Token::Literal& value);
void abort() {
this->m_aborted = true;
}
void handleAbort() {
if (this->m_aborted)
LogConsole::abortEvaluation("evaluation aborted by user");
}
private:
void patternCreated();
@ -134,11 +155,14 @@ namespace hex::pl {
LogConsole m_console;
std::endian m_defaultEndian = std::endian::native;
u32 m_evalDepth;
u32 m_arrayLimit;
u32 m_patternLimit;
u64 m_evalDepth;
u64 m_arrayLimit;
u64 m_patternLimit;
u64 m_loopLimit;
u32 m_currPatternCount;
u64 m_currPatternCount;
std::atomic<bool> m_aborted;
std::vector<Scope> m_scopes;
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function> m_customFunctions;

View File

@ -31,6 +31,8 @@ namespace hex::pl {
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);
void abort();
const std::vector<std::pair<LogConsole::Level, std::string>>& getConsoleLog();
const std::optional<std::pair<u32, std::string>>& getError();

View File

@ -106,6 +106,7 @@ namespace hex::pl {
this->m_stack.clear();
this->m_customFunctions.clear();
this->m_scopes.clear();
this->m_aborted = false;
this->dataOffset() = 0x00;
this->m_currPatternCount = 0;

View File

@ -67,6 +67,16 @@ namespace hex::pl {
return true;
});
this->m_preprocessor->addPragmaHandler("loop_limit", [this](const std::string &value) {
auto limit = strtol(value.c_str(), nullptr, 0);
if (limit <= 0)
return false;
this->m_evaluator->setLoopLimit(limit);
return true;
});
this->m_preprocessor->addPragmaHandler("base_address", [](const std::string &value) {
auto baseAddress = strtoull(value.c_str(), nullptr, 0);
@ -93,6 +103,7 @@ namespace hex::pl {
this->m_evaluator->setEvaluationDepth(32);
this->m_evaluator->setArrayLimit(0x1000);
this->m_evaluator->setPatternLimit(0x2000);
this->m_evaluator->setLoopLimit(0x1000);
for (auto &node : this->m_currAST)
delete node;
@ -133,6 +144,10 @@ namespace hex::pl {
return this->executeString(provider, file.readString());
}
void PatternLanguage::abort() {
this->m_evaluator->abort();
}
const std::vector<std::pair<LogConsole::Level, std::string>>& PatternLanguage::getConsoleLog() {
return this->m_evaluator->getConsole().getLog();

View File

@ -245,16 +245,18 @@ namespace hex {
ImGui::EndChild();
ImGui::PopStyleColor(1);
ImGui::Disabled([this] {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(ImColor(0x20, 0x85, 0x20)));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
if (ImGui::ArrowButton("evaluate", ImGuiDir_Right))
if (this->m_evaluatorRunning) {
if (ImGui::IconButton(ICON_VS_DEBUG_STOP, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed)))
this->m_patternLanguageRuntime->abort();
} else {
if (ImGui::IconButton(ICON_VS_DEBUG_START, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen)))
this->parsePattern(this->m_textEditor.GetText().data());
}
ImGui::PopStyleVar();
ImGui::PopStyleColor();
}, this->m_evaluatorRunning);
ImGui::PopStyleVar();
ImGui::SameLine();
if (this->m_evaluatorRunning)