Complete step451 type system translation with tests
This commit is contained in:
@@ -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)
|
||||
|
||||
140
editor/src/TypeSystemTranslator.h
Normal file
140
editor/src/TypeSystemTranslator.h
Normal file
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
|
||||
// Step 451: Type System Translation — maps type systems across languages
|
||||
// with annotation-guided safety preservation.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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<TypeTranslation> 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<std::string>& 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<T>" || type == "T?") {
|
||||
if (tgt == "rust") { t.targetType = "Option<T>"; t.safety = TypeSafety::Preserved; }
|
||||
else if (tgt == "python") { t.targetType = "Optional[T]"; t.safety = TypeSafety::Preserved; }
|
||||
else if (tgt == "java") { t.targetType = "Optional<T>"; 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<T>" || type == "Vec<T>" || type == "list") {
|
||||
if (tgt == "rust") { t.targetType = "Vec<T>"; t.safety = TypeSafety::Preserved; }
|
||||
else if (tgt == "python") { t.targetType = "list[T]"; t.safety = TypeSafety::Preserved; }
|
||||
else if (tgt == "java") { t.targetType = "List<T>"; 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<K,V>" || type == "HashMap<K,V>" || type == "dict") {
|
||||
if (tgt == "rust") { t.targetType = "HashMap<K,V>"; t.safety = TypeSafety::Preserved; }
|
||||
else if (tgt == "python") { t.targetType = "dict[K,V]"; t.safety = TypeSafety::Preserved; }
|
||||
else if (tgt == "java") { t.targetType = "Map<K,V>"; 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;
|
||||
}
|
||||
};
|
||||
146
editor/tests/step451_test.cpp
Normal file
146
editor/tests/step451_test.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Step 451: Type System Translation Tests (12 tests)
|
||||
|
||||
#include "TypeSystemTranslator.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_nullable_to_rust_option() {
|
||||
TEST(nullable_to_rust_option);
|
||||
auto r = TypeSystemTranslator::translate({"Optional<T>"}, "java", "rust");
|
||||
auto t = r.getTranslation("Optional<T>");
|
||||
CHECK(t.targetType == "Option<T>", "expected Option<T>");
|
||||
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<T>"}, "java", "c");
|
||||
auto t = r.getTranslation("Optional<T>");
|
||||
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<T>"}, "java", "rust");
|
||||
auto t = r.getTranslation("List<T>");
|
||||
CHECK(t.targetType == "Vec<T>", "expected Vec<T>");
|
||||
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<T>"}, "java", "c");
|
||||
auto t = r.getTranslation("List<T>");
|
||||
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<K,V>"}, "java", "go");
|
||||
auto t = r.getTranslation("Map<K,V>");
|
||||
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<T>", "List<T>", "Map<K,V>", "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<K,V>"), "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;
|
||||
}
|
||||
29
progress.md
29
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>`/`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)
|
||||
|
||||
Reference in New Issue
Block a user