Complete step453 memory model translation with tests

This commit is contained in:
Bill
2026-02-16 19:43:42 -07:00
parent dae03ac827
commit fdc602a2db
4 changed files with 429 additions and 0 deletions

View File

@@ -2956,4 +2956,13 @@ target_link_libraries(step452_test PRIVATE
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step453_test tests/step453_test.cpp)
target_include_directories(step453_test PRIVATE src)
target_link_libraries(step453_test PRIVATE
nlohmann_json::nlohmann_json
unofficial::tree-sitter::tree-sitter
tree_sitter_python tree_sitter_cpp tree_sitter_elisp
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)

View File

@@ -0,0 +1,249 @@
#pragma once
// Step 453: Memory Model Translation — translates ownership/lifecycle across
// memory models with safety tracking annotations.
#include <string>
#include <vector>
enum class OwnershipModel { Manual, RAII, GC, BorrowChecked, ARC };
enum class SafetyDelta { Gained, Lost, Neutral };
struct MemoryTranslation {
std::string pattern; // e.g. "@Owner(Unique)", "@Owner(Shared_ARC)"
OwnershipModel sourceModel;
OwnershipModel targetModel;
std::string sourceLanguage;
std::string targetLanguage;
std::string sourceCode;
std::string targetCode;
SafetyDelta safetyChange = SafetyDelta::Neutral;
std::string annotation;
std::string note;
};
struct MemoryAnalysisResult {
std::string sourceLanguage;
std::string targetLanguage;
OwnershipModel sourceModel = OwnershipModel::Manual;
OwnershipModel targetModel = OwnershipModel::Manual;
std::vector<MemoryTranslation> translations;
bool hasPattern(const std::string& p) const {
for (const auto& t : translations)
if (t.pattern == p) return true;
return false;
}
int countSafetyGained() const {
int n = 0;
for (const auto& t : translations)
if (t.safetyChange == SafetyDelta::Gained) ++n;
return n;
}
int countSafetyLost() const {
int n = 0;
for (const auto& t : translations)
if (t.safetyChange == SafetyDelta::Lost) ++n;
return n;
}
};
class MemoryModelTranslator {
public:
static MemoryAnalysisResult analyze(const std::string& source,
const std::string& srcLang,
const std::string& tgtLang) {
MemoryAnalysisResult result;
result.sourceLanguage = srcLang;
result.targetLanguage = tgtLang;
result.sourceModel = detectOwnership(source, srcLang);
result.targetModel = defaultOwnership(tgtLang);
if (hasUniqueOwnership(source, srcLang))
result.translations.push_back(translateUnique(srcLang, tgtLang));
if (hasSharedOwnership(source, srcLang))
result.translations.push_back(translateShared(srcLang, tgtLang));
if (hasManualMemory(source))
result.translations.push_back(translateManual(srcLang, tgtLang));
if (hasScopeLifetime(source))
result.translations.push_back(translateScope(srcLang, tgtLang));
return result;
}
private:
static OwnershipModel detectOwnership(const std::string& src, const std::string& lang) {
if (lang == "rust") return OwnershipModel::BorrowChecked;
if (lang == "python" || lang == "java" || lang == "go" || lang == "javascript")
return OwnershipModel::GC;
if (src.find("unique_ptr") != std::string::npos ||
src.find("shared_ptr") != std::string::npos) return OwnershipModel::RAII;
if (src.find("malloc") != std::string::npos ||
src.find("free(") != std::string::npos) return OwnershipModel::Manual;
if (lang == "cpp" || lang == "c++") return OwnershipModel::RAII;
if (lang == "c") return OwnershipModel::Manual;
return OwnershipModel::Manual;
}
static OwnershipModel defaultOwnership(const std::string& lang) {
if (lang == "rust") return OwnershipModel::BorrowChecked;
if (lang == "cpp" || lang == "c++") return OwnershipModel::RAII;
if (lang == "c") return OwnershipModel::Manual;
if (lang == "python" || lang == "java" || lang == "go" || lang == "javascript")
return OwnershipModel::GC;
return OwnershipModel::Manual;
}
static bool hasUniqueOwnership(const std::string& src, const std::string& lang) {
if (lang == "rust") return src.find("Box<") != std::string::npos || src.find("let mut") != std::string::npos;
if (lang == "cpp") return src.find("unique_ptr") != std::string::npos;
return false;
}
static bool hasSharedOwnership(const std::string& src, const std::string& lang) {
if (lang == "rust") return src.find("Arc<") != std::string::npos || src.find("Rc<") != std::string::npos;
if (lang == "cpp") return src.find("shared_ptr") != std::string::npos;
return false;
}
static bool hasManualMemory(const std::string& src) {
return src.find("malloc(") != std::string::npos ||
src.find("calloc(") != std::string::npos ||
src.find("free(") != std::string::npos ||
src.find("new ") != std::string::npos;
}
static bool hasScopeLifetime(const std::string& src) {
return src.find("RAII") != std::string::npos ||
src.find("defer ") != std::string::npos ||
src.find("try-finally") != std::string::npos ||
src.find("with ") != std::string::npos ||
src.find("using (") != std::string::npos;
}
static MemoryTranslation translateUnique(const std::string& src, const std::string& tgt) {
MemoryTranslation t;
t.pattern = "@Owner(Unique)";
t.sourceLanguage = src;
t.targetLanguage = tgt;
if (tgt == "rust") {
t.targetCode = "Box::new(value) or owned value";
t.safetyChange = (src == "c") ? SafetyDelta::Gained : SafetyDelta::Neutral;
t.annotation = "@Owner(Unique), @Lifetime(owned)";
} else if (tgt == "cpp" || tgt == "c++") {
t.targetCode = "std::unique_ptr<T>(new T(...))";
t.safetyChange = (src == "c") ? SafetyDelta::Gained : SafetyDelta::Neutral;
t.annotation = "@Owner(Unique)";
} else if (tgt == "c") {
t.targetCode = "T* p = malloc(sizeof(T)); /* single owner, must free */";
t.safetyChange = SafetyDelta::Lost;
t.annotation = "@Owner(Manual), @Risk(high)";
t.note = "Unique ownership lost — manual free required";
} else {
t.targetCode = "value // GC handles lifetime";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Owner(GC)";
t.note = "GC language — no explicit ownership needed";
}
t.sourceModel = (src == "rust") ? OwnershipModel::BorrowChecked :
(src == "cpp") ? OwnershipModel::RAII : OwnershipModel::Manual;
t.targetModel = defaultOwnership(tgt);
return t;
}
static MemoryTranslation translateShared(const std::string& src, const std::string& tgt) {
MemoryTranslation t;
t.pattern = "@Owner(Shared_ARC)";
t.sourceLanguage = src;
t.targetLanguage = tgt;
if (tgt == "rust") {
t.targetCode = "Arc::new(value) or Rc::new(value)";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Owner(Shared_ARC)";
} else if (tgt == "cpp" || tgt == "c++") {
t.targetCode = "std::shared_ptr<T>(new T(...))";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Owner(Shared_ARC)";
} else if (tgt == "c") {
t.targetCode = "T* p = malloc(sizeof(T)); /* manual refcount */";
t.safetyChange = SafetyDelta::Lost;
t.annotation = "@Owner(Manual), @Risk(high)";
} else {
t.targetCode = "value // GC handles sharing";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Owner(GC)";
}
t.sourceModel = (src == "rust") ? OwnershipModel::BorrowChecked : OwnershipModel::RAII;
t.targetModel = defaultOwnership(tgt);
return t;
}
static MemoryTranslation translateManual(const std::string& src, const std::string& tgt) {
MemoryTranslation t;
t.pattern = "@Owner(Manual)";
t.sourceLanguage = src;
t.targetLanguage = tgt;
t.sourceModel = OwnershipModel::Manual;
if (tgt == "rust") {
t.targetCode = "let value = T::new(...); // owned, borrow checker enforces lifetime";
t.safetyChange = SafetyDelta::Gained;
t.annotation = "@Owner(BorrowChecked), @Risk(lowered)";
t.note = "Borrow checker eliminates use-after-free and double-free";
} else if (tgt == "cpp" || tgt == "c++") {
t.targetCode = "auto p = std::make_unique<T>(...);";
t.safetyChange = SafetyDelta::Gained;
t.annotation = "@Owner(RAII)";
} else if (tgt == "java" || tgt == "python" || tgt == "go") {
t.targetCode = "T value = new T(...) // GC manages lifetime";
t.safetyChange = SafetyDelta::Gained;
t.annotation = "@Owner(GC), @Risk(lowered)";
} else {
t.targetCode = "malloc/free // manual";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Owner(Manual)";
}
t.targetModel = defaultOwnership(tgt);
return t;
}
static MemoryTranslation translateScope(const std::string& src, const std::string& tgt) {
MemoryTranslation t;
t.pattern = "@Lifetime(Scope)";
t.sourceLanguage = src;
t.targetLanguage = tgt;
if (tgt == "rust") {
t.targetCode = "{ let resource = acquire(); /* dropped at end of scope */ }";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Lifetime(Scope), @Owner(RAII)";
} else if (tgt == "cpp" || tgt == "c++") {
t.targetCode = "{ auto resource = Resource(); /* destructor at scope end */ }";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Lifetime(Scope)";
} else if (tgt == "python") {
t.targetCode = "with resource_manager() as r: ...";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Lifetime(Scope)";
} else if (tgt == "go") {
t.targetCode = "defer resource.Close()";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Lifetime(deferred)";
} else if (tgt == "java") {
t.targetCode = "try (var r = new Resource()) { ... }";
t.safetyChange = SafetyDelta::Neutral;
t.annotation = "@Lifetime(try-with-resources)";
} else {
t.targetCode = "acquire(); ... release(); // manual scope";
t.safetyChange = SafetyDelta::Lost;
t.annotation = "@Lifetime(Manual), @Risk(medium)";
}
t.sourceModel = OwnershipModel::RAII;
t.targetModel = defaultOwnership(tgt);
return t;
}
};

