Step 376: Add Scheme-specific annotation differentiation
This commit is contained in:
@@ -2263,4 +2263,13 @@ target_link_libraries(step375_test PRIVATE
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
add_executable(step376_test tests/step376_test.cpp)
|
||||
target_include_directories(step376_test PRIVATE src)
|
||||
target_link_libraries(step376_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)
|
||||
|
||||
@@ -16,6 +16,31 @@
|
||||
out.push_back({fn->id, "PolicyAnnotation", "style", "literal",
|
||||
"optimize declaration favors literal policy output", 0.86});
|
||||
}
|
||||
if ((hasCallNamed(fn, "call/cc") || hasCallNamed(fn, "call-with-current-continuation")) &&
|
||||
!hasInferred(out, fn->id, "ExecAnnotation", "continuation")) {
|
||||
out.push_back({fn->id, "ExecAnnotation", "mode", "continuation",
|
||||
"Scheme continuation primitives detected", 0.92});
|
||||
}
|
||||
if (hasCallNamed(fn, "make-parameter") &&
|
||||
!hasInferred(out, fn->id, "BindingAnnotation", "parameter")) {
|
||||
out.push_back({fn->id, "BindingAnnotation", "time", "parameter",
|
||||
"Scheme make-parameter indicates parameter binding model", 0.90});
|
||||
}
|
||||
if (hasCallNamed(fn, "guard") &&
|
||||
!hasInferred(out, fn->id, "ExceptionAnnotation", "guard")) {
|
||||
out.push_back({fn->id, "ExceptionAnnotation", "style", "guard",
|
||||
"Scheme guard form indicates guard-style exception handling", 0.88});
|
||||
}
|
||||
if (hasCallNamed(fn, "handler-case") &&
|
||||
!hasInferred(out, fn->id, "ExceptionAnnotation", "condition")) {
|
||||
out.push_back({fn->id, "ExceptionAnnotation", "style", "condition",
|
||||
"Common Lisp condition-system form detected", 0.88});
|
||||
}
|
||||
if (!fnName.empty() && isTailRecursive(fn, fnName) &&
|
||||
!hasInferred(out, fn->id, "LoopAnnotation", "tail-recursive")) {
|
||||
out.push_back({fn->id, "LoopAnnotation", "hint", "tail-recursive",
|
||||
"Tail recursion pattern maps to Scheme loop idiom", 0.85});
|
||||
}
|
||||
if (fn->conceptType == "MethodDeclaration" && fnName.size() > 0 &&
|
||||
!hasInferred(out, fn->id, "SyntheticAnnotation", "clos-method")) {
|
||||
out.push_back({fn->id, "SyntheticAnnotation", "generator", "clos-method",
|
||||
@@ -37,9 +62,15 @@
|
||||
}
|
||||
|
||||
void inferMacro(const ASTNode* macroNode, std::vector<InferredAnnotation>& out) const {
|
||||
if (!hasInferred(out, macroNode->id, "MetaAnnotation", "quoted")) {
|
||||
out.push_back({macroNode->id, "MetaAnnotation", "state", "quoted",
|
||||
"Macro definitions operate over quoted forms", 0.92});
|
||||
std::string metaState = "quoted";
|
||||
for (auto* anno : macroNode->getChildren("annotations")) {
|
||||
if (anno->conceptType != "MetaAnnotation") continue;
|
||||
auto* m = static_cast<const MetaAnnotation*>(anno);
|
||||
if (m->state == "hygienic") metaState = "hygienic";
|
||||
}
|
||||
if (!hasInferred(out, macroNode->id, "MetaAnnotation", metaState)) {
|
||||
out.push_back({macroNode->id, "MetaAnnotation", "state", metaState,
|
||||
"Macro form state inferred from language macro style", 0.92});
|
||||
}
|
||||
if (!hasInferred(out, macroNode->id, "SyntheticAnnotation", "macro")) {
|
||||
out.push_back({macroNode->id, "SyntheticAnnotation", "generator", "macro",
|
||||
|
||||
@@ -81,15 +81,15 @@ private:
|
||||
if (lang == "python" || lang == "elisp" || lang == "ruby" ||
|
||||
lang == "javascript" || lang == "java" || lang == "csharp" ||
|
||||
lang == "kotlin" || lang == "common-lisp" || lang == "commonlisp" ||
|
||||
lang == "lisp" || lang == "cl") {
|
||||
lang == "lisp" || lang == "cl" || lang == "scheme" || lang == "scm") {
|
||||
// GC languages → @Reclaim(Tracing) on the module
|
||||
out.push_back({mod->id, "ReclaimAnnotation", "Tracing",
|
||||
lang + " uses tracing garbage collection",
|
||||
0.95});
|
||||
if (lang == "common-lisp" || lang == "commonlisp" ||
|
||||
lang == "lisp" || lang == "cl") {
|
||||
lang == "lisp" || lang == "cl" || lang == "scheme" || lang == "scm") {
|
||||
out.push_back({mod->id, "OwnerAnnotation", "Shared_GC",
|
||||
"Common Lisp values are GC-managed shared objects",
|
||||
"Lisp-family values are GC-managed shared objects",
|
||||
0.92});
|
||||
}
|
||||
}
|
||||
|
||||
192
editor/tests/step376_test.cpp
Normal file
192
editor/tests/step376_test.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
// Step 376: Scheme-Specific Annotations + CL Differentiation (12 tests)
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "AnnotationInference.h"
|
||||
#include "MemoryStrategyInference.h"
|
||||
#include "CrossLanguageProjector.h"
|
||||
#include "Pipeline.h"
|
||||
#include "ast/SchemeParser.h"
|
||||
#include "ast/CommonLispParser.h"
|
||||
|
||||
static bool hasInference(const std::vector<AnnotationInference::InferredAnnotation>& 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;
|
||||
}
|
||||
|
||||
static bool hasMemory(const std::vector<MemoryStrategyInference::Suggestion>& suggestions,
|
||||
const std::string& annotationType,
|
||||
const std::string& strategy) {
|
||||
for (const auto& s : suggestions) {
|
||||
if (s.annotationType == annotationType && s.strategy == strategy) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
|
||||
// Test 1: Scheme tail recursion -> TailCall
|
||||
{
|
||||
auto mod = SchemeParser::parseScheme("(define (loopf n) (loopf n))");
|
||||
AnnotationInference inf;
|
||||
auto inferred = inf.inferAll(mod.get());
|
||||
assert(hasInference(inferred, "TailCallAnnotation"));
|
||||
std::cout << "Test 1 PASSED: Scheme tail recursion -> TailCall\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 2: call/cc -> Exec(continuation)
|
||||
{
|
||||
auto mod = SchemeParser::parseScheme("(define (cc f) (call/cc f))");
|
||||
AnnotationInference inf;
|
||||
auto inferred = inf.inferAll(mod.get());
|
||||
assert(hasInference(inferred, "ExecAnnotation", "continuation"));
|
||||
std::cout << "Test 2 PASSED: call/cc -> Exec(continuation)\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 3: define-syntax -> Meta(hygienic)
|
||||
{
|
||||
auto mod = SchemeParser::parseScheme("(define-syntax m (syntax-rules () ((_ x) x)))");
|
||||
AnnotationInference inf;
|
||||
auto inferred = inf.inferAll(mod.get());
|
||||
assert(hasInference(inferred, "MetaAnnotation", "hygienic"));
|
||||
std::cout << "Test 3 PASSED: define-syntax -> Meta(hygienic)\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 4: CL -> Scheme projection path works
|
||||
{
|
||||
Pipeline p;
|
||||
auto res = p.run("(defun id (x) x)", "common-lisp", "scheme");
|
||||
assert(res.success);
|
||||
assert(!res.generatedCode.empty());
|
||||
std::cout << "Test 4 PASSED: CL -> Scheme projection path\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 5: Scheme -> CL projection path works
|
||||
{
|
||||
Pipeline p;
|
||||
auto res = p.run("(define (id x) x)", "scheme", "common-lisp");
|
||||
assert(res.success);
|
||||
assert(!res.generatedCode.empty());
|
||||
std::cout << "Test 5 PASSED: Scheme -> CL projection path\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 6: both Scheme and CL use GC defaults
|
||||
{
|
||||
MemoryStrategyInference mem;
|
||||
Module scm("m1", "scm", "scheme");
|
||||
Module cl("m2", "cl", "common-lisp");
|
||||
auto s1 = mem.inferAnnotations(&scm);
|
||||
auto s2 = mem.inferAnnotations(&cl);
|
||||
assert(hasMemory(s1, "ReclaimAnnotation", "Tracing"));
|
||||
assert(hasMemory(s2, "ReclaimAnnotation", "Tracing"));
|
||||
std::cout << "Test 6 PASSED: Scheme/CL GC defaults\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 7: differentiate @Meta between CL and Scheme macros
|
||||
{
|
||||
auto cl = CommonLispParser::parseCommonLisp("(defmacro m (x) x)");
|
||||
auto scm = SchemeParser::parseScheme("(define-syntax m (syntax-rules () ((_ x) x)))");
|
||||
AnnotationInference inf;
|
||||
auto clInf = inf.inferAll(cl.get());
|
||||
auto scmInf = inf.inferAll(scm.get());
|
||||
assert(hasInference(clInf, "MetaAnnotation", "quoted"));
|
||||
assert(hasInference(scmInf, "MetaAnnotation", "hygienic"));
|
||||
std::cout << "Test 7 PASSED: differentiated macro meta states\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 8: differentiate @Binding types
|
||||
{
|
||||
auto cl = CommonLispParser::parseCommonLisp("(defvar *special* 1)");
|
||||
auto scm = SchemeParser::parseScheme("(define (mk) (make-parameter 42))");
|
||||
AnnotationInference inf;
|
||||
auto clInf = inf.inferAll(cl.get());
|
||||
auto scmInf = inf.inferAll(scm.get());
|
||||
assert(hasInference(clInf, "BindingAnnotation", "dynamic"));
|
||||
assert(hasInference(scmInf, "BindingAnnotation", "parameter"));
|
||||
std::cout << "Test 8 PASSED: differentiated binding types\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 9: differentiate @Exception types
|
||||
{
|
||||
auto cl = CommonLispParser::parseCommonLisp("(defun f () (handler-case x))");
|
||||
auto scm = SchemeParser::parseScheme("(define (g) (guard (e (#t e)) e))");
|
||||
AnnotationInference inf;
|
||||
auto clInf = inf.inferAll(cl.get());
|
||||
auto scmInf = inf.inferAll(scm.get());
|
||||
assert(hasInference(clInf, "ExceptionAnnotation", "condition"));
|
||||
assert(hasInference(scmInf, "ExceptionAnnotation", "guard"));
|
||||
std::cout << "Test 9 PASSED: differentiated exception styles\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 10: cross-language annotation fidelity Scheme <-> CL
|
||||
{
|
||||
Module mod("m1", "scheme", "scheme");
|
||||
auto* fn = new Function("f1", "cc");
|
||||
auto* ex = new ExecAnnotation();
|
||||
ex->id = "a1";
|
||||
ex->mode = "continuation";
|
||||
fn->addChild("annotations", ex);
|
||||
mod.addChild("functions", fn);
|
||||
auto* mac = new MacroDefinition("m1", "mac");
|
||||
auto* meta = new MetaAnnotation();
|
||||
meta->id = "a2";
|
||||
meta->state = "hygienic";
|
||||
mac->addChild("annotations", meta);
|
||||
mod.addChild("statements", mac);
|
||||
|
||||
CrossLanguageProjector projector;
|
||||
auto cl = projector.project(&mod, "common-lisp");
|
||||
auto back = projector.project(cl.get(), "scheme");
|
||||
assert(projector.annotationsPreserved(&mod, back.get()));
|
||||
std::cout << "Test 10 PASSED: annotation fidelity across Scheme/CL\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 11: Scheme tail recursion also maps to Loop(tail-recursive)
|
||||
{
|
||||
auto mod = SchemeParser::parseScheme("(define (loopf n) (loopf n))");
|
||||
AnnotationInference inf;
|
||||
auto inferred = inf.inferAll(mod.get());
|
||||
assert(hasInference(inferred, "LoopAnnotation", "tail-recursive"));
|
||||
std::cout << "Test 11 PASSED: Scheme loop tail-recursive signal\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 12: confidence values remain bounded
|
||||
{
|
||||
auto mod = SchemeParser::parseScheme(
|
||||
"(define-syntax m (syntax-rules () ((_ x) x)))\n"
|
||||
"(define (cc f) (call/cc f))\n");
|
||||
AnnotationInference inf;
|
||||
auto inferred = inf.inferAll(mod.get());
|
||||
bool strong = false;
|
||||
for (const auto& a : inferred) {
|
||||
assert(a.confidence >= 0.0 && a.confidence <= 1.0);
|
||||
if (a.confidence >= 0.85) strong = true;
|
||||
}
|
||||
assert(strong);
|
||||
std::cout << "Test 12 PASSED: confidence bounds\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
std::cout << "\nResults: " << passed << "/12\n";
|
||||
assert(passed == 12);
|
||||
return 0;
|
||||
}
|
||||
49
progress.md
49
progress.md
@@ -2656,6 +2656,55 @@ annotation handling.
|
||||
- `editor/src/ast/SchemeGenerator.h` is within header size limit
|
||||
(`159` lines <= `600`)
|
||||
|
||||
### Step 376: Scheme-Specific Annotations + CL Differentiation
|
||||
**Status:** PASS (12/12 tests)
|
||||
|
||||
Added Scheme-specific inference signals and explicit Common Lisp vs Scheme
|
||||
differentiation rules in annotation inference, plus Scheme memory defaults in
|
||||
memory-strategy inference.
|
||||
|
||||
**Files created:**
|
||||
- `editor/tests/step376_test.cpp` — 12 tests covering:
|
||||
1. Scheme tail recursion -> `TailCall`
|
||||
2. `call/cc` -> `Exec(continuation)`
|
||||
3. `define-syntax` -> `Meta(hygienic)`
|
||||
4. CL -> Scheme projection path
|
||||
5. Scheme -> CL projection path
|
||||
6. GC defaults for both Scheme and CL
|
||||
7. differentiated macro meta states (quoted vs hygienic)
|
||||
8. differentiated binding states (dynamic vs parameter)
|
||||
9. differentiated exception styles (condition vs guard)
|
||||
10. Scheme/CL annotation fidelity through projection
|
||||
11. tail-recursive loop idiom signal (`Loop(tail-recursive)`)
|
||||
12. confidence bound checks
|
||||
|
||||
**Files modified:**
|
||||
- `editor/src/AnnotationInferenceLisp.h` — add Lisp/Scheme-specific inference:
|
||||
- continuation detection (`call/cc`, `call-with-current-continuation`)
|
||||
- parameter-binding detection (`make-parameter`)
|
||||
- condition-vs-guard exception style differentiation
|
||||
- tail-recursive loop signal (`LoopAnnotation: tail-recursive`)
|
||||
- macro meta-state differentiation via existing hygienic/quoted metadata
|
||||
- `editor/src/MemoryStrategyInference.h` — add Scheme defaults:
|
||||
- include `scheme/scm` in tracing-GC defaults
|
||||
- shared GC ownership default for Lisp-family modules
|
||||
- `editor/CMakeLists.txt` — `step376_test` target
|
||||
|
||||
**Verification run:**
|
||||
- `step376_test` — PASS (12/12) new step coverage
|
||||
- `step375_test` — PASS (12/12) regression coverage
|
||||
- `step374_test` — PASS (12/12) regression coverage
|
||||
- `step373_test` — PASS (8/8) regression coverage
|
||||
- `step372_test` — PASS (12/12) regression coverage
|
||||
|
||||
**Architecture gate check:**
|
||||
- `editor/src/AnnotationInference.h` remains within header-size limit
|
||||
(`599` lines <= `600`)
|
||||
- `editor/src/MemoryStrategyInference.h` remains within header-size limit
|
||||
(`384` lines <= `600`)
|
||||
- `editor/src/AnnotationInferenceLisp.h` remains within header-size guidance
|
||||
(`129` lines)
|
||||
|
||||
# Roadmap Planning — Sprints 12-25+
|
||||
|
||||
## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)
|
||||
|
||||
Reference in New Issue
Block a user