From 4cd5156c7b4bee26cd15433adca1a18ee069cb38 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 16 Feb 2026 19:41:17 -0700 Subject: [PATCH] Complete step451 type system translation with tests --- editor/CMakeLists.txt | 9 ++ editor/src/TypeSystemTranslator.h | 140 ++++++++++++++++++++++++++++ editor/tests/step451_test.cpp | 146 ++++++++++++++++++++++++++++++ progress.md | 29 ++++++ 4 files changed, 324 insertions(+) create mode 100644 editor/src/TypeSystemTranslator.h create mode 100644 editor/tests/step451_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 4503dba..6b3a807 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -2938,4 +2938,13 @@ target_link_libraries(step450_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step451_test tests/step451_test.cpp) +target_include_directories(step451_test PRIVATE src) +target_link_libraries(step451_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) diff --git a/editor/src/TypeSystemTranslator.h b/editor/src/TypeSystemTranslator.h new file mode 100644 index 0000000..fa71826 --- /dev/null +++ b/editor/src/TypeSystemTranslator.h @@ -0,0 +1,140 @@ +#pragma once + +// Step 451: Type System Translation — maps type systems across languages +// with annotation-guided safety preservation. + +#include +#include + +enum class TypeSafety { Preserved, Widened, Narrowed, Lossy }; + +struct TypeTranslation { + std::string sourceType; + std::string sourceLanguage; + std::string targetType; + std::string targetLanguage; + TypeSafety safety = TypeSafety::Preserved; + std::string annotation; // e.g. @Risk(medium) for lossy + std::string note; +}; + +struct TypeTranslationResult { + std::string sourceLanguage; + std::string targetLanguage; + std::vector translations; + + bool hasTranslation(const std::string& sourceType) const { + for (const auto& t : translations) + if (t.sourceType == sourceType) return true; + return false; + } + + TypeTranslation getTranslation(const std::string& sourceType) const { + for (const auto& t : translations) + if (t.sourceType == sourceType) return t; + return {}; + } + + int countLossy() const { + int n = 0; + for (const auto& t : translations) + if (t.safety == TypeSafety::Lossy) ++n; + return n; + } +}; + +class TypeSystemTranslator { +public: + static TypeTranslationResult translate(const std::vector& sourceTypes, + const std::string& srcLang, + const std::string& tgtLang) { + TypeTranslationResult result; + result.sourceLanguage = srcLang; + result.targetLanguage = tgtLang; + + for (const auto& st : sourceTypes) { + auto tt = mapType(st, srcLang, tgtLang); + result.translations.push_back(std::move(tt)); + } + return result; + } + +private: + static TypeTranslation mapType(const std::string& type, + const std::string& src, + const std::string& tgt) { + TypeTranslation t; + t.sourceType = type; + t.sourceLanguage = src; + t.targetLanguage = tgt; + + // Nullable types + if (type == "Optional" || type == "Optional" || type == "T?") { + if (tgt == "rust") { t.targetType = "Option"; t.safety = TypeSafety::Preserved; } + else if (tgt == "python") { t.targetType = "Optional[T]"; t.safety = TypeSafety::Preserved; } + else if (tgt == "java") { t.targetType = "Optional"; t.safety = TypeSafety::Preserved; } + else if (tgt == "c" || tgt == "cpp") { t.targetType = "T*"; t.safety = TypeSafety::Lossy; t.annotation = "@Risk(medium)"; } + else { t.targetType = "nullable T"; t.safety = TypeSafety::Widened; } + } + // Generic collections + else if (type == "List" || type == "Vec" || type == "list") { + if (tgt == "rust") { t.targetType = "Vec"; t.safety = TypeSafety::Preserved; } + else if (tgt == "python") { t.targetType = "list[T]"; t.safety = TypeSafety::Preserved; } + else if (tgt == "java") { t.targetType = "List"; t.safety = TypeSafety::Preserved; } + else if (tgt == "c") { t.targetType = "void*"; t.safety = TypeSafety::Lossy; t.annotation = "@Risk(high)"; t.note = "Generics lost in C"; } + else if (tgt == "go") { t.targetType = "[]T"; t.safety = TypeSafety::Preserved; } + else { t.targetType = "array"; t.safety = TypeSafety::Widened; } + } + // Map/Dict + else if (type == "Map" || type == "HashMap" || type == "dict") { + if (tgt == "rust") { t.targetType = "HashMap"; t.safety = TypeSafety::Preserved; } + else if (tgt == "python") { t.targetType = "dict[K,V]"; t.safety = TypeSafety::Preserved; } + else if (tgt == "java") { t.targetType = "Map"; t.safety = TypeSafety::Preserved; } + else if (tgt == "go") { t.targetType = "map[K]V"; t.safety = TypeSafety::Preserved; } + else if (tgt == "c") { t.targetType = "void*"; t.safety = TypeSafety::Lossy; t.annotation = "@Risk(high)"; } + else { t.targetType = "map"; t.safety = TypeSafety::Widened; } + } + // Enum types + else if (type == "enum" || type == "Enum") { + if (tgt == "rust") { t.targetType = "enum"; t.safety = TypeSafety::Preserved; t.note = "Rust enum is more expressive (sum type)"; } + else if (tgt == "java") { t.targetType = "enum"; t.safety = TypeSafety::Preserved; } + else if (tgt == "python") { t.targetType = "Enum"; t.safety = TypeSafety::Preserved; } + else if (tgt == "c") { t.targetType = "enum/constants"; t.safety = TypeSafety::Narrowed; t.note = "C enum has no methods"; } + else if (tgt == "go") { t.targetType = "const iota"; t.safety = TypeSafety::Narrowed; } + else { t.targetType = "enum"; t.safety = TypeSafety::Preserved; } + } + // Class hierarchy → traits/interfaces + else if (type == "class" || type == "abstract class") { + if (tgt == "rust") { t.targetType = "trait + struct"; t.safety = TypeSafety::Preserved; t.note = "Composition over inheritance"; } + else if (tgt == "java") { t.targetType = "interface + class"; t.safety = TypeSafety::Preserved; } + else if (tgt == "go") { t.targetType = "interface + struct"; t.safety = TypeSafety::Preserved; } + else if (tgt == "c") { t.targetType = "struct + vtable"; t.safety = TypeSafety::Lossy; t.annotation = "@Risk(medium)"; } + else if (tgt == "python") { t.targetType = "class (ABC)"; t.safety = TypeSafety::Preserved; } + else { t.targetType = "class"; t.safety = TypeSafety::Preserved; } + } + // String types + else if (type == "String" || type == "string" || type == "str") { + if (tgt == "rust") { t.targetType = "String"; t.safety = TypeSafety::Preserved; } + else if (tgt == "python") { t.targetType = "str"; t.safety = TypeSafety::Preserved; } + else if (tgt == "java") { t.targetType = "String"; t.safety = TypeSafety::Preserved; } + else if (tgt == "c") { t.targetType = "char*"; t.safety = TypeSafety::Lossy; t.annotation = "@Risk(medium)"; t.note = "No length tracking"; } + else if (tgt == "go") { t.targetType = "string"; t.safety = TypeSafety::Preserved; } + else { t.targetType = "string"; t.safety = TypeSafety::Preserved; } + } + // Primitive int + else if (type == "int" || type == "i32" || type == "int32") { + if (tgt == "rust") { t.targetType = "i32"; t.safety = TypeSafety::Preserved; } + else if (tgt == "python") { t.targetType = "int"; t.safety = TypeSafety::Widened; t.note = "Python int is arbitrary precision"; } + else if (tgt == "java") { t.targetType = "int"; t.safety = TypeSafety::Preserved; } + else if (tgt == "c" || tgt == "cpp") { t.targetType = "int"; t.safety = TypeSafety::Preserved; } + else if (tgt == "go") { t.targetType = "int32"; t.safety = TypeSafety::Preserved; } + else { t.targetType = "int"; t.safety = TypeSafety::Preserved; } + } + else { + t.targetType = type; + t.safety = TypeSafety::Preserved; + t.note = "Unknown type — preserved as-is"; + } + return t; + } +}; diff --git a/editor/tests/step451_test.cpp b/editor/tests/step451_test.cpp new file mode 100644 index 0000000..a5d43d4 --- /dev/null +++ b/editor/tests/step451_test.cpp @@ -0,0 +1,146 @@ +// Step 451: Type System Translation Tests (12 tests) + +#include "TypeSystemTranslator.h" + +#include + +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_nullable_to_rust_option() { + TEST(nullable_to_rust_option); + auto r = TypeSystemTranslator::translate({"Optional"}, "java", "rust"); + auto t = r.getTranslation("Optional"); + CHECK(t.targetType == "Option", "expected Option"); + CHECK(t.safety == TypeSafety::Preserved, "nullable should be preserved"); + PASS(); +} + +void test_nullable_to_c_is_lossy() { + TEST(nullable_to_c_is_lossy); + auto r = TypeSystemTranslator::translate({"Optional"}, "java", "c"); + auto t = r.getTranslation("Optional"); + CHECK(t.targetType == "T*", "expected pointer representation"); + CHECK(t.safety == TypeSafety::Lossy, "nullable->C should be lossy"); + CHECK(t.annotation == "@Risk(medium)", "expected risk annotation"); + PASS(); +} + +void test_list_to_rust_vec() { + TEST(list_to_rust_vec); + auto r = TypeSystemTranslator::translate({"List"}, "java", "rust"); + auto t = r.getTranslation("List"); + CHECK(t.targetType == "Vec", "expected Vec"); + CHECK(t.safety == TypeSafety::Preserved, "generic list should preserve"); + PASS(); +} + +void test_list_to_c_void_ptr_lossy() { + TEST(list_to_c_void_ptr_lossy); + auto r = TypeSystemTranslator::translate({"List"}, "java", "c"); + auto t = r.getTranslation("List"); + CHECK(t.targetType == "void*", "expected void* in C"); + CHECK(t.safety == TypeSafety::Lossy, "generics->C should be lossy"); + CHECK(t.annotation == "@Risk(high)", "expected high risk annotation"); + PASS(); +} + +void test_map_to_go_map_type() { + TEST(map_to_go_map_type); + auto r = TypeSystemTranslator::translate({"Map"}, "java", "go"); + auto t = r.getTranslation("Map"); + CHECK(t.targetType == "map[K]V", "expected Go map"); + CHECK(t.safety == TypeSafety::Preserved, "map should preserve semantics"); + PASS(); +} + +void test_enum_to_c_narrowed() { + TEST(enum_to_c_narrowed); + auto r = TypeSystemTranslator::translate({"Enum"}, "java", "c"); + auto t = r.getTranslation("Enum"); + CHECK(t.targetType == "enum/constants", "expected C enum/constants"); + CHECK(t.safety == TypeSafety::Narrowed, "C enum should be narrowed"); + PASS(); +} + +void test_class_to_rust_trait_struct() { + TEST(class_to_rust_trait_struct); + auto r = TypeSystemTranslator::translate({"abstract class"}, "java", "rust"); + auto t = r.getTranslation("abstract class"); + CHECK(t.targetType == "trait + struct", "expected trait + struct"); + CHECK(t.safety == TypeSafety::Preserved, "should preserve behavior intent"); + PASS(); +} + +void test_class_to_c_vtable_lossy() { + TEST(class_to_c_vtable_lossy); + auto r = TypeSystemTranslator::translate({"class"}, "java", "c"); + auto t = r.getTranslation("class"); + CHECK(t.targetType == "struct + vtable", "expected struct + vtable"); + CHECK(t.safety == TypeSafety::Lossy, "class->C should be lossy"); + CHECK(t.annotation == "@Risk(medium)", "expected risk annotation"); + PASS(); +} + +void test_string_to_c_char_ptr_lossy() { + TEST(string_to_c_char_ptr_lossy); + auto r = TypeSystemTranslator::translate({"String"}, "java", "c"); + auto t = r.getTranslation("String"); + CHECK(t.targetType == "char*", "expected char*"); + CHECK(t.safety == TypeSafety::Lossy, "String->char* should be lossy"); + PASS(); +} + +void test_int_to_python_widened() { + TEST(int_to_python_widened); + auto r = TypeSystemTranslator::translate({"int"}, "c", "python"); + auto t = r.getTranslation("int"); + CHECK(t.targetType == "int", "expected python int"); + CHECK(t.safety == TypeSafety::Widened, "expected widened numeric range"); + PASS(); +} + +void test_unknown_type_preserved() { + TEST(unknown_type_preserved); + auto r = TypeSystemTranslator::translate({"CustomBlob"}, "java", "rust"); + auto t = r.getTranslation("CustomBlob"); + CHECK(t.targetType == "CustomBlob", "unknown type should stay unchanged"); + CHECK(t.safety == TypeSafety::Preserved, "unknown type should preserve"); + PASS(); +} + +void test_mixed_batch_translation_counts_lossy() { + TEST(mixed_batch_translation_counts_lossy); + auto r = TypeSystemTranslator::translate( + {"Optional", "List", "Map", "int"}, + "java", + "c"); + CHECK(r.translations.size() == 4, "expected 4 translated types"); + CHECK(r.countLossy() >= 3, "expected at least 3 lossy mappings"); + CHECK(r.hasTranslation("Map"), "expected map translation"); + PASS(); +} + +int main() { + std::cout << "Step 451: Type System Translation Tests\n"; + + test_nullable_to_rust_option(); // 1 + test_nullable_to_c_is_lossy(); // 2 + test_list_to_rust_vec(); // 3 + test_list_to_c_void_ptr_lossy(); // 4 + test_map_to_go_map_type(); // 5 + test_enum_to_c_narrowed(); // 6 + test_class_to_rust_trait_struct(); // 7 + test_class_to_c_vtable_lossy(); // 8 + test_string_to_c_char_ptr_lossy(); // 9 + test_int_to_python_widened(); // 10 + test_unknown_type_preserved(); // 11 + test_mixed_batch_translation_counts_lossy(); // 12 + + std::cout << "\nResults: " << passed << "/" << (passed + failed) + << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index 7a9438a..b33ec9f 100644 --- a/progress.md +++ b/progress.md @@ -5736,3 +5736,32 @@ literal/syntactic rewrites. **Architecture gate check:** - `editor/src/AlgorithmEquivalence.h` within header-size limit (`228` <= `600`) - `editor/tests/step450_test.cpp` within test-file size guidance (`143` lines) + +### Step 451: Type System Translation +**Status:** PASS (12/12 tests) + +Completes type-system mapping across language boundaries with explicit safety +classification and risk annotations for lossy projections. + +**Files added:** +- `editor/src/TypeSystemTranslator.h` — type translation engine: + - nullable mapping (`Optional`/`T?`), generic collections, maps, enums + - class-hierarchy projection (`trait + struct`, `interface + struct`, `struct + vtable`) + - primitive/string translation across Rust/Python/Java/C/C++/Go + - safety classification (`Preserved`, `Widened`, `Narrowed`, `Lossy`) + - risk annotation tagging for lossy targets (`@Risk(medium|high)`) +- `editor/tests/step451_test.cpp` — 12 tests covering: + - nullable/generic/map translations and safety categories + - enum/class/string lossy/narrowed mappings + - unknown-type pass-through behavior + - mixed-batch translation with lossy-count validation +- `editor/CMakeLists.txt` — `step451_test` target + +**Verification run:** +- `cmake --build editor/build-native --target step451_test` — PASS +- `./editor/build-native/step451_test` — PASS (12/12) +- `./editor/build-native/step450_test` — PASS (12/12) regression coverage + +**Architecture gate check:** +- `editor/src/TypeSystemTranslator.h` within header-size limit (`140` <= `600`) +- `editor/tests/step451_test.cpp` within test-file size guidance (`146` lines)