Phase 11b — Validation & Conflict Completion: - Step 297: Subject 2-4 validation rules E0600-E0805 (12/12) - Step 298: Subject 5-8 validation rules E0900-E1202 (12/12) - Step 299: Cross-type conflict detection, 6 conflict pairs (12/12) - Step 300: TransformEngineExtended — float folding, dead var, annotation-aware (12/12) - Step 301: Phase 11b integration tests (8/8) Phase 11c — Parser Deepening (start): - Step 302: New AST nodes — ClassDeclaration, InterfaceDeclaration, MethodDeclaration, GenericType, TypeParameter with JSON roundtrip (12/12) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
214 lines
7.6 KiB
C++
214 lines
7.6 KiB
C++
#pragma once
|
|
// Step 300: Extended transform engine
|
|
//
|
|
// Adds float constant folding, dead variable elimination,
|
|
// and annotation-aware optimization to the base TransformEngine.
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <cstdlib>
|
|
#include "TransformEngine.h"
|
|
#include "ast/ASTNode.h"
|
|
#include "ast/Expression.h"
|
|
#include "ast/Variable.h"
|
|
#include "ast/Function.h"
|
|
#include "ast/Annotation.h"
|
|
|
|
class TransformEngineExtended : public TransformEngine {
|
|
public:
|
|
// Float constant folding: folds BinaryOperations on FloatLiterals
|
|
TransformResult floatConstantFolding() {
|
|
TransformResult result{false, "", 0};
|
|
if (!root_) return result;
|
|
foldFloatConstants(root_, result);
|
|
return result;
|
|
}
|
|
|
|
// Dead variable elimination: removes unused variable declarations
|
|
TransformResult deadVariableElimination() {
|
|
TransformResult result{false, "", 0};
|
|
if (!root_) return result;
|
|
eliminateDeadVariables(root_, result);
|
|
return result;
|
|
}
|
|
|
|
// Annotation-aware: skip nodes with @OptimizationLock, preserve @BoundsCheck
|
|
TransformResult annotationAwareOptimize() {
|
|
TransformResult result{false, "", 0};
|
|
if (!root_) return result;
|
|
|
|
// Check for OptimizationLock
|
|
if (hasAnnotationType(root_, "OptimizationLock")) {
|
|
result.warning = "Optimization skipped: OptimizationLock present";
|
|
return result;
|
|
}
|
|
|
|
// Apply folding, skip BoundsCheck-protected nodes
|
|
foldConstantsSkipProtected(root_, result);
|
|
return result;
|
|
}
|
|
|
|
// Apply all extended transforms
|
|
TransformResult applyAllExtended() {
|
|
TransformResult combined{false, "", 0};
|
|
|
|
auto r1 = floatConstantFolding();
|
|
auto r2 = deadVariableElimination();
|
|
auto r3 = annotationAwareOptimize();
|
|
|
|
combined.applied = r1.applied || r2.applied || r3.applied;
|
|
combined.nodesModified = r1.nodesModified + r2.nodesModified + r3.nodesModified;
|
|
if (!r3.warning.empty()) combined.warning = r3.warning;
|
|
|
|
return combined;
|
|
}
|
|
|
|
protected:
|
|
// Extended root pointer accessible in this class
|
|
ASTNode* root_ = nullptr;
|
|
|
|
public:
|
|
void setRoot(ASTNode* root) {
|
|
root_ = root;
|
|
TransformEngine::setRoot(root);
|
|
}
|
|
|
|
private:
|
|
// Recursively fold constant BinaryOperations on FloatLiterals (bottom-up)
|
|
void foldFloatConstants(ASTNode* node, TransformResult& result) {
|
|
if (!node) return;
|
|
|
|
// Process children first (bottom-up) so nested folds work
|
|
for (const auto& role : node->childRoles()) {
|
|
auto children = node->getChildren(role);
|
|
for (auto* child : children) {
|
|
foldFloatConstants(child, result);
|
|
}
|
|
}
|
|
|
|
// Check each child role for foldable BinaryOperations on float operands
|
|
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* left = binOp->getChild("left");
|
|
auto* right = binOp->getChild("right");
|
|
|
|
if (left && right &&
|
|
left->conceptType == "FloatLiteral" &&
|
|
right->conceptType == "FloatLiteral") {
|
|
|
|
double lv = std::stod(static_cast<FloatLiteral*>(left)->value);
|
|
double rv = std::stod(static_cast<FloatLiteral*>(right)->value);
|
|
double res = 0;
|
|
|
|
if (binOp->op == "+") res = lv + rv;
|
|
else if (binOp->op == "-") res = lv - rv;
|
|
else if (binOp->op == "*") res = lv * rv;
|
|
else if (binOp->op == "/" && rv != 0) res = lv / rv;
|
|
else continue;
|
|
|
|
auto* replacement = new FloatLiteral();
|
|
replacement->id = "folded_" + binOp->id;
|
|
replacement->value = std::to_string(res);
|
|
node->setChild(role, replacement);
|
|
|
|
result.applied = true;
|
|
result.nodesModified++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove variable declarations that are never referenced in the function body
|
|
void eliminateDeadVariables(ASTNode* node, TransformResult& result) {
|
|
if (!node) return;
|
|
|
|
if (node->conceptType == "Function") {
|
|
auto body = node->getChildren("body");
|
|
|
|
// Collect declared variable names
|
|
std::vector<std::string> declaredVars;
|
|
for (auto* stmt : body) {
|
|
if (stmt->conceptType == "Variable") {
|
|
declaredVars.push_back(static_cast<Variable*>(stmt)->name);
|
|
}
|
|
}
|
|
|
|
// Check if each variable is referenced anywhere in the body
|
|
for (const auto& varName : declaredVars) {
|
|
bool used = false;
|
|
for (auto* stmt : body) {
|
|
if (stmt->conceptType != "Variable" && hasReference(stmt, varName)) {
|
|
used = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!used) {
|
|
// Remove the variable declaration
|
|
for (auto* stmt : body) {
|
|
if (stmt->conceptType == "Variable" &&
|
|
static_cast<Variable*>(stmt)->name == varName) {
|
|
node->removeChild(stmt);
|
|
result.applied = true;
|
|
result.nodesModified++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto* child : node->allChildren()) {
|
|
eliminateDeadVariables(child, result);
|
|
}
|
|
}
|
|
|
|
// Check if a subtree contains a VariableReference to the given name
|
|
bool hasReference(const ASTNode* node, const std::string& name) const {
|
|
if (!node) return false;
|
|
if (node->conceptType == "VariableReference") {
|
|
if (static_cast<const VariableReference*>(node)->variableName == name)
|
|
return true;
|
|
}
|
|
for (auto* child : node->allChildren()) {
|
|
if (hasReference(child, name)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Recursively check if any node in the subtree has the given annotation type
|
|
bool hasAnnotationType(const ASTNode* node, const std::string& type) const {
|
|
if (!node) return false;
|
|
for (const auto* anno : node->getChildren("annotations")) {
|
|
if (anno->conceptType == type) return true;
|
|
}
|
|
for (auto* child : node->allChildren()) {
|
|
if (hasAnnotationType(child, type)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Fold constants but skip nodes protected by BoundsCheck or OptimizationLock
|
|
void foldConstantsSkipProtected(ASTNode* node, TransformResult& result) {
|
|
if (!node) return;
|
|
|
|
// Skip nodes with BoundsCheck or OptimizationLock annotations
|
|
for (const auto* anno : node->getChildren("annotations")) {
|
|
if (anno->conceptType == "BoundsCheckAnnotation" ||
|
|
anno->conceptType == "OptimizationLock")
|
|
return;
|
|
}
|
|
|
|
for (const auto& role : node->childRoles()) {
|
|
auto children = node->getChildren(role);
|
|
for (auto* child : children) {
|
|
foldConstantsSkipProtected(child, result);
|
|
}
|
|
}
|
|
}
|
|
};
|