Complete step452 concurrency model translation with tests

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

View File

@@ -2947,4 +2947,13 @@ target_link_libraries(step451_test PRIVATE
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step452_test tests/step452_test.cpp)
target_include_directories(step452_test PRIVATE src)
target_link_libraries(step452_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 452: Concurrency Model Translation — maps concurrency patterns across
// language runtimes with @Exec, @Sync, @ThreadModel, @Blocking annotations.
#include <string>
#include <vector>
enum class ConcurrencyModel { Threads, AsyncAwait, Channels, Coroutines, EventLoop, None };
enum class ConcurrencySafety { Safe, NeedsReview, Unsafe };
struct ConcurrencyTranslation {
std::string pattern; // e.g. "async/await", "thread spawn"
ConcurrencyModel sourceModel;
ConcurrencyModel targetModel;
std::string sourceLanguage;
std::string targetLanguage;
std::string sourceCode;
std::string targetCode;
ConcurrencySafety safety = ConcurrencySafety::Safe;
std::string annotation; // e.g. @Blocking(false)
std::string note;
};
struct ConcurrencyAnalysisResult {
std::string sourceLanguage;
std::string targetLanguage;
ConcurrencyModel sourceModel = ConcurrencyModel::None;
ConcurrencyModel targetModel = ConcurrencyModel::None;
std::vector<ConcurrencyTranslation> translations;
bool hasPattern(const std::string& p) const {
for (const auto& t : translations)
if (t.pattern == p) return true;
return false;
}
int countNeedsReview() const {
int n = 0;
for (const auto& t : translations)
if (t.safety == ConcurrencySafety::NeedsReview) ++n;
return n;
}
};
class ConcurrencyTranslator {
public:
static ConcurrencyAnalysisResult analyze(const std::string& source,
const std::string& srcLang,
const std::string& tgtLang) {
ConcurrencyAnalysisResult result;
result.sourceLanguage = srcLang;
result.targetLanguage = tgtLang;
result.sourceModel = detectModel(source, srcLang);
result.targetModel = defaultModel(tgtLang);
if (hasAsync(source)) {
result.translations.push_back(translateAsync(srcLang, tgtLang));
}
if (hasThreads(source)) {
result.translations.push_back(translateThreads(srcLang, tgtLang));
}
if (hasChannels(source)) {
result.translations.push_back(translateChannels(srcLang, tgtLang));
}
if (hasMutex(source)) {
result.translations.push_back(translateMutex(srcLang, tgtLang));
}
return result;
}
private:
static bool hasAsync(const std::string& src) {
return src.find("async ") != std::string::npos ||
src.find("await ") != std::string::npos ||
src.find("asyncio") != std::string::npos ||
src.find("Promise") != std::string::npos;
}
static bool hasThreads(const std::string& src) {
return src.find("Thread") != std::string::npos ||
src.find("thread") != std::string::npos ||
src.find("pthread") != std::string::npos ||
src.find("goroutine") != std::string::npos ||
src.find("go func") != std::string::npos;
}
static bool hasChannels(const std::string& src) {
return src.find("chan ") != std::string::npos ||
src.find("channel") != std::string::npos ||
src.find("mpsc::") != std::string::npos;
}
static bool hasMutex(const std::string& src) {
return src.find("mutex") != std::string::npos ||
src.find("Mutex") != std::string::npos ||
src.find("Lock") != std::string::npos ||
src.find("synchronized") != std::string::npos;
}
static ConcurrencyModel detectModel(const std::string& src, const std::string& lang) {
if (hasAsync(src)) return ConcurrencyModel::AsyncAwait;
if (hasChannels(src)) return ConcurrencyModel::Channels;
if (hasThreads(src)) return ConcurrencyModel::Threads;
if (lang == "go") return ConcurrencyModel::Channels;
if (lang == "javascript" || lang == "js") return ConcurrencyModel::EventLoop;
return ConcurrencyModel::None;
}
static ConcurrencyModel defaultModel(const std::string& lang) {
if (lang == "go") return ConcurrencyModel::Channels;
if (lang == "javascript" || lang == "js") return ConcurrencyModel::EventLoop;
if (lang == "rust") return ConcurrencyModel::AsyncAwait;
if (lang == "python") return ConcurrencyModel::AsyncAwait;
if (lang == "java") return ConcurrencyModel::Threads;
if (lang == "c" || lang == "cpp") return ConcurrencyModel::Threads;
return ConcurrencyModel::Threads;
}
static ConcurrencyTranslation translateAsync(const std::string& src, const std::string& tgt) {
ConcurrencyTranslation t;
t.pattern = "async/await";
t.sourceModel = ConcurrencyModel::AsyncAwait;
t.sourceLanguage = src;
t.targetLanguage = tgt;
if (tgt == "rust") {
t.targetModel = ConcurrencyModel::AsyncAwait;
t.targetCode = "async fn f() -> Result<T> { ... .await }";
t.safety = ConcurrencySafety::NeedsReview;
t.annotation = "@Exec(async), @ThreadModel(tokio)";
t.note = "Rust async requires explicit runtime (tokio/async-std)";
} else if (tgt == "go") {
t.targetModel = ConcurrencyModel::Channels;
t.targetCode = "go func() { ch <- result }()";
t.safety = ConcurrencySafety::NeedsReview;
t.annotation = "@Exec(goroutine), @Blocking(false)";
t.note = "Go uses goroutines+channels instead of async/await";
} else if (tgt == "python") {
t.targetModel = ConcurrencyModel::AsyncAwait;
t.targetCode = "async def f(): result = await coro()";
t.safety = ConcurrencySafety::Safe;
t.annotation = "@Exec(async), @ThreadModel(asyncio)";
} else if (tgt == "java") {
t.targetModel = ConcurrencyModel::Threads;
t.targetCode = "CompletableFuture.supplyAsync(() -> { ... })";
t.safety = ConcurrencySafety::NeedsReview;
t.annotation = "@Exec(future), @ThreadModel(executor)";
t.note = "Java uses CompletableFuture, not native async/await";
} else if (tgt == "c") {
t.targetModel = ConcurrencyModel::Threads;
t.targetCode = "pthread_create(&thread, NULL, callback, arg)";
t.safety = ConcurrencySafety::Unsafe;
t.annotation = "@Exec(thread), @Blocking(true), @Risk(high)";
t.note = "C has no async/await — manual thread management";
} else {
t.targetModel = ConcurrencyModel::AsyncAwait;
t.targetCode = "async { ... }";
t.safety = ConcurrencySafety::NeedsReview;
}
return t;
}
static ConcurrencyTranslation translateThreads(const std::string& src, const std::string& tgt) {
ConcurrencyTranslation t;
t.pattern = "thread_spawn";
t.sourceModel = ConcurrencyModel::Threads;
t.sourceLanguage = src;
t.targetLanguage = tgt;
if (tgt == "rust") {
t.targetCode = "std::thread::spawn(move || { ... })";
t.safety = ConcurrencySafety::Safe;
t.annotation = "@Sync(Send+Sync), @ThreadModel(native)";
} else if (tgt == "go") {
t.targetCode = "go func() { ... }()";
t.safety = ConcurrencySafety::Safe;
t.annotation = "@Exec(goroutine)";
} else if (tgt == "python") {
t.targetCode = "threading.Thread(target=func).start()";
t.safety = ConcurrencySafety::NeedsReview;
t.annotation = "@ThreadModel(GIL), @Blocking(true)";
t.note = "Python GIL limits true parallelism";
} else if (tgt == "java") {
t.targetCode = "new Thread(() -> { ... }).start()";
t.safety = ConcurrencySafety::Safe;
} else {
t.targetCode = "spawn_thread(func)";
t.safety = ConcurrencySafety::NeedsReview;
}
t.targetModel = defaultModel(tgt);
return t;
}
static ConcurrencyTranslation translateChannels(const std::string& src, const std::string& tgt) {
ConcurrencyTranslation t;
t.pattern = "channels";
t.sourceModel = ConcurrencyModel::Channels;
t.sourceLanguage = src;
t.targetLanguage = tgt;
if (tgt == "rust") {
t.targetCode = "let (tx, rx) = mpsc::channel(); tx.send(value);";
t.safety = ConcurrencySafety::Safe;
t.annotation = "@Sync(channel)";
} else if (tgt == "go") {
t.targetCode = "ch := make(chan T); ch <- value";
t.safety = ConcurrencySafety::Safe;
} else if (tgt == "java") {
t.targetCode = "BlockingQueue<T> queue = new LinkedBlockingQueue<>();";
t.safety = ConcurrencySafety::Safe;
} else {
t.targetCode = "channel.send(value)";
t.safety = ConcurrencySafety::NeedsReview;
}
t.targetModel = defaultModel(tgt);
return t;
}
static ConcurrencyTranslation translateMutex(const std::string& src, const std::string& tgt) {
ConcurrencyTranslation t;
t.pattern = "mutex";
t.sourceModel = ConcurrencyModel::Threads;
t.sourceLanguage = src;
t.targetLanguage = tgt;
if (tgt == "rust") {
t.targetCode = "let data = Mutex::new(value); let guard = data.lock().unwrap();";
t.safety = ConcurrencySafety::Safe;
t.annotation = "@Sync(Mutex)";
} else if (tgt == "go") {
t.targetCode = "var mu sync.Mutex; mu.Lock(); defer mu.Unlock();";
t.safety = ConcurrencySafety::Safe;
} else if (tgt == "java") {
t.targetCode = "synchronized(lock) { ... }";
t.safety = ConcurrencySafety::Safe;
} else if (tgt == "c") {
t.targetCode = "pthread_mutex_lock(&mutex); ... pthread_mutex_unlock(&mutex);";
t.safety = ConcurrencySafety::NeedsReview;
t.annotation = "@Sync(pthread_mutex)";
} else {
t.targetCode = "lock.acquire(); ... lock.release();";
t.safety = ConcurrencySafety::NeedsReview;
}
t.targetModel = defaultModel(tgt);
return t;
}
};

View File

@@ -0,0 +1,146 @@
// Step 452: Concurrency Model Translation Tests (12 tests)
#include "ConcurrencyTranslator.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_async_python_to_rust_needs_runtime_review() {
TEST(async_python_to_rust_needs_runtime_review);
auto r = ConcurrencyTranslator::analyze("async def f(): await g()", "python", "rust");
CHECK(r.hasPattern("async/await"), "expected async pattern");
CHECK(r.countNeedsReview() >= 1, "rust async runtime should require review");
CHECK(r.translations[0].annotation.find("tokio") != std::string::npos,
"expected tokio runtime annotation");
PASS();
}
void test_async_to_c_is_unsafe() {
TEST(async_to_c_is_unsafe);
auto r = ConcurrencyTranslator::analyze("async def f(): await g()", "python", "c");
CHECK(r.hasPattern("async/await"), "expected async pattern");
CHECK(r.translations[0].safety == ConcurrencySafety::Unsafe, "async->C should be unsafe");
CHECK(r.translations[0].annotation.find("@Risk(high)") != std::string::npos,
"expected high risk annotation");
PASS();
}
void test_thread_java_to_go_maps_to_goroutine() {
TEST(thread_java_to_go_maps_to_goroutine);
auto r = ConcurrencyTranslator::analyze("new Thread(() -> {}).start();", "java", "go");
CHECK(r.hasPattern("thread_spawn"), "expected thread spawn pattern");
CHECK(r.translations[0].targetCode.find("go func") != std::string::npos,
"expected goroutine mapping");
CHECK(r.translations[0].safety == ConcurrencySafety::Safe, "expected safe mapping");
PASS();
}
void test_thread_to_python_marks_gil_review() {
TEST(thread_to_python_marks_gil_review);
auto r = ConcurrencyTranslator::analyze("std::thread t(f);", "cpp", "python");
CHECK(r.hasPattern("thread_spawn"), "expected thread spawn pattern");
CHECK(r.translations[0].safety == ConcurrencySafety::NeedsReview, "expected review");
CHECK(r.translations[0].annotation.find("GIL") != std::string::npos, "expected GIL annotation");
PASS();
}
void test_channels_go_to_rust_mpsc() {
TEST(channels_go_to_rust_mpsc);
auto r = ConcurrencyTranslator::analyze("ch := make(chan int); ch <- 1", "go", "rust");
CHECK(r.hasPattern("channels"), "expected channels pattern");
CHECK(r.translations[0].targetCode.find("mpsc::channel") != std::string::npos,
"expected rust mpsc mapping");
PASS();
}
void test_mutex_java_to_c_requires_review() {
TEST(mutex_java_to_c_requires_review);
auto r = ConcurrencyTranslator::analyze("synchronized(lock) { x++; }", "java", "c");
CHECK(r.hasPattern("mutex"), "expected mutex pattern");
CHECK(r.translations[0].safety == ConcurrencySafety::NeedsReview, "expected review in C");
CHECK(r.translations[0].targetCode.find("pthread_mutex_lock") != std::string::npos,
"expected pthread mutex mapping");
PASS();
}
void test_source_model_prefers_async_when_present() {
TEST(source_model_prefers_async_when_present);
auto r = ConcurrencyTranslator::analyze(
"async def f(): await g()\nthreading.Thread(target=h).start()",
"python",
"rust");
CHECK(r.sourceModel == ConcurrencyModel::AsyncAwait, "async should win source model detection");
PASS();
}
void test_target_model_defaults_for_javascript() {
TEST(target_model_defaults_for_javascript);
auto r = ConcurrencyTranslator::analyze("value = 1;", "python", "javascript");
CHECK(r.targetModel == ConcurrencyModel::EventLoop, "javascript target should default to event loop");
PASS();
}
void test_no_patterns_on_plain_code() {
TEST(no_patterns_on_plain_code);
auto r = ConcurrencyTranslator::analyze("x = a + b;", "python", "rust");
CHECK(r.translations.empty(), "plain code should not emit translations");
CHECK(!r.hasPattern("async/await"), "should not detect async pattern");
PASS();
}
void test_multiple_patterns_detected() {
TEST(multiple_patterns_detected);
auto r = ConcurrencyTranslator::analyze(
"async def f(): await g()\nmutex.lock()\nmutex.unlock()",
"python",
"rust");
CHECK(r.hasPattern("async/await"), "expected async");
CHECK(r.hasPattern("mutex"), "expected mutex");
CHECK(r.translations.size() >= 2, "expected multiple translations");
PASS();
}
void test_async_python_to_python_stays_safe() {
TEST(async_python_to_python_stays_safe);
auto r = ConcurrencyTranslator::analyze("async def f(): await g()", "python", "python");
CHECK(r.hasPattern("async/await"), "expected async pattern");
CHECK(r.translations[0].safety == ConcurrencySafety::Safe, "python async should stay safe");
PASS();
}
void test_review_count_aggregates_multiple_translations() {
TEST(review_count_aggregates_multiple_translations);
auto r = ConcurrencyTranslator::analyze(
"async def f(): await g()\nnew Thread(() -> {}).start();",
"python",
"java");
CHECK(r.translations.size() >= 2, "expected async + thread translations");
CHECK(r.countNeedsReview() >= 1, "expected review-required mappings");
PASS();
}
int main() {
std::cout << "Step 452: Concurrency Model Translation Tests\n";
test_async_python_to_rust_needs_runtime_review(); // 1
test_async_to_c_is_unsafe(); // 2
test_thread_java_to_go_maps_to_goroutine(); // 3
test_thread_to_python_marks_gil_review(); // 4
test_channels_go_to_rust_mpsc(); // 5
test_mutex_java_to_c_requires_review(); // 6
test_source_model_prefers_async_when_present(); // 7
test_target_model_defaults_for_javascript(); // 8
test_no_patterns_on_plain_code(); // 9
test_multiple_patterns_detected(); // 10
test_async_python_to_python_stays_safe(); // 11
test_review_count_aggregates_multiple_translations(); // 12
std::cout << "\nResults: " << passed << "/" << (passed + failed)
<< " passed\n";
return failed == 0 ? 0 : 1;
}

