diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 4deb62c..dc8cdc8 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -2236,4 +2236,13 @@ target_link_libraries(step372_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step373_test tests/step373_test.cpp) +target_include_directories(step373_test PRIVATE src) +target_link_libraries(step373_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/tests/step373_test.cpp b/editor/tests/step373_test.cpp new file mode 100644 index 0000000..0e2c2fc --- /dev/null +++ b/editor/tests/step373_test.cpp @@ -0,0 +1,150 @@ +// Step 373: Common Lisp Integration (8 tests) + +#include +#include +#include +#include "Pipeline.h" +#include "CrossLanguageProjector.h" +#include "AnnotationInference.h" +#include "CompactAST.h" +#include "SemannoSidecar.h" +#include "ast/CommonLispParser.h" +#include "ast/CommonLispGenerator.h" + +static bool contains(const std::string& text, const std::string& token) { + return text.find(token) != std::string::npos; +} + +static bool hasInference(const std::vector& inferred, + const std::string& annotationType, + const std::string& value = "") { + for (const auto& a : inferred) { + if (a.annotationType != annotationType) continue; + if (value.empty() || a.value == value) return true; + } + return false; +} + +int main() { + int passed = 0; + + // Test 1: Parse CL -> generate CL -> parse roundtrip shape + { + std::string src = + "(defclass point () ((x) (y)))\n" + "(defun add (a b) (+ a b))\n"; + auto mod1 = CommonLispParser::parseCommonLisp(src); + CommonLispGenerator gen; + std::string out = gen.generate(mod1.get()); + auto mod2 = CommonLispParser::parseCommonLisp(out); + assert(mod1->getChildren("classes").size() == mod2->getChildren("classes").size()); + assert(mod1->getChildren("functions").size() == mod2->getChildren("functions").size()); + std::cout << "Test 1 PASSED: CL parse/generate/parse roundtrip\n"; + passed++; + } + + // Test 2: Python -> Common Lisp (class -> CLOS) + { + Pipeline p; + std::string py = + "class Point:\n" + " def __init__(self, x, y):\n" + " self.x = x\n" + " self.y = y\n"; + auto res = p.run(py, "python", "common-lisp"); + assert(res.success); + assert(contains(res.generatedCode, "(defclass")); + std::cout << "Test 2 PASSED: Python class -> Common Lisp CLOS form\n"; + passed++; + } + + // Test 3: Common Lisp -> Python projection retains class structure + { + auto src = CommonLispParser::parseCommonLisp("(defclass point () ((x) (y)))"); + CrossLanguageProjector projector; + auto pyMod = projector.project(src.get(), "python"); + Pipeline p; + auto code = p.generate(pyMod.get(), "python"); + assert(pyMod != nullptr); + assert(pyMod->getChildren("classes").size() == 1); + assert(!code.empty()); + std::cout << "Test 3 PASSED: Common Lisp class retained in Python projection\n"; + passed++; + } + + // Test 4: Common Lisp -> Java projection retains class hierarchy shape + { + auto src = CommonLispParser::parseCommonLisp("(defclass rectangle (shape) ((w) (h)))"); + CrossLanguageProjector projector; + auto javaMod = projector.project(src.get(), "java"); + assert(javaMod != nullptr); + assert(javaMod->getChildren("classes").size() == 1); + std::cout << "Test 4 PASSED: Common Lisp class retained in Java projection\n"; + passed++; + } + + // Test 5: CL annotation inference (macro, dynamic var, tail call) + { + std::string cl = + "(defmacro m (x) x)\n" + "(defvar *state* 1)\n" + "(defun loopf (n) (loopf n))\n"; + auto mod = CommonLispParser::parseCommonLisp(cl); + AnnotationInference inf; + auto inferred = inf.inferAll(mod.get()); + assert(hasInference(inferred, "MetaAnnotation", "quoted")); + assert(hasInference(inferred, "BindingAnnotation", "dynamic")); + assert(hasInference(inferred, "TailCallAnnotation")); + std::cout << "Test 5 PASSED: CL annotation inference integration\n"; + passed++; + } + + // Test 6: Semanno sidecar roundtrip on .lisp path + { + Module mod("m1", "cl_module", "common-lisp"); + auto* fn = new Function("f1", "run"); + fn->setSpan(1, 1, 1, 12); + auto* owner = new OwnerAnnotation("a1", "Shared_GC"); + fn->addChild("annotations", owner); + mod.addChild("functions", fn); + + std::string root = "/tmp/whetstone_step373"; + std::string filePath = "samples/test.lisp"; + auto save = saveSemannoSidecar(root, filePath, &mod); + auto load = loadSemannoSidecar(root, filePath); + assert(save.success); + assert(load.success); + assert(load.count >= 1); + std::cout << "Test 6 PASSED: Semanno sidecar roundtrip for CL\n"; + passed++; + } + + // Test 7: Pipeline.run with CL source succeeds + { + Pipeline p; + std::string cl = "(defun id (x) x)"; + auto res = p.run(cl, "common-lisp", "common-lisp"); + assert(res.success); + assert(!res.generatedCode.empty()); + std::cout << "Test 7 PASSED: Pipeline.run with CL source\n"; + passed++; + } + + // Test 8: Compact AST has meaningful Lisp node names + { + auto mod = CommonLispParser::parseCommonLisp("(defun id (x) x)"); + auto compact = toJsonCompactTree(mod.get()); + assert(compact.is_array()); + bool hasFunctionNode = false; + for (const auto& n : compact) { + if (n.contains("type") && n["type"] == "Function") hasFunctionNode = true; + } + assert(hasFunctionNode); + std::cout << "Test 8 PASSED: compact AST contains Function node\n"; + passed++; + } + + std::cout << "\nResults: " << passed << "/8\n"; + assert(passed == 8); + return 0; +} diff --git a/progress.md b/progress.md index 0039bbc..5cbf229 100644 --- a/progress.md +++ b/progress.md @@ -2533,6 +2533,38 @@ plus Common Lisp memory-strategy defaults. - `editor/src/MemoryStrategyInference.h` remains within header-size limit (`384` lines <= `600`) +### Step 373: Common Lisp Integration +**Status:** PASS (8/8 tests) + +Added phase-level integration validation for Common Lisp parse/generate +roundtrips, cross-language projection paths, inference integration, and CL +artifact compatibility with Semanno and compact AST tooling. + +**Files created:** +- `editor/tests/step373_test.cpp` — 8 integration tests covering: + 1. Common Lisp parse -> generate -> parse roundtrip shape + 2. Python class -> Common Lisp CLOS generation path + 3. Common Lisp defclass retained through Python projection + 4. Common Lisp class hierarchy retained through Java projection + 5. Common Lisp annotation inference integration (macro/dynamic/tail-call) + 6. Semanno sidecar save/load roundtrip on `.lisp` path + 7. `Pipeline.run()` success with Common Lisp source + 8. compact AST node naming on Common Lisp module + +**Files modified:** +- `editor/CMakeLists.txt` — `step373_test` target + +**Verification run:** +- `step373_test` — PASS (8/8) new step coverage +- `step372_test` — PASS (12/12) regression coverage +- `step371_test` — PASS (12/12) regression coverage +- `step370_test` — PASS (12/12) regression coverage +- `step369_test` — PASS (8/8) regression coverage + +**Architecture gate check:** +- `editor/tests/step373_test.cpp` remains within project file-size guidance + for test artifacts (`147` lines) + # Roadmap Planning — Sprints 12-25+ ## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)