View File

@@ -0,0 +1,142 @@
// Step 453: Memory Model Translation Tests (12 tests)
#include "MemoryModelTranslator.h"
#include <iostream>
static int passed = 0, failed = 0;
#define TEST(name) { std::cout << " " << #name << "... "; }
#define PASS() { std::cout << "PASS\n"; ++passed; }
#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; }
#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {}
void test_manual_c_to_rust_gains_safety() {
TEST(manual_c_to_rust_gains_safety);
auto r = MemoryModelTranslator::analyze("p = malloc(8); free(p);", "c", "rust");
CHECK(r.hasPattern("@Owner(Manual)"), "expected manual pattern");
CHECK(r.translations[0].safetyChange == SafetyDelta::Gained, "manual->rust should gain safety");
CHECK(r.translations[0].annotation.find("@Risk(lowered)") != std::string::npos,
"expected lowered risk annotation");
PASS();
}
void test_manual_c_to_java_gains_gc_safety() {
TEST(manual_c_to_java_gains_gc_safety);
auto r = MemoryModelTranslator::analyze("p = malloc(8); free(p);", "c", "java");
CHECK(r.hasPattern("@Owner(Manual)"), "expected manual pattern");
CHECK(r.translations[0].safetyChange == SafetyDelta::Gained, "manual->java should gain safety");
CHECK(r.translations[0].annotation.find("@Owner(GC)") != std::string::npos,
"expected GC owner annotation");
PASS();
}
void test_unique_cpp_to_c_loses_safety() {
TEST(unique_cpp_to_c_loses_safety);
auto r = MemoryModelTranslator::analyze("std::unique_ptr<Foo> p;", "cpp", "c");
CHECK(r.hasPattern("@Owner(Unique)"), "expected unique ownership pattern");
CHECK(r.translations[0].safetyChange == SafetyDelta::Lost, "unique->C should lose safety");
CHECK(r.translations[0].annotation.find("@Risk(high)") != std::string::npos,
"expected high risk annotation");
PASS();
}
void test_shared_cpp_to_rust_arc_mapping() {
TEST(shared_cpp_to_rust_arc_mapping);
auto r = MemoryModelTranslator::analyze("std::shared_ptr<Foo> p;", "cpp", "rust");
CHECK(r.hasPattern("@Owner(Shared_ARC)"), "expected shared ownership pattern");
CHECK(r.translations[0].targetCode.find("Arc::new") != std::string::npos,
"expected Arc mapping");
CHECK(r.translations[0].safetyChange == SafetyDelta::Neutral, "shared->shared should be neutral");
PASS();
}
void test_shared_rust_to_c_loses_safety() {
TEST(shared_rust_to_c_loses_safety);
auto r = MemoryModelTranslator::analyze("let p: Arc<Foo> = Arc::new(v);", "rust", "c");
CHECK(r.hasPattern("@Owner(Shared_ARC)"), "expected shared ownership pattern");
CHECK(r.translations[0].safetyChange == SafetyDelta::Lost, "shared->C should lose safety");
CHECK(r.translations[0].annotation.find("@Risk(high)") != std::string::npos,
"expected high risk annotation");
PASS();
}
void test_scope_lifetime_to_go_defer() {
TEST(scope_lifetime_to_go_defer);
auto r = MemoryModelTranslator::analyze("with open(path) as f: data = f.read()", "python", "go");
CHECK(r.hasPattern("@Lifetime(Scope)"), "expected scope lifetime pattern");
CHECK(r.translations[0].annotation.find("@Lifetime(deferred)") != std::string::npos,
"expected deferred lifetime annotation");
PASS();
}
void test_scope_to_c_loses_scope_guarantee() {
TEST(scope_to_c_loses_scope_guarantee);
auto r = MemoryModelTranslator::analyze("with resource_manager() as r: use(r)", "python", "c");
CHECK(r.hasPattern("@Lifetime(Scope)"), "expected scope pattern");
CHECK(r.translations[0].safetyChange == SafetyDelta::Lost, "scope->C should lose guarantee");
CHECK(r.translations[0].annotation.find("@Risk(medium)") != std::string::npos,
"expected medium risk annotation");
PASS();
}
void test_detect_source_model_rust_borrowchecked() {
TEST(detect_source_model_rust_borrowchecked);
auto r = MemoryModelTranslator::analyze("let x = Box::new(1);", "rust", "cpp");
CHECK(r.sourceModel == OwnershipModel::BorrowChecked, "rust source should be borrow-checked");
PASS();
}
void test_detect_target_model_java_gc() {
TEST(detect_target_model_java_gc);
auto r = MemoryModelTranslator::analyze("int* p = malloc(8);", "c", "java");
CHECK(r.targetModel == OwnershipModel::GC, "java target should use GC model");
PASS();
}
void test_no_pattern_on_plain_code() {
TEST(no_pattern_on_plain_code);
auto r = MemoryModelTranslator::analyze("x = a + b;", "python", "rust");
CHECK(r.translations.empty(), "plain code should not emit memory translations");
PASS();
}
void test_safety_gain_count_for_manual_migration() {
TEST(safety_gain_count_for_manual_migration);
auto r = MemoryModelTranslator::analyze("p = malloc(8); free(p);", "c", "rust");
CHECK(r.countSafetyGained() >= 1, "expected at least one safety gain");
CHECK(r.countSafetyLost() == 0, "manual->rust should not lose safety");
PASS();
}
void test_mixed_patterns_report_gain_and_loss() {
TEST(mixed_patterns_report_gain_and_loss);
auto r = MemoryModelTranslator::analyze(
"std::unique_ptr<Foo> p; q = malloc(8); free(q);",
"cpp",
"c");
CHECK(r.translations.size() >= 2, "expected unique + manual translations");
CHECK(r.countSafetyLost() >= 1, "expected at least one safety loss");
CHECK(r.countSafetyGained() == 0, "cpp->c should not gain safety here");
PASS();
}
int main() {
std::cout << "Step 453: Memory Model Translation Tests\n";
test_manual_c_to_rust_gains_safety(); // 1
test_manual_c_to_java_gains_gc_safety(); // 2
test_unique_cpp_to_c_loses_safety(); // 3
test_shared_cpp_to_rust_arc_mapping(); // 4
test_shared_rust_to_c_loses_safety(); // 5
test_scope_lifetime_to_go_defer(); // 6
test_scope_to_c_loses_scope_guarantee(); // 7
test_detect_source_model_rust_borrowchecked(); // 8
test_detect_target_model_java_gc(); // 9
test_no_pattern_on_plain_code(); // 10
test_safety_gain_count_for_manual_migration(); // 11
test_mixed_patterns_report_gain_and_loss(); // 12
std::cout << "\nResults: " << passed << "/" << (passed + failed)
<< " passed\n";
return failed == 0 ? 0 : 1;
}