View File

@@ -5765,3 +5765,31 @@ classification and risk annotations for lossy projections.
**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)
### Step 452: Concurrency Model Translation
**Status:** PASS (12/12 tests)
Adds concurrency-pattern translation with explicit runtime/safety annotations
for async/thread/channel/mutex constructs across language runtime models.
**Files added:**
- `editor/src/ConcurrencyTranslator.h` — concurrency translation engine:
- source/target model detection (`Threads`, `AsyncAwait`, `Channels`, `EventLoop`)
- pattern translators for `async/await`, `thread_spawn`, `channels`, `mutex`
- runtime-aware annotations (`@Exec`, `@ThreadModel`, `@Sync`, `@Blocking`)
- safety grading (`Safe`, `NeedsReview`, `Unsafe`) and review counts
- `editor/tests/step452_test.cpp` — 12 tests covering:
- async mapping across Rust/Python/C targets
- thread/channel/mutex projection to Go/Rust/C
- source/target model detection behavior
- plain-code no-pattern behavior and multi-pattern aggregation
- `editor/CMakeLists.txt``step452_test` target
**Verification run:**
- `cmake --build editor/build-native --target step452_test` — PASS
- `./editor/build-native/step452_test` — PASS (12/12)
- `./editor/build-native/step451_test` — PASS (12/12) regression coverage
**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)