Sprint 3 complete: Phases 3g+3h (Steps 68-75), all 75 steps done
Phase 3g — Optimization Pipeline (17/17 tests): Step 68: TransformEngine — constant folding, dead code elimination, OptimizationLock warning Step 69: StrategyAwareOptimizer — annotation-constrained (@Reclaim allows, @Owner blocks duplication, @Deallocate blocks reorder, @Allocate blocks dynamic) Step 70: StrategyValidator — post-optimization invariants (use-after-free, leak, aliasing) Step 71: IncrementalOptimizer — transform journal, undo by ID, provenance tracking Phase 3h — Integration & Validation (26/26 tests): Step 72: Pipeline — end-to-end parse→infer→validate→optimize→generate for Python/C++ Step 73: Error handling — empty ASTs, null roots, nonexistent IDs, unannotated code Step 74: Performance benchmarks — 1000-fn AST 1ms, JSON round-trip 4ms, 50 transforms+undo 1ms Step 75: APIDocGenerator — structured docs for 23 components across 6 categories Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
145
editor/src/TransformEngine.h
Normal file
145
editor/src/TransformEngine.h
Normal file
@@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include "ast/ASTNode.h"
|
||||
#include "ast/Expression.h"
|
||||
#include "ast/Statement.h"
|
||||
#include "ast/Annotation.h"
|
||||
|
||||
class TransformEngine {
|
||||
public:
|
||||
struct TransformResult {
|
||||
bool applied;
|
||||
std::string warning;
|
||||
int nodesModified;
|
||||
};
|
||||
|
||||
void setRoot(ASTNode* root) { root_ = root; }
|
||||
|
||||
TransformResult constantFolding() {
|
||||
TransformResult result{false, "", 0};
|
||||
if (!root_) return result;
|
||||
std::string lockWarning = checkOptimizationLock(root_);
|
||||
foldConstants(root_, result);
|
||||
if (!lockWarning.empty() && result.applied) {
|
||||
result.warning = lockWarning;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TransformResult deadCodeElimination() {
|
||||
TransformResult result{false, "", 0};
|
||||
if (!root_) return result;
|
||||
eliminateDeadCode(root_, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<TransformResult> applyAll() {
|
||||
std::vector<TransformResult> results;
|
||||
results.push_back(constantFolding());
|
||||
results.push_back(deadCodeElimination());
|
||||
return results;
|
||||
}
|
||||
|
||||
private:
|
||||
ASTNode* root_ = nullptr;
|
||||
|
||||
// Recursively fold constant BinaryOperations on IntegerLiterals
|
||||
void foldConstants(ASTNode* node, TransformResult& result) {
|
||||
// Process children first (bottom-up) so nested folds work
|
||||
for (const auto& role : node->childRoles()) {
|
||||
auto children = node->getChildren(role);
|
||||
for (auto* child : children) {
|
||||
foldConstants(child, result);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this node's parent has a child that is a foldable BinaryOperation
|
||||
// We look at each child role for BinaryOperations we can fold
|
||||
for (const auto& role : node->childRoles()) {
|
||||
auto children = node->getChildren(role);
|
||||
for (size_t i = 0; i < children.size(); ++i) {
|
||||
auto* child = children[i];
|
||||
if (child->conceptType == "BinaryOperation") {
|
||||
auto* binOp = static_cast<BinaryOperation*>(child);
|
||||
auto* leftNode = binOp->getChild("left");
|
||||
auto* rightNode = binOp->getChild("right");
|
||||
|
||||
if (leftNode && rightNode &&
|
||||
leftNode->conceptType == "IntegerLiteral" &&
|
||||
rightNode->conceptType == "IntegerLiteral") {
|
||||
|
||||
auto* leftLit = static_cast<IntegerLiteral*>(leftNode);
|
||||
auto* rightLit = static_cast<IntegerLiteral*>(rightNode);
|
||||
int foldedValue = evaluateOp(binOp->op, leftLit->value, rightLit->value);
|
||||
|
||||
auto* replacement = new IntegerLiteral("folded_" + binOp->id, foldedValue);
|
||||
node->setChild(role, replacement);
|
||||
|
||||
result.applied = true;
|
||||
result.nodesModified++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int evaluateOp(const std::string& op, int left, int right) {
|
||||
if (op == "+") return left + right;
|
||||
if (op == "-") return left - right;
|
||||
if (op == "*") return left * right;
|
||||
if (op == "/" && right != 0) return left / right;
|
||||
if (op == "%") return left % right;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove statements after Return in function bodies
|
||||
void eliminateDeadCode(ASTNode* node, TransformResult& result) {
|
||||
if (node->conceptType == "Function") {
|
||||
auto body = node->getChildren("body");
|
||||
bool foundReturn = false;
|
||||
std::vector<ASTNode*> toRemove;
|
||||
|
||||
for (auto* stmt : body) {
|
||||
if (foundReturn) {
|
||||
toRemove.push_back(stmt);
|
||||
}
|
||||
if (stmt->conceptType == "Return") {
|
||||
foundReturn = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* dead : toRemove) {
|
||||
node->removeChild(dead);
|
||||
result.applied = true;
|
||||
result.nodesModified++;
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into children
|
||||
for (auto* child : node->allChildren()) {
|
||||
eliminateDeadCode(child, result);
|
||||
}
|
||||
}
|
||||
|
||||
// Walk ancestors for OptimizationLock annotations
|
||||
std::string checkOptimizationLock(ASTNode* node) {
|
||||
std::string warning;
|
||||
checkOptimizationLockRecursive(node, warning);
|
||||
return warning;
|
||||
}
|
||||
|
||||
void checkOptimizationLockRecursive(ASTNode* node, std::string& warning) {
|
||||
if (node->conceptType == "OptimizationLock") {
|
||||
auto* lock = static_cast<OptimizationLock*>(node);
|
||||
if (lock->lockLevel == "warning") {
|
||||
warning = "OptimizationLock: " + lock->lockReason +
|
||||
" (locked by " + lock->lockedBy + ")";
|
||||
}
|
||||
}
|
||||
for (auto* child : node->allChildren()) {
|
||||
checkOptimizationLockRecursive(child, warning);
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user