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 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 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 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 102:** Compile and pass (1/1)
|
||||||
**Step 103:** Compile and pass (1/1)
|
**Step 103:** Compile and pass (1/1)
|
||||||
**Step 104:** Compile and pass (2/2)
|
**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 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 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 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_include_directories(step104_test PRIVATE src)
|
||||||
target_link_libraries(step104_test PRIVATE nlohmann_json::nlohmann_json)
|
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(SDL2 CONFIG REQUIRED)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
find_package(glad CONFIG REQUIRED)
|
find_package(glad CONFIG REQUIRED)
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
#include "MemoryStrategyInference.h"
|
#include "MemoryStrategyInference.h"
|
||||||
#include "AnnotationConflict.h"
|
#include "AnnotationConflict.h"
|
||||||
#include "StrategyDashboard.h"
|
#include "StrategyDashboard.h"
|
||||||
|
#include "TransformEngine.h"
|
||||||
|
#include "StrategyAwareOptimizer.h"
|
||||||
#include "CrossLanguageProjector.h"
|
#include "CrossLanguageProjector.h"
|
||||||
#include "ast/Generator.h"
|
#include "ast/Generator.h"
|
||||||
#include "ast/Annotation.h"
|
#include "ast/Annotation.h"
|
||||||
@@ -127,6 +129,9 @@ struct EditorState {
|
|||||||
std::vector<MemoryStrategyInference::Suggestion> suggestions;
|
std::vector<MemoryStrategyInference::Suggestion> suggestions;
|
||||||
bool showSuggestionPopup = false;
|
bool showSuggestionPopup = false;
|
||||||
MemoryStrategyInference::Suggestion suggestionPopup;
|
MemoryStrategyInference::Suggestion suggestionPopup;
|
||||||
|
std::string optimizeFoldSummary;
|
||||||
|
std::string optimizeDeadCodeSummary;
|
||||||
|
std::string optimizeApplySummary;
|
||||||
|
|
||||||
BufferState* active() { return activeBuffer; }
|
BufferState* active() { return activeBuffer; }
|
||||||
|
|
||||||
@@ -523,6 +528,20 @@ struct EditorState {
|
|||||||
(preserved ? "yes" : "no") + ").\n";
|
(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) {
|
void updateCursorPos(int bytePos) {
|
||||||
if (!active()) return;
|
if (!active()) return;
|
||||||
active()->cursorLine = 1;
|
active()->cursorLine = 1;
|
||||||
@@ -591,6 +610,35 @@ static int countAnnotationNodes(const ASTNode* node) {
|
|||||||
return count;
|
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
|
// ImGui InputTextMultiline with std::string resize callback
|
||||||
@@ -1954,6 +2002,123 @@ int main(int, char**) {
|
|||||||
ImGui::EndTabItem();
|
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
|
// AST view
|
||||||
if (ImGui::BeginTabItem("AST")) {
|
if (ImGui::BeginTabItem("AST")) {
|
||||||
ImGui::PushFont(monoFont);
|
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