Step 105: add optimization controls panel
This commit is contained in:
@@ -205,6 +205,7 @@ All 38 steps implemented and passing. Each step has a corresponding test (`step1
|
||||
- [x] Step 102: **IMPLEMENTED** — Memory strategy dashboard panel with counts and JSON export (1/1 tests pass)
|
||||
- [x] Step 103: **IMPLEMENTED** — Side-by-side generated code view with scroll lock, target language selection, and line highlighting (1/1 tests pass)
|
||||
- [x] Step 104: **IMPLEMENTED** — Cross-language projection button with read-only projected tabs and annotation summary (2/2 tests pass)
|
||||
- [x] Step 105: **IMPLEMENTED** — Optimization controls panel with constraint-aware buttons and summaries (2/2 tests pass)
|
||||
|
||||
---
|
||||
|
||||
@@ -289,6 +290,7 @@ vcpkg's imgui 1.91.9 removed the `sdl2-binding` feature (only `sdl3-binding` exi
|
||||
**Step 102:** Compile and pass (1/1)
|
||||
**Step 103:** Compile and pass (1/1)
|
||||
**Step 104:** Compile and pass (2/2)
|
||||
**Step 105:** Compile and pass (2/2)
|
||||
|
||||
---
|
||||
|
||||
@@ -402,3 +404,4 @@ Sprint 4 in progress. Step 76 (LayoutManager) done. Next: Step 77 (custom code e
|
||||
| 2026-02-09 | Codex | Step 102: Memory strategy dashboard panel with counts and JSON export. 1/1 tests pass. |
|
||||
| 2026-02-09 | Codex | Step 103: Side-by-side generated code view with scroll lock, target language selector, and line highlighting. 1/1 tests pass. |
|
||||
| 2026-02-09 | Codex | Step 104: Cross-language projection button with read-only projected tabs and annotation summary. 2/2 tests pass. |
|
||||
| 2026-02-09 | Codex | Step 105: Optimization controls panel with constraint-aware buttons and summaries. 2/2 tests pass. |
|
||||
|
||||
@@ -566,6 +566,10 @@ add_executable(step104_test tests/step104_test.cpp)
|
||||
target_include_directories(step104_test PRIVATE src)
|
||||
target_link_libraries(step104_test PRIVATE nlohmann_json::nlohmann_json)
|
||||
|
||||
add_executable(step105_test tests/step105_test.cpp)
|
||||
target_include_directories(step105_test PRIVATE src)
|
||||
target_link_libraries(step105_test PRIVATE nlohmann_json::nlohmann_json)
|
||||
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(glad CONFIG REQUIRED)
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "MemoryStrategyInference.h"
|
||||
#include "AnnotationConflict.h"
|
||||
#include "StrategyDashboard.h"
|
||||
#include "TransformEngine.h"
|
||||
#include "StrategyAwareOptimizer.h"
|
||||
#include "CrossLanguageProjector.h"
|
||||
#include "ast/Generator.h"
|
||||
#include "ast/Annotation.h"
|
||||
@@ -127,6 +129,9 @@ struct EditorState {
|
||||
std::vector<MemoryStrategyInference::Suggestion> suggestions;
|
||||
bool showSuggestionPopup = false;
|
||||
MemoryStrategyInference::Suggestion suggestionPopup;
|
||||
std::string optimizeFoldSummary;
|
||||
std::string optimizeDeadCodeSummary;
|
||||
std::string optimizeApplySummary;
|
||||
|
||||
BufferState* active() { return activeBuffer; }
|
||||
|
||||
@@ -523,6 +528,20 @@ struct EditorState {
|
||||
(preserved ? "yes" : "no") + ").\n";
|
||||
}
|
||||
|
||||
void refreshActiveTextFromAST() {
|
||||
if (!active()) return;
|
||||
active()->editBuf = active()->sync.getText();
|
||||
active()->editor.setContent(active()->editBuf, active()->language);
|
||||
active()->highlightsDirty = true;
|
||||
active()->modified = true;
|
||||
if (lsp && active()->path.rfind("(untitled", 0) != 0) {
|
||||
active()->lspVersion += 1;
|
||||
lsp->didChange(toFileUri(active()->path), active()->editBuf, active()->lspVersion);
|
||||
}
|
||||
analysisPending = true;
|
||||
analysisLastChange = ImGui::GetTime();
|
||||
}
|
||||
|
||||
void updateCursorPos(int bytePos) {
|
||||
if (!active()) return;
|
||||
active()->cursorLine = 1;
|
||||
@@ -591,6 +610,35 @@ static int countAnnotationNodes(const ASTNode* node) {
|
||||
return count;
|
||||
}
|
||||
|
||||
static std::string findOptimizationBlockReason(const ASTNode* node) {
|
||||
if (!node) return "";
|
||||
for (auto* anno : node->getChildren("annotations")) {
|
||||
if (anno->conceptType == "OwnerAnnotation") {
|
||||
auto* oa = static_cast<const OwnerAnnotation*>(anno);
|
||||
if (oa->strategy == "Single") {
|
||||
return "@Owner(Single) blocks optimization (aliasing risk)";
|
||||
}
|
||||
}
|
||||
if (anno->conceptType == "DeallocateAnnotation") {
|
||||
auto* da = static_cast<const DeallocateAnnotation*>(anno);
|
||||
if (da->strategy == "Explicit") {
|
||||
return "@Deallocate(Explicit) blocks optimization (reorder risk)";
|
||||
}
|
||||
}
|
||||
if (anno->conceptType == "AllocateAnnotation") {
|
||||
auto* aa = static_cast<const AllocateAnnotation*>(anno);
|
||||
if (aa->strategy == "Static") {
|
||||
return "@Allocate(Static) blocks optimization (dynamic alloc risk)";
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto* child : node->allChildren()) {
|
||||
std::string found = findOptimizationBlockReason(child);
|
||||
if (!found.empty()) return found;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ImGui InputTextMultiline with std::string resize callback
|
||||
@@ -1954,6 +2002,123 @@ int main(int, char**) {
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// Optimization controls
|
||||
if (ImGui::BeginTabItem("Optimize")) {
|
||||
ImGui::PushFont(uiFont);
|
||||
Module* ast = state.active() ? state.active()->sync.getAST() : nullptr;
|
||||
if (!state.active()) {
|
||||
ImGui::TextDisabled("(no active buffer)");
|
||||
} else if (!ast) {
|
||||
ImGui::TextDisabled("(no AST)");
|
||||
} else if (state.active()->readOnly) {
|
||||
ImGui::TextDisabled("(read-only buffer)");
|
||||
} else {
|
||||
std::string blockReason = findOptimizationBlockReason(ast);
|
||||
bool blocked = !blockReason.empty();
|
||||
|
||||
auto showBlockedTooltip = [&](const std::string& reason) {
|
||||
if (!reason.empty() &&
|
||||
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(reason.c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
};
|
||||
|
||||
if (blocked) ImGui::BeginDisabled();
|
||||
if (ImGui::Button("Constant Fold")) {
|
||||
TransformEngine engine;
|
||||
engine.setRoot(ast);
|
||||
auto res = engine.constantFolding();
|
||||
std::string summary = "Constant Fold: ";
|
||||
if (res.applied) {
|
||||
summary += "applied (" + std::to_string(res.nodesModified) + " nodes)";
|
||||
} else {
|
||||
summary += "no changes";
|
||||
}
|
||||
if (!res.warning.empty()) {
|
||||
summary += " — warning: " + res.warning;
|
||||
state.outputLog += res.warning + "\n";
|
||||
}
|
||||
state.optimizeFoldSummary = summary;
|
||||
state.outputLog += summary + "\n";
|
||||
if (res.applied) state.refreshActiveTextFromAST();
|
||||
}
|
||||
showBlockedTooltip(blockReason);
|
||||
if (blocked) ImGui::EndDisabled();
|
||||
if (!state.optimizeFoldSummary.empty()) {
|
||||
ImGui::TextWrapped("%s", state.optimizeFoldSummary.c_str());
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (blocked) ImGui::BeginDisabled();
|
||||
if (ImGui::Button("Dead Code Elimination")) {
|
||||
TransformEngine engine;
|
||||
engine.setRoot(ast);
|
||||
auto res = engine.deadCodeElimination();
|
||||
std::string summary = "Dead Code Elimination: ";
|
||||
if (res.applied) {
|
||||
summary += "applied (" + std::to_string(res.nodesModified) + " nodes)";
|
||||
} else {
|
||||
summary += "no changes";
|
||||
}
|
||||
if (!res.warning.empty()) {
|
||||
summary += " — warning: " + res.warning;
|
||||
state.outputLog += res.warning + "\n";
|
||||
}
|
||||
state.optimizeDeadCodeSummary = summary;
|
||||
state.outputLog += summary + "\n";
|
||||
if (res.applied) state.refreshActiveTextFromAST();
|
||||
}
|
||||
showBlockedTooltip(blockReason);
|
||||
if (blocked) ImGui::EndDisabled();
|
||||
if (!state.optimizeDeadCodeSummary.empty()) {
|
||||
ImGui::TextWrapped("%s", state.optimizeDeadCodeSummary.c_str());
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (blocked) ImGui::BeginDisabled();
|
||||
if (ImGui::Button("Apply All")) {
|
||||
TransformEngine engine;
|
||||
engine.setRoot(ast);
|
||||
auto results = engine.applyAll();
|
||||
int totalNodes = 0;
|
||||
bool applied = false;
|
||||
std::string warnings;
|
||||
for (const auto& res : results) {
|
||||
totalNodes += res.nodesModified;
|
||||
if (res.applied) applied = true;
|
||||
if (!res.warning.empty()) {
|
||||
if (!warnings.empty()) warnings += "; ";
|
||||
warnings += res.warning;
|
||||
}
|
||||
}
|
||||
std::string summary = "Apply All: ";
|
||||
if (applied) {
|
||||
summary += "applied (" + std::to_string(totalNodes) + " nodes)";
|
||||
} else {
|
||||
summary += "no changes";
|
||||
}
|
||||
if (!warnings.empty()) {
|
||||
summary += " — warning: " + warnings;
|
||||
state.outputLog += warnings + "\n";
|
||||
}
|
||||
state.optimizeApplySummary = summary;
|
||||
state.outputLog += summary + "\n";
|
||||
if (applied) state.refreshActiveTextFromAST();
|
||||
}
|
||||
showBlockedTooltip(blockReason);
|
||||
if (blocked) ImGui::EndDisabled();
|
||||
if (!state.optimizeApplySummary.empty()) {
|
||||
ImGui::TextWrapped("%s", state.optimizeApplySummary.c_str());
|
||||
}
|
||||
}
|
||||
ImGui::PopFont();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// AST view
|
||||
if (ImGui::BeginTabItem("AST")) {
|
||||
ImGui::PushFont(monoFont);
|
||||
|
||||
56
editor/tests/step105_test.cpp
Normal file
56
editor/tests/step105_test.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Step 105 TDD Test: Optimization controls
|
||||
//
|
||||
// Tests:
|
||||
// 1. StrategyAwareOptimizer blocks optimization when @Owner(Single) present
|
||||
// 2. TransformEngine constant folding modifies nodes
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include "StrategyAwareOptimizer.h"
|
||||
#include "TransformEngine.h"
|
||||
#include "ast/Module.h"
|
||||
#include "ast/Function.h"
|
||||
#include "ast/Statement.h"
|
||||
#include "ast/Expression.h"
|
||||
#include "ast/Annotation.h"
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
Module mod("m1", "mod", "python");
|
||||
auto* fn = new Function("f1", "foo");
|
||||
auto* owner = new OwnerAnnotation("a1", "Single");
|
||||
fn->addChild("annotations", owner);
|
||||
mod.addChild("functions", fn);
|
||||
|
||||
StrategyAwareOptimizer opt;
|
||||
opt.setRoot(&mod);
|
||||
auto res = opt.optimizeFunction("f1");
|
||||
assert(!res.blocked.empty());
|
||||
std::cout << "Test 1 PASS: optimization blocked by annotation" << std::endl;
|
||||
++passed;
|
||||
|
||||
Module mod2("m2", "mod2", "python");
|
||||
auto* fn2 = new Function("f2", "bar");
|
||||
auto* ret = new Return();
|
||||
ret->id = "r1";
|
||||
auto* bin = new BinaryOperation("b1", "+");
|
||||
auto* left = new IntegerLiteral("i1", 2);
|
||||
auto* right = new IntegerLiteral("i2", 3);
|
||||
bin->setChild("left", left);
|
||||
bin->setChild("right", right);
|
||||
ret->setChild("value", bin);
|
||||
fn2->addChild("body", ret);
|
||||
mod2.addChild("functions", fn2);
|
||||
|
||||
TransformEngine engine;
|
||||
engine.setRoot(&mod2);
|
||||
auto foldRes = engine.constantFolding();
|
||||
assert(foldRes.applied && foldRes.nodesModified > 0);
|
||||
std::cout << "Test 2 PASS: constant folding applied" << std::endl;
|
||||
++passed;
|
||||
|
||||
std::cout << "\n=== Step 105 Results: " << passed << " passed, " << failed << " failed ===" << std::endl;
|
||||
return failed > 0 ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user