Files
whetstone_DSL/editor/src/IncrementalOptimizer.h

224 lines
7.5 KiB
C++

#pragma once
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>
#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<std::string> 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<TransformRecord> getTransformHistory() const {
std::vector<TransformRecord> result;
for (const auto& r : history_) {
result.push_back(r.info);
}
return result;
}
std::string recordExternalTransform(const std::string& transformName,
const std::vector<std::string>& 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<void()> undo;
};
struct InternalRecord {
TransformRecord info;
std::vector<UndoAction> undoActions;
};
std::vector<InternalRecord> history_;
std::map<std::string, std::string> 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<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);
// 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<ASTNode*> 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;
}
};