#pragma once #include #include #include #include #include #include #include #include #include "ast/ASTNode.h" #include "ast/Expression.h" #include "ast/Statement.h" class IncrementalOptimizer { public: struct TransformRecord { std::string transformId; std::string transformName; std::vector affectedNodeIds; std::string timestamp; std::string actor; bool reversible = true; }; void setRoot(ASTNode* root) { root_ = root; } std::string applyTransform(const std::string& transformName) { std::string tid = "t" + std::to_string(nextId_++); InternalRecord record; record.info.transformId = tid; record.info.transformName = transformName; record.info.timestamp = currentTimestamp(); record.info.actor = "optimizer"; if (transformName == "constant-fold") { applyConstantFolding(root_, tid, record); } else if (transformName == "dead-code-elim") { applyDeadCodeElim(root_, tid, record); } history_.push_back(std::move(record)); return tid; } std::vector getTransformHistory() const { std::vector result; for (const auto& r : history_) { result.push_back(r.info); } return result; } std::string recordExternalTransform(const std::string& transformName, const std::vector& affectedNodeIds, const std::string& actor) { std::string tid = "t" + std::to_string(nextId_++); InternalRecord record; record.info.transformId = tid; record.info.transformName = transformName; record.info.timestamp = currentTimestamp(); record.info.actor = actor; record.info.reversible = false; record.info.affectedNodeIds = affectedNodeIds; for (const auto& nodeId : affectedNodeIds) { provenance_[nodeId] = tid; } history_.push_back(std::move(record)); return tid; } bool undoTransform(const std::string& transformId) { for (auto it = history_.begin(); it != history_.end(); ++it) { if (it->info.transformId == transformId) { if (!it->info.reversible) return false; // Apply undo actions in reverse order for (auto ait = it->undoActions.rbegin(); ait != it->undoActions.rend(); ++ait) { ait->undo(); } // Remove provenance entries for this transform for (const auto& nodeId : it->info.affectedNodeIds) { provenance_.erase(nodeId); } history_.erase(it); return true; } } return false; } bool undoLast() { if (history_.empty()) return false; return undoTransform(history_.back().info.transformId); } std::string getProvenance(const std::string& nodeId) const { auto it = provenance_.find(nodeId); return it != provenance_.end() ? it->second : ""; } static std::string currentTimestamp() { auto now = std::chrono::system_clock::now(); std::time_t tt = std::chrono::system_clock::to_time_t(now); std::tm tm{}; #ifdef _WIN32 localtime_s(&tm, &tt); #else localtime_r(&tt, &tm); #endif std::ostringstream oss; oss << std::put_time(&tm, "%H:%M:%S"); return oss.str(); } private: ASTNode* root_ = nullptr; int nextId_ = 1; struct UndoAction { std::function undo; }; struct InternalRecord { TransformRecord info; std::vector undoActions; }; std::vector history_; std::map provenance_; // nodeId → transformId void applyConstantFolding(ASTNode* node, const std::string& tid, InternalRecord& record) { // Bottom-up: process children first for (const auto& role : node->childRoles()) { auto children = node->getChildren(role); for (auto* child : children) { applyConstantFolding(child, tid, record); } } // Check each child role for foldable BinaryOperations 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(child); auto* leftNode = binOp->getChild("left"); auto* rightNode = binOp->getChild("right"); if (leftNode && rightNode && leftNode->conceptType == "IntegerLiteral" && rightNode->conceptType == "IntegerLiteral") { auto* leftLit = static_cast(leftNode); auto* rightLit = static_cast(rightNode); int foldedValue = evaluateOp(binOp->op, leftLit->value, rightLit->value); auto* replacement = new IntegerLiteral("folded_" + binOp->id, foldedValue); // Record undo: restore old child ASTNode* parent = node; std::string savedRole = role; ASTNode* oldChild = child; record.undoActions.push_back({[parent, savedRole, oldChild]() { parent->setChild(savedRole, oldChild); }}); node->setChild(role, replacement); // Track provenance and affected nodes provenance_[replacement->id] = tid; record.info.affectedNodeIds.push_back(replacement->id); } } } } } void applyDeadCodeElim(ASTNode* node, const std::string& tid, InternalRecord& record) { if (node->conceptType == "Function") { auto body = node->getChildren("body"); bool foundReturn = false; std::vector toRemove; for (auto* stmt : body) { if (foundReturn) { toRemove.push_back(stmt); } if (stmt->conceptType == "Return") { foundReturn = true; } } for (auto* dead : toRemove) { // Record undo: re-add the removed child ASTNode* parent = node; ASTNode* removedChild = dead; record.undoActions.push_back({[parent, removedChild]() { parent->addChild("body", removedChild); }}); node->removeChild(dead); record.info.affectedNodeIds.push_back(dead->id); } } // Recurse for (auto* child : node->allChildren()) { applyDeadCodeElim(child, tid, record); } } 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; } };