View File

@@ -5793,3 +5793,32 @@ for async/thread/channel/mutex constructs across language runtime models.
**Architecture gate check:**
- `editor/src/ConcurrencyTranslator.h` within header-size limit (`249` <= `600`)
- `editor/tests/step452_test.cpp` within test-file size guidance (`146` lines)
### Step 453: Memory Model Translation
**Status:** PASS (12/12 tests)
Completes ownership/lifetime translation across manual, RAII, GC, ARC, and
borrow-checked models with explicit safety-delta tracking.
**Files added:**
- `editor/src/MemoryModelTranslator.h` — memory model translation engine:
- ownership model detection (`Manual`, `RAII`, `GC`, `BorrowChecked`, `ARC`)
- translation patterns for `@Owner(Unique)`, `@Owner(Shared_ARC)`,
`@Owner(Manual)`, `@Lifetime(Scope)`
- per-translation safety delta (`Gained`, `Lost`, `Neutral`)
- migration annotations (e.g., `@Risk(high)`, `@Risk(lowered)`)
- `editor/tests/step453_test.cpp` — 12 tests covering:
- manual-memory safety gains in Rust/GC targets
- unique/shared ownership degradation when targeting C
- scope-lifetime mapping (`defer`, try-with-resources, manual fallback)
- source/target model inference and mixed-pattern safety counters
- `editor/CMakeLists.txt``step453_test` target
**Verification run:**
- `cmake --build editor/build-native --target step453_test` — PASS
- `./editor/build-native/step453_test` — PASS (12/12)
- `./editor/build-native/step452_test` — PASS (12/12) regression coverage
**Architecture gate check:**
- `editor/src/MemoryModelTranslator.h` within header-size limit (`249` <= `600`)
- `editor/tests/step453_test.cpp` within test-file size guidance (`142` lines)