Files
whetstone_DSL/editor/tests/step66_test.cpp
Bill 650e8557ae Phase 3f complete: Advanced Memory Management (Steps 64-67)
Step 64: AnnotationValidator — @Deallocate missing-intent, @Owner(Single) alias detection, parent/child conflict (5/5 tests)
Step 65: MemoryStrategyInference — language defaults, per-function pattern analysis, confidence scores (5/5 tests)
Step 66: CrossLanguageProjector — deep-copy AST projection, annotation-aware CppGenerator (shared_ptr/unique_ptr) (5/5 tests)
Step 67: Optimization annotations — HotCold, Inline, Pure, ConstExpr with C++ attribute generation (9/9 tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 20:57:58 -07:00

196 lines
6.4 KiB
C++

// Step 66 TDD Test: Cross-language memory projection
//
// Tests the "Lossless Projection Logic" from Memory strategy.md Section 3:
// 1. Python → C++: @Reclaim(Tracing) → inject ref-counting shim (shared_ptr)
// 2. C++ → Python: @Deallocate(Explicit) → wrap in try-with-resources pattern
// 3. Rust-like → Python: @Owner(Single) → preserve in metadata, don't enforce
// 4. Round-trip: annotation survives language round-trip
// 5. @Lifetime(RAII) → inject destructor calls at scope end
//
// Will fail until cross-language projection is implemented.
#include <iostream>
#include <string>
#include <cassert>
#include "ast/ASTNode.h"
#include "ast/Module.h"
#include "ast/Function.h"
#include "ast/Variable.h"
#include "ast/Annotation.h"
#include "ast/Generator.h"
static bool contains(const std::string& haystack, const std::string& needle) {
return haystack.find(needle) != std::string::npos;
}
#include "CrossLanguageProjector.h"
int main() {
int passed = 0;
int failed = 0;
CrossLanguageProjector projector;
// --- Test 1: Python @Reclaim(Tracing) → C++ shared_ptr ---
{
Module pyMod("m1", "PyModule", "python");
Function* fn = new Function("f1", "process");
ReclaimAnnotation* anno = new ReclaimAnnotation();
anno->id = "a1";
anno->strategy = "Tracing";
fn->addChild("annotations", anno);
Variable* var = new Variable("v1", "data");
fn->addChild("body", var);
pyMod.addChild("functions", fn);
auto cppMod = projector.project(&pyMod, "cpp");
assert(cppMod != nullptr && "Projection should produce a module");
assert(cppMod->targetLanguage == "cpp" && "Target should be cpp");
// Generate C++ from the projected module
CppGenerator gen;
std::string output = gen.generate(cppMod.get());
// @Reclaim(Tracing) in C++ → should use shared_ptr for GC-like semantics
assert(contains(output, "shared_ptr") &&
"Python @Reclaim(Tracing) → C++ should use shared_ptr");
std::cout << "Test 1 PASS: Python @Reclaim(Tracing) → C++ shared_ptr" << std::endl;
++passed;
delete var;
delete anno;
delete fn;
}
// --- Test 2: C++ @Deallocate(Explicit) → Python wrapper ---
{
Module cppMod("m1", "CppModule", "cpp");
Function* fn = new Function("f1", "allocate");
DeallocateAnnotation* anno = new DeallocateAnnotation();
anno->id = "a1";
anno->strategy = "Explicit";
fn->addChild("annotations", anno);
Variable* var = new Variable("v1", "ptr");
fn->addChild("body", var);
cppMod.addChild("functions", fn);
auto pyMod = projector.project(&cppMod, "python");
assert(pyMod != nullptr && "Projection should produce a module");
assert(pyMod->targetLanguage == "python" && "Target should be python");
// The annotation should still be present in metadata
auto projectedFns = pyMod->getChildren("functions");
assert(!projectedFns.empty() && "Should have functions");
std::cout << "Test 2 PASS: C++ @Deallocate(Explicit) → Python projection" << std::endl;
++passed;
delete var;
delete anno;
delete fn;
}
// --- Test 3: @Owner(Single) → Python preserves in metadata ---
{
Module rustLike("m1", "RustLike", "cpp");
Function* fn = new Function("f1", "ownership");
OwnerAnnotation* anno = new OwnerAnnotation();
anno->id = "a1";
anno->strategy = "Single";
fn->addChild("annotations", anno);
rustLike.addChild("functions", fn);
auto pyMod = projector.project(&rustLike, "python");
// @Owner(Single) should be preserved in metadata even though Python doesn't enforce it
auto projectedFns = pyMod->getChildren("functions");
auto* projectedFn = static_cast<Function*>(projectedFns[0]);
auto annos = projectedFn->getChildren("annotations");
bool hasOwner = false;
for (auto* a : annos) {
if (a->conceptType == "OwnerAnnotation") {
hasOwner = true;
}
}
assert(hasOwner && "@Owner(Single) should be preserved in Python projection metadata");
std::cout << "Test 3 PASS: @Owner(Single) preserved in Python metadata" << std::endl;
++passed;
delete anno;
delete fn;
}
// --- Test 4: Round-trip preserves annotations ---
{
Module pyMod("m1", "RoundTrip", "python");
Function* fn = new Function("f1", "process");
ReclaimAnnotation* anno = new ReclaimAnnotation();
anno->id = "a1";
anno->strategy = "Tracing";
fn->addChild("annotations", anno);
pyMod.addChild("functions", fn);
// Python → C++
auto cppMod = projector.project(&pyMod, "cpp");
// C++ → Python
auto pyModBack = projector.project(cppMod.get(), "python");
// Annotation should survive round-trip
assert(projector.annotationsPreserved(&pyMod, pyModBack.get()) &&
"Annotations should survive Python → C++ → Python round-trip");
std::cout << "Test 4 PASS: Round-trip preserves annotations" << std::endl;
++passed;
delete anno;
delete fn;
}
// --- Test 5: @Lifetime(RAII) in C++ generation ---
{
Module cppMod("m1", "RAIIModule", "cpp");
Function* fn = new Function("f1", "scoped");
LifetimeAnnotation* anno = new LifetimeAnnotation();
anno->id = "a1";
anno->strategy = "RAII";
fn->addChild("annotations", anno);
Variable* var = new Variable("v1", "resource");
fn->addChild("body", var);
PrimitiveType* retType = new PrimitiveType("t1", "void");
fn->setChild("returnType", retType);
cppMod.addChild("functions", fn);
CppGenerator gen;
std::string output = gen.generate(&cppMod);
// @Lifetime(RAII) → unique_ptr with RAII semantics
assert(contains(output, "unique_ptr") &&
"@Lifetime(RAII) should produce unique_ptr in C++");
std::cout << "Test 5 PASS: @Lifetime(RAII) generates unique_ptr" << std::endl;
++passed;
delete retType;
delete var;
delete anno;
delete fn;
}
// --- Summary ---
std::cout << "\n=== Step 66 Results: " << passed << " passed, " << failed << " failed ===" << std::endl;
return failed > 0 ? 1 : 0;
}