Step 105: add optimization controls panel

This commit is contained in:
Bill
2026-02-09 11:02:25 -07:00
parent 8a85ba298d
commit f7da8eee8d
4 changed files with 228 additions and 0 deletions

View File

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

View File

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

View File

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

View 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;
}