diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 161ce2a..1d4f9e6 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -1662,4 +1662,40 @@ target_link_libraries(step271_test PRIVATE tree_sitter_java tree_sitter_rust tree_sitter_go tree_sitter_org) +# Step 272: Type System — Layout & Constraints +add_executable(step272_test tests/step272_test.cpp) +target_include_directories(step272_test PRIVATE src) +target_link_libraries(step272_test PRIVATE nlohmann_json::nlohmann_json) + +# Step 273: Type System — Identity & Mutability +add_executable(step273_test tests/step273_test.cpp) +target_include_directories(step273_test PRIVATE src) +target_link_libraries(step273_test PRIVATE nlohmann_json::nlohmann_json) + +# Step 274: Concurrency — Primitives & Memory Model +add_executable(step274_test tests/step274_test.cpp) +target_include_directories(step274_test PRIVATE src) +target_link_libraries(step274_test PRIVATE nlohmann_json::nlohmann_json) + +# Step 275: Async, Parallelism & Error Handling +add_executable(step275_test tests/step275_test.cpp) +target_include_directories(step275_test PRIVATE src) +target_link_libraries(step275_test PRIVATE nlohmann_json::nlohmann_json) + +# Step 276: Scope & Namespace Annotations +add_executable(step276_test tests/step276_test.cpp) +target_include_directories(step276_test PRIVATE src) +target_link_libraries(step276_test PRIVATE nlohmann_json::nlohmann_json) + +# Step 277: Phase 10c Integration Tests +add_executable(step277_test tests/step277_test.cpp) +target_include_directories(step277_test PRIVATE src) +target_link_libraries(step277_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 + tree_sitter_org) + # Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies) diff --git a/editor/src/CompactAST.h b/editor/src/CompactAST.h index 672e50d..36b395f 100644 --- a/editor/src/CompactAST.h +++ b/editor/src/CompactAST.h @@ -58,6 +58,115 @@ inline json extractSemanticSummary(const ASTNode* node) { auto* ta = static_cast(a); if (!ta->tags.empty()) sem["tags"] = ta->tags; } + // Type System — Layout & Constraints (Step 272) + else if (a->conceptType == "BitWidthAnnotation") { + auto* ba = static_cast(a); + sem["bitWidth"] = ba->width; + } + else if (a->conceptType == "EndianAnnotation") { + auto* ea = static_cast(a); + if (!ea->order.empty()) sem["endian"] = ea->order; + } + else if (a->conceptType == "LayoutAnnotation") { + auto* la = static_cast(a); + json obj; + if (!la->mode.empty()) obj["mode"] = la->mode; + if (la->alignment > 0) obj["alignment"] = la->alignment; + if (!obj.empty()) sem["layout"] = obj; + } + else if (a->conceptType == "NullabilityAnnotation") { + auto* na = static_cast(a); + json obj; + obj["nullable"] = na->nullable; + if (!na->strategy.empty()) obj["strategy"] = na->strategy; + sem["nullability"] = obj; + } + else if (a->conceptType == "VarianceAnnotation") { + auto* va = static_cast(a); + if (!va->variance.empty()) sem["variance"] = va->variance; + } + // Type System — Identity & Mutability (Step 273) + else if (a->conceptType == "IdentityAnnotation") { + auto* ia = static_cast(a); + if (!ia->mode.empty()) sem["identity"] = ia->mode; + } + else if (a->conceptType == "MutAnnotation") { + auto* ma = static_cast(a); + if (!ma->depth.empty()) sem["mutability"] = ma->depth; + } + else if (a->conceptType == "TypeStateAnnotation") { + auto* ts = static_cast(a); + if (!ts->state.empty()) sem["typeState"] = ts->state; + } + // Concurrency (Step 274) + else if (a->conceptType == "AtomicAnnotation") { + auto* aa = static_cast(a); + if (!aa->consistency.empty()) sem["atomic"] = aa->consistency; + } + else if (a->conceptType == "SyncAnnotation") { + auto* sa = static_cast(a); + if (!sa->primitive.empty()) sem["sync"] = sa->primitive; + } + else if (a->conceptType == "ThreadModelAnnotation") { + auto* tm = static_cast(a); + if (!tm->model.empty()) sem["threadModel"] = tm->model; + } + else if (a->conceptType == "MemoryBarrierAnnotation") { + sem["memoryBarrier"] = true; + } + // Async, Parallelism & Error Handling (Step 275) + else if (a->conceptType == "ExecAnnotation") { + auto* ea = static_cast(a); + json obj; + if (!ea->mode.empty()) obj["mode"] = ea->mode; + if (!ea->runtimeHint.empty()) obj["runtime"] = ea->runtimeHint; + if (!obj.empty()) sem["exec"] = obj; + } + else if (a->conceptType == "BlockingAnnotation") { + auto* ba = static_cast(a); + if (!ba->kind.empty()) sem["blocking"] = ba->kind; + } + else if (a->conceptType == "ParallelAnnotation") { + auto* pa = static_cast(a); + if (!pa->kind.empty()) sem["parallel"] = pa->kind; + } + else if (a->conceptType == "TrapAnnotation") { + auto* ta = static_cast(a); + if (!ta->signal.empty()) sem["trap"] = ta->signal; + } + else if (a->conceptType == "ExceptionAnnotation") { + auto* ea = static_cast(a); + if (!ea->style.empty()) sem["exception"] = ea->style; + } + else if (a->conceptType == "PanicAnnotation") { + auto* pa = static_cast(a); + if (!pa->behavior.empty()) sem["panic"] = pa->behavior; + } + // Scope & Namespace (Step 276) + else if (a->conceptType == "BindingAnnotation") { + auto* ba = static_cast(a); + if (!ba->time.empty()) sem["binding"] = ba->time; + } + else if (a->conceptType == "LookupAnnotation") { + auto* la = static_cast(a); + if (!la->mode.empty()) sem["lookup"] = la->mode; + } + else if (a->conceptType == "CaptureAnnotation") { + auto* ca = static_cast(a); + if (!ca->strategy.empty()) sem["capture"] = ca->strategy; + } + else if (a->conceptType == "VisibilityAnnotation") { + auto* va = static_cast(a); + if (!va->level.empty()) sem["visibility"] = va->level; + } + else if (a->conceptType == "NamespaceAnnotation") { + auto* na = static_cast(a); + if (!na->style.empty()) sem["namespace"] = na->style; + } + else if (a->conceptType == "ScopeAnnotation") { + auto* sa = static_cast(a); + if (!sa->kind.empty()) sem["scope"] = sa->kind; + } } return sem.empty() ? json() : sem; } diff --git a/editor/src/HeadlessAgentRPCHandler.h b/editor/src/HeadlessAgentRPCHandler.h index 96797f1..ffab5de 100644 --- a/editor/src/HeadlessAgentRPCHandler.h +++ b/editor/src/HeadlessAgentRPCHandler.h @@ -1654,6 +1654,34 @@ inline json handleHeadlessAgentRequest(HeadlessEditorState& state, else if (type == "risk") conceptType = "RiskAnnotation"; else if (type == "contract") conceptType = "ContractAnnotation"; else if (type == "tags") conceptType = "SemanticTagAnnotation"; + // Type System (Steps 272-273) + else if (type == "bitWidth") conceptType = "BitWidthAnnotation"; + else if (type == "endian") conceptType = "EndianAnnotation"; + else if (type == "layout") conceptType = "LayoutAnnotation"; + else if (type == "nullability") conceptType = "NullabilityAnnotation"; + else if (type == "variance") conceptType = "VarianceAnnotation"; + else if (type == "identity") conceptType = "IdentityAnnotation"; + else if (type == "mut") conceptType = "MutAnnotation"; + else if (type == "typeState") conceptType = "TypeStateAnnotation"; + // Concurrency (Step 274) + else if (type == "atomic") conceptType = "AtomicAnnotation"; + else if (type == "sync") conceptType = "SyncAnnotation"; + else if (type == "threadModel") conceptType = "ThreadModelAnnotation"; + else if (type == "memoryBarrier") conceptType = "MemoryBarrierAnnotation"; + // Async / Error Handling (Step 275) + else if (type == "exec") conceptType = "ExecAnnotation"; + else if (type == "blocking") conceptType = "BlockingAnnotation"; + else if (type == "parallel") conceptType = "ParallelAnnotation"; + else if (type == "trap") conceptType = "TrapAnnotation"; + else if (type == "exception") conceptType = "ExceptionAnnotation"; + else if (type == "panic") conceptType = "PanicAnnotation"; + // Scope & Namespace (Step 276) + else if (type == "binding") conceptType = "BindingAnnotation"; + else if (type == "lookup") conceptType = "LookupAnnotation"; + else if (type == "capture") conceptType = "CaptureAnnotation"; + else if (type == "visibility") conceptType = "VisibilityAnnotation"; + else if (type == "namespace") conceptType = "NamespaceAnnotation"; + else if (type == "scope") conceptType = "ScopeAnnotation"; else return headlessRpcError(id, -32602, "Unknown annotation type: " + type); // Remove existing annotation of same type (update semantics) @@ -1722,6 +1750,12 @@ inline json handleHeadlessAgentRequest(HeadlessEditorState& state, } else if (a->conceptType == "SemanticTagAnnotation") { auto* ta = static_cast(a); entry = {{"type", "tags"}, {"tags", ta->tags}}; + } else { + // Generic fallback for all other semantic annotations + entry = {{"type", a->conceptType}}; + json props = propertiesToJson(a); + for (auto& [k, v] : props.items()) + entry[k] = v; } if (!entry.empty()) annos.push_back(entry); } @@ -1749,6 +1783,11 @@ inline json handleHeadlessAgentRequest(HeadlessEditorState& state, } else if (a->conceptType == "SemanticTagAnnotation") { auto* ta = static_cast(a); entry = {{"type", "tags"}, {"tags", ta->tags}}; + } else { + entry = {{"type", a->conceptType}}; + json props = propertiesToJson(a); + for (auto& [k, v] : props.items()) + entry[k] = v; } if (!entry.empty()) annoList.push_back(entry); } diff --git a/editor/src/SidecarPersistence.h b/editor/src/SidecarPersistence.h index 10783d0..9650c31 100644 --- a/editor/src/SidecarPersistence.h +++ b/editor/src/SidecarPersistence.h @@ -23,17 +23,50 @@ inline std::string sidecarPath(const std::string& workspaceRoot, return (base / (filePath + ".ast.json")).string(); } +// --- Check if a node type is a semantic annotation --- +inline bool isSemanticAnnotation(const std::string& conceptType) { + return conceptType == "IntentAnnotation" || + conceptType == "ComplexityAnnotation" || + conceptType == "RiskAnnotation" || + conceptType == "ContractAnnotation" || + conceptType == "SemanticTagAnnotation" || + // Type System (Steps 272-273) + conceptType == "BitWidthAnnotation" || + conceptType == "EndianAnnotation" || + conceptType == "LayoutAnnotation" || + conceptType == "NullabilityAnnotation" || + conceptType == "VarianceAnnotation" || + conceptType == "IdentityAnnotation" || + conceptType == "MutAnnotation" || + conceptType == "TypeStateAnnotation" || + // Concurrency (Step 274) + conceptType == "AtomicAnnotation" || + conceptType == "SyncAnnotation" || + conceptType == "ThreadModelAnnotation" || + conceptType == "MemoryBarrierAnnotation" || + // Async / Error Handling (Step 275) + conceptType == "ExecAnnotation" || + conceptType == "BlockingAnnotation" || + conceptType == "ParallelAnnotation" || + conceptType == "TrapAnnotation" || + conceptType == "ExceptionAnnotation" || + conceptType == "PanicAnnotation" || + // Scope & Namespace (Step 276) + conceptType == "BindingAnnotation" || + conceptType == "LookupAnnotation" || + conceptType == "CaptureAnnotation" || + conceptType == "VisibilityAnnotation" || + conceptType == "NamespaceAnnotation" || + conceptType == "ScopeAnnotation"; +} + // --- Count semantic annotations in an AST --- inline int countSemanticAnnotations(const ASTNode* node) { if (!node) return 0; int count = 0; auto annos = node->getChildren("annotations"); for (const auto* a : annos) { - if (a->conceptType == "IntentAnnotation" || - a->conceptType == "ComplexityAnnotation" || - a->conceptType == "RiskAnnotation" || - a->conceptType == "ContractAnnotation" || - a->conceptType == "SemanticTagAnnotation") + if (isSemanticAnnotation(a->conceptType)) ++count; } for (const auto* child : node->allChildren()) { @@ -77,15 +110,6 @@ inline SidecarSaveResult saveSidecarAST(const std::string& workspaceRoot, return result; } -// --- Check if a node type is a semantic annotation --- -inline bool isSemanticAnnotation(const std::string& conceptType) { - return conceptType == "IntentAnnotation" || - conceptType == "ComplexityAnnotation" || - conceptType == "RiskAnnotation" || - conceptType == "ContractAnnotation" || - conceptType == "SemanticTagAnnotation"; -} - // --- Find a matching node in the live AST --- // Tries ID match first, then falls back to concept+name match // (node IDs are ephemeral and change across re-parses). diff --git a/editor/src/ast/Annotation.h b/editor/src/ast/Annotation.h index 151a044..b30fb49 100644 --- a/editor/src/ast/Annotation.h +++ b/editor/src/ast/Annotation.h @@ -182,3 +182,159 @@ public: std::vector tags; // e.g. ["@serialize", "@validation"] SemanticTagAnnotation() { conceptType = "SemanticTagAnnotation"; } }; + +// Type System Annotations — Layout & Constraints (Step 272, Subject 2) + +class BitWidthAnnotation : public Annotation { +public: + int width = 0; // e.g. 32 for Java int + BitWidthAnnotation() { conceptType = "BitWidthAnnotation"; } +}; + +class EndianAnnotation : public Annotation { +public: + std::string order; // "big" | "little" + EndianAnnotation() { conceptType = "EndianAnnotation"; } +}; + +class LayoutAnnotation : public Annotation { +public: + std::string mode; // "packed" | "aligned" + int alignment = 0; + LayoutAnnotation() { conceptType = "LayoutAnnotation"; } +}; + +class NullabilityAnnotation : public Annotation { +public: + bool nullable = false; + std::string strategy; // "strict" | "nullable" + NullabilityAnnotation() { conceptType = "NullabilityAnnotation"; } +}; + +class VarianceAnnotation : public Annotation { +public: + std::string variance; // "covariant" | "contravariant" | "invariant" + VarianceAnnotation() { conceptType = "VarianceAnnotation"; } +}; + +// Type System Annotations — Identity & Mutability (Step 273, Subject 2) + +class IdentityAnnotation : public Annotation { +public: + std::string mode; // "nominal" | "structural" + IdentityAnnotation() { conceptType = "IdentityAnnotation"; } +}; + +class MutAnnotation : public Annotation { +public: + std::string depth; // "shallow" | "deep" | "interior" + MutAnnotation() { conceptType = "MutAnnotation"; } +}; + +class TypeStateAnnotation : public Annotation { +public: + std::string state; // "erased" | "reified" + TypeStateAnnotation() { conceptType = "TypeStateAnnotation"; } +}; + +// Concurrency Annotations — Primitives & Memory Model (Step 274, Subject 3) + +class AtomicAnnotation : public Annotation { +public: + std::string consistency; // "seq_cst" | "relaxed" | "acquire" | "release" + AtomicAnnotation() { conceptType = "AtomicAnnotation"; } +}; + +class SyncAnnotation : public Annotation { +public: + std::string primitive; // "monitor" | "spin" | "semaphore" + SyncAnnotation() { conceptType = "SyncAnnotation"; } +}; + +class ThreadModelAnnotation : public Annotation { +public: + std::string model; // "green" | "os" | "fiber" + ThreadModelAnnotation() { conceptType = "ThreadModelAnnotation"; } +}; + +class MemoryBarrierAnnotation : public Annotation { +public: + MemoryBarrierAnnotation() { conceptType = "MemoryBarrierAnnotation"; } +}; + +// Async, Parallelism & Error Handling Annotations (Step 275, Subject 3) + +class ExecAnnotation : public Annotation { +public: + std::string mode; // "async" | "event" + std::string runtimeHint; // e.g. "tokio", "libuv" + ExecAnnotation() { conceptType = "ExecAnnotation"; } +}; + +class BlockingAnnotation : public Annotation { +public: + std::string kind; // "io" | "compute" + BlockingAnnotation() { conceptType = "BlockingAnnotation"; } +}; + +class ParallelAnnotation : public Annotation { +public: + std::string kind; // "data" | "task" + ParallelAnnotation() { conceptType = "ParallelAnnotation"; } +}; + +class TrapAnnotation : public Annotation { +public: + std::string signal; // e.g. "SIGSEGV", "SIGFPE" + TrapAnnotation() { conceptType = "TrapAnnotation"; } +}; + +class ExceptionAnnotation : public Annotation { +public: + std::string style; // "checked" | "unchecked" + ExceptionAnnotation() { conceptType = "ExceptionAnnotation"; } +}; + +class PanicAnnotation : public Annotation { +public: + std::string behavior; // "abort" | "unwind" + PanicAnnotation() { conceptType = "PanicAnnotation"; } +}; + +// Scope & Namespace Annotations (Step 276, Subject 4) + +class BindingAnnotation : public Annotation { +public: + std::string time; // "static" | "dynamic" + BindingAnnotation() { conceptType = "BindingAnnotation"; } +}; + +class LookupAnnotation : public Annotation { +public: + std::string mode; // "lexical" | "hoisted" + LookupAnnotation() { conceptType = "LookupAnnotation"; } +}; + +class CaptureAnnotation : public Annotation { +public: + std::string strategy; // "value" | "ref" | "move" + CaptureAnnotation() { conceptType = "CaptureAnnotation"; } +}; + +class VisibilityAnnotation : public Annotation { +public: + std::string level; // "private" | "internal" | "friend" | "public" + VisibilityAnnotation() { conceptType = "VisibilityAnnotation"; } +}; + +class NamespaceAnnotation : public Annotation { +public: + std::string style; // "qualified" | "flat" + NamespaceAnnotation() { conceptType = "NamespaceAnnotation"; } +}; + +class ScopeAnnotation : public Annotation { +public: + std::string kind; // "local" | "global_leaked" | "singleton" + ScopeAnnotation() { conceptType = "ScopeAnnotation"; } +}; diff --git a/editor/src/ast/Serialization.h b/editor/src/ast/Serialization.h index 427cd81..3e09869 100644 --- a/editor/src/ast/Serialization.h +++ b/editor/src/ast/Serialization.h @@ -163,6 +163,107 @@ inline json propertiesToJson(const ASTNode* node) { auto* n = static_cast(node); if (!n->tags.empty()) props["tags"] = n->tags; } + // Type System — Layout & Constraints (Step 272) + else if (ct == "BitWidthAnnotation") { + auto* n = static_cast(node); + props["width"] = n->width; + } + else if (ct == "EndianAnnotation") { + auto* n = static_cast(node); + if (!n->order.empty()) props["order"] = n->order; + } + else if (ct == "LayoutAnnotation") { + auto* n = static_cast(node); + if (!n->mode.empty()) props["mode"] = n->mode; + props["alignment"] = n->alignment; + } + else if (ct == "NullabilityAnnotation") { + auto* n = static_cast(node); + props["nullable"] = n->nullable; + if (!n->strategy.empty()) props["strategy"] = n->strategy; + } + else if (ct == "VarianceAnnotation") { + auto* n = static_cast(node); + if (!n->variance.empty()) props["variance"] = n->variance; + } + // Type System — Identity & Mutability (Step 273) + else if (ct == "IdentityAnnotation") { + auto* n = static_cast(node); + if (!n->mode.empty()) props["mode"] = n->mode; + } + else if (ct == "MutAnnotation") { + auto* n = static_cast(node); + if (!n->depth.empty()) props["depth"] = n->depth; + } + else if (ct == "TypeStateAnnotation") { + auto* n = static_cast(node); + if (!n->state.empty()) props["state"] = n->state; + } + // Concurrency — Primitives & Memory Model (Step 274) + else if (ct == "AtomicAnnotation") { + auto* n = static_cast(node); + if (!n->consistency.empty()) props["consistency"] = n->consistency; + } + else if (ct == "SyncAnnotation") { + auto* n = static_cast(node); + if (!n->primitive.empty()) props["primitive"] = n->primitive; + } + else if (ct == "ThreadModelAnnotation") { + auto* n = static_cast(node); + if (!n->model.empty()) props["model"] = n->model; + } + // MemoryBarrierAnnotation has no extra fields + // Async, Parallelism & Error Handling (Step 275) + else if (ct == "ExecAnnotation") { + auto* n = static_cast(node); + if (!n->mode.empty()) props["mode"] = n->mode; + if (!n->runtimeHint.empty()) props["runtimeHint"] = n->runtimeHint; + } + else if (ct == "BlockingAnnotation") { + auto* n = static_cast(node); + if (!n->kind.empty()) props["kind"] = n->kind; + } + else if (ct == "ParallelAnnotation") { + auto* n = static_cast(node); + if (!n->kind.empty()) props["kind"] = n->kind; + } + else if (ct == "TrapAnnotation") { + auto* n = static_cast(node); + if (!n->signal.empty()) props["signal"] = n->signal; + } + else if (ct == "ExceptionAnnotation") { + auto* n = static_cast(node); + if (!n->style.empty()) props["style"] = n->style; + } + else if (ct == "PanicAnnotation") { + auto* n = static_cast(node); + if (!n->behavior.empty()) props["behavior"] = n->behavior; + } + // Scope & Namespace (Step 276) + else if (ct == "BindingAnnotation") { + auto* n = static_cast(node); + if (!n->time.empty()) props["time"] = n->time; + } + else if (ct == "LookupAnnotation") { + auto* n = static_cast(node); + if (!n->mode.empty()) props["mode"] = n->mode; + } + else if (ct == "CaptureAnnotation") { + auto* n = static_cast(node); + if (!n->strategy.empty()) props["strategy"] = n->strategy; + } + else if (ct == "VisibilityAnnotation") { + auto* n = static_cast(node); + if (!n->level.empty()) props["level"] = n->level; + } + else if (ct == "NamespaceAnnotation") { + auto* n = static_cast(node); + if (!n->style.empty()) props["style"] = n->style; + } + else if (ct == "ScopeAnnotation") { + auto* n = static_cast(node); + if (!n->kind.empty()) props["kind"] = n->kind; + } // NullLiteral, ListLiteral, IndexAccess, Block, Assignment, IfStatement, // WhileLoop, Return, ExpressionStatement, ListType, SetType, MapType, // TupleType, ArrayType, OptionalType — no extra properties @@ -240,6 +341,35 @@ inline ASTNode* createNode(const std::string& conceptName) { if (conceptName == "RiskAnnotation") return new RiskAnnotation(); if (conceptName == "ContractAnnotation") return new ContractAnnotation(); if (conceptName == "SemanticTagAnnotation") return new SemanticTagAnnotation(); + // Type System — Layout & Constraints (Step 272) + if (conceptName == "BitWidthAnnotation") return new BitWidthAnnotation(); + if (conceptName == "EndianAnnotation") return new EndianAnnotation(); + if (conceptName == "LayoutAnnotation") return new LayoutAnnotation(); + if (conceptName == "NullabilityAnnotation") return new NullabilityAnnotation(); + if (conceptName == "VarianceAnnotation") return new VarianceAnnotation(); + // Type System — Identity & Mutability (Step 273) + if (conceptName == "IdentityAnnotation") return new IdentityAnnotation(); + if (conceptName == "MutAnnotation") return new MutAnnotation(); + if (conceptName == "TypeStateAnnotation") return new TypeStateAnnotation(); + // Concurrency (Step 274) + if (conceptName == "AtomicAnnotation") return new AtomicAnnotation(); + if (conceptName == "SyncAnnotation") return new SyncAnnotation(); + if (conceptName == "ThreadModelAnnotation") return new ThreadModelAnnotation(); + if (conceptName == "MemoryBarrierAnnotation") return new MemoryBarrierAnnotation(); + // Async, Parallelism & Error Handling (Step 275) + if (conceptName == "ExecAnnotation") return new ExecAnnotation(); + if (conceptName == "BlockingAnnotation") return new BlockingAnnotation(); + if (conceptName == "ParallelAnnotation") return new ParallelAnnotation(); + if (conceptName == "TrapAnnotation") return new TrapAnnotation(); + if (conceptName == "ExceptionAnnotation") return new ExceptionAnnotation(); + if (conceptName == "PanicAnnotation") return new PanicAnnotation(); + // Scope & Namespace (Step 276) + if (conceptName == "BindingAnnotation") return new BindingAnnotation(); + if (conceptName == "LookupAnnotation") return new LookupAnnotation(); + if (conceptName == "CaptureAnnotation") return new CaptureAnnotation(); + if (conceptName == "VisibilityAnnotation") return new VisibilityAnnotation(); + if (conceptName == "NamespaceAnnotation") return new NamespaceAnnotation(); + if (conceptName == "ScopeAnnotation") return new ScopeAnnotation(); return nullptr; } @@ -396,6 +526,107 @@ inline void setPropertiesFromJson(ASTNode* node, const json& props) { } } } + // Type System — Layout & Constraints (Step 272) + else if (ct == "BitWidthAnnotation") { + auto* n = static_cast(node); + if (props.contains("width")) n->width = props["width"].get(); + } + else if (ct == "EndianAnnotation") { + auto* n = static_cast(node); + if (props.contains("order")) n->order = props["order"].get(); + } + else if (ct == "LayoutAnnotation") { + auto* n = static_cast(node); + if (props.contains("mode")) n->mode = props["mode"].get(); + if (props.contains("alignment")) n->alignment = props["alignment"].get(); + } + else if (ct == "NullabilityAnnotation") { + auto* n = static_cast(node); + if (props.contains("nullable")) n->nullable = props["nullable"].get(); + if (props.contains("strategy")) n->strategy = props["strategy"].get(); + } + else if (ct == "VarianceAnnotation") { + auto* n = static_cast(node); + if (props.contains("variance")) n->variance = props["variance"].get(); + } + // Type System — Identity & Mutability (Step 273) + else if (ct == "IdentityAnnotation") { + auto* n = static_cast(node); + if (props.contains("mode")) n->mode = props["mode"].get(); + } + else if (ct == "MutAnnotation") { + auto* n = static_cast(node); + if (props.contains("depth")) n->depth = props["depth"].get(); + } + else if (ct == "TypeStateAnnotation") { + auto* n = static_cast(node); + if (props.contains("state")) n->state = props["state"].get(); + } + // Concurrency (Step 274) + else if (ct == "AtomicAnnotation") { + auto* n = static_cast(node); + if (props.contains("consistency")) n->consistency = props["consistency"].get(); + } + else if (ct == "SyncAnnotation") { + auto* n = static_cast(node); + if (props.contains("primitive")) n->primitive = props["primitive"].get(); + } + else if (ct == "ThreadModelAnnotation") { + auto* n = static_cast(node); + if (props.contains("model")) n->model = props["model"].get(); + } + // MemoryBarrierAnnotation has no extra fields + // Async, Parallelism & Error Handling (Step 275) + else if (ct == "ExecAnnotation") { + auto* n = static_cast(node); + if (props.contains("mode")) n->mode = props["mode"].get(); + if (props.contains("runtimeHint")) n->runtimeHint = props["runtimeHint"].get(); + } + else if (ct == "BlockingAnnotation") { + auto* n = static_cast(node); + if (props.contains("kind")) n->kind = props["kind"].get(); + } + else if (ct == "ParallelAnnotation") { + auto* n = static_cast(node); + if (props.contains("kind")) n->kind = props["kind"].get(); + } + else if (ct == "TrapAnnotation") { + auto* n = static_cast(node); + if (props.contains("signal")) n->signal = props["signal"].get(); + } + else if (ct == "ExceptionAnnotation") { + auto* n = static_cast(node); + if (props.contains("style")) n->style = props["style"].get(); + } + else if (ct == "PanicAnnotation") { + auto* n = static_cast(node); + if (props.contains("behavior")) n->behavior = props["behavior"].get(); + } + // Scope & Namespace (Step 276) + else if (ct == "BindingAnnotation") { + auto* n = static_cast(node); + if (props.contains("time")) n->time = props["time"].get(); + } + else if (ct == "LookupAnnotation") { + auto* n = static_cast(node); + if (props.contains("mode")) n->mode = props["mode"].get(); + } + else if (ct == "CaptureAnnotation") { + auto* n = static_cast(node); + if (props.contains("strategy")) n->strategy = props["strategy"].get(); + } + else if (ct == "VisibilityAnnotation") { + auto* n = static_cast(node); + if (props.contains("level")) n->level = props["level"].get(); + } + else if (ct == "NamespaceAnnotation") { + auto* n = static_cast(node); + if (props.contains("style")) n->style = props["style"].get(); + } + else if (ct == "ScopeAnnotation") { + auto* n = static_cast(node); + if (props.contains("kind")) n->kind = props["kind"].get(); + } } inline std::string generateNodeId() { diff --git a/editor/tests/step272_test.cpp b/editor/tests/step272_test.cpp new file mode 100644 index 0000000..41780e5 --- /dev/null +++ b/editor/tests/step272_test.cpp @@ -0,0 +1,201 @@ +// Step 272: Type System Annotations — Layout & Constraints (12 tests) +// Tests: BitWidthAnnotation, EndianAnnotation, LayoutAnnotation, +// NullabilityAnnotation, VarianceAnnotation +// + JSON roundtrip + compact AST integration + +#include +#include +#include +#include "ast/ASTNode.h" +#include "ast/Module.h" +#include "ast/Function.h" +#include "ast/Annotation.h" +#include "ast/Serialization.h" +#include "ASTUtils.h" +#include "CompactAST.h" + +static int passed = 0; +static int failed = 0; + +static void check(bool cond, const std::string& name) { + if (cond) { std::cout << " PASS: " << name << "\n"; ++passed; } + else { std::cout << " FAIL: " << name << "\n"; ++failed; } +} + +// --- Test 1: BitWidthAnnotation creation and fields --- +static void test_bitwidth_annotation() { + BitWidthAnnotation bw; + check(bw.conceptType == "BitWidthAnnotation", "conceptType is BitWidthAnnotation"); + bw.width = 32; + check(bw.width == 32, "width field set to 32"); +} + +// --- Test 2: EndianAnnotation creation and fields --- +static void test_endian_annotation() { + EndianAnnotation ea; + check(ea.conceptType == "EndianAnnotation", "conceptType is EndianAnnotation"); + ea.order = "big"; + check(ea.order == "big", "order field set to big"); +} + +// --- Test 3: LayoutAnnotation creation and fields --- +static void test_layout_annotation() { + LayoutAnnotation la; + check(la.conceptType == "LayoutAnnotation", "conceptType is LayoutAnnotation"); + la.mode = "packed"; + la.alignment = 8; + check(la.mode == "packed", "mode field set to packed"); + check(la.alignment == 8, "alignment field set to 8"); +} + +// --- Test 4: NullabilityAnnotation creation and fields --- +static void test_nullability_annotation() { + NullabilityAnnotation na; + check(na.conceptType == "NullabilityAnnotation", "conceptType is NullabilityAnnotation"); + na.nullable = true; + na.strategy = "strict"; + check(na.nullable == true, "nullable field set to true"); + check(na.strategy == "strict", "strategy field set to strict"); +} + +// --- Test 5: VarianceAnnotation creation and fields --- +static void test_variance_annotation() { + VarianceAnnotation va; + check(va.conceptType == "VarianceAnnotation", "conceptType is VarianceAnnotation"); + va.variance = "covariant"; + check(va.variance == "covariant", "variance field set to covariant"); +} + +// --- Test 6: BitWidthAnnotation JSON roundtrip --- +static void test_bitwidth_json_roundtrip() { + auto* bw = new BitWidthAnnotation(); + bw->id = "bw1"; + bw->width = 64; + json j = toJson(bw); + check(j["concept"] == "BitWidthAnnotation", "JSON concept correct"); + check(j["properties"]["width"] == 64, "JSON width correct"); + ASTNode* restored = fromJson(j); + auto* rbw = dynamic_cast(restored); + check(rbw != nullptr, "fromJson creates BitWidthAnnotation"); + check(rbw->width == 64, "roundtrip width preserved"); + delete bw; + delete restored; +} + +// --- Test 7: LayoutAnnotation JSON roundtrip --- +static void test_layout_json_roundtrip() { + auto* la = new LayoutAnnotation(); + la->id = "la1"; + la->mode = "aligned"; + la->alignment = 16; + json j = toJson(la); + ASTNode* restored = fromJson(j); + auto* rla = dynamic_cast(restored); + check(rla != nullptr, "fromJson creates LayoutAnnotation"); + check(rla->mode == "aligned", "roundtrip mode preserved"); + check(rla->alignment == 16, "roundtrip alignment preserved"); + delete la; + delete restored; +} + +// --- Test 8: NullabilityAnnotation JSON roundtrip --- +static void test_nullability_json_roundtrip() { + auto* na = new NullabilityAnnotation(); + na->id = "na1"; + na->nullable = true; + na->strategy = "nullable"; + json j = toJson(na); + check(j["properties"]["nullable"] == true, "JSON nullable correct"); + ASTNode* restored = fromJson(j); + auto* rna = dynamic_cast(restored); + check(rna != nullptr, "fromJson creates NullabilityAnnotation"); + check(rna->nullable == true, "roundtrip nullable preserved"); + check(rna->strategy == "nullable", "roundtrip strategy preserved"); + delete na; + delete restored; +} + +// --- Test 9: All 5 types survive createNode factory --- +static void test_create_node_factory() { + std::vector types = { + "BitWidthAnnotation", "EndianAnnotation", "LayoutAnnotation", + "NullabilityAnnotation", "VarianceAnnotation" + }; + for (const auto& t : types) { + ASTNode* node = createNode(t); + check(node != nullptr && node->conceptType == t, + "createNode(" + t + ") works"); + delete node; + } +} + +// --- Test 10: Compact AST shows bitWidth in semantic summary --- +static void test_compact_ast_bitwidth() { + auto* func = new Function(); + func->id = "f1"; + func->name = "getInt"; + auto* bw = new BitWidthAnnotation(); + bw->width = 32; + func->addChild("annotations", bw); + json sem = extractSemanticSummary(func); + check(!sem.empty(), "semantic summary not empty"); + check(sem.contains("bitWidth"), "bitWidth in semantic summary"); + check(sem["bitWidth"] == 32, "bitWidth value correct"); + delete func; +} + +// --- Test 11: Compact AST shows layout in semantic summary --- +static void test_compact_ast_layout() { + auto* func = new Function(); + func->id = "f2"; + func->name = "pack"; + auto* la = new LayoutAnnotation(); + la->mode = "packed"; + la->alignment = 4; + func->addChild("annotations", la); + json sem = extractSemanticSummary(func); + check(sem.contains("layout"), "layout in semantic summary"); + check(sem["layout"]["mode"] == "packed", "layout mode correct"); + check(sem["layout"]["alignment"] == 4, "layout alignment correct"); + delete func; +} + +// --- Test 12: Multiple type annotations on one node --- +static void test_multiple_type_annotations() { + auto* func = new Function(); + func->id = "f3"; + func->name = "convert"; + auto* bw = new BitWidthAnnotation(); + bw->width = 16; + func->addChild("annotations", bw); + auto* ea = new EndianAnnotation(); + ea->order = "little"; + func->addChild("annotations", ea); + auto* va = new VarianceAnnotation(); + va->variance = "invariant"; + func->addChild("annotations", va); + json sem = extractSemanticSummary(func); + check(sem["bitWidth"] == 16, "bitWidth present in multi-annotation"); + check(sem["endian"] == "little", "endian present in multi-annotation"); + check(sem["variance"] == "invariant", "variance present in multi-annotation"); + delete func; +} + +int main() { + std::cout << "=== Step 272: Type System Annotations — Layout & Constraints ===\n"; + test_bitwidth_annotation(); + test_endian_annotation(); + test_layout_annotation(); + test_nullability_annotation(); + test_variance_annotation(); + test_bitwidth_json_roundtrip(); + test_layout_json_roundtrip(); + test_nullability_json_roundtrip(); + test_create_node_factory(); + test_compact_ast_bitwidth(); + test_compact_ast_layout(); + test_multiple_type_annotations(); + std::cout << "\nResults: " << passed << " passed, " << failed << " failed out of " + << (passed + failed) << "\n"; + return failed > 0 ? 1 : 0; +} diff --git a/editor/tests/step273_test.cpp b/editor/tests/step273_test.cpp new file mode 100644 index 0000000..c174eb0 --- /dev/null +++ b/editor/tests/step273_test.cpp @@ -0,0 +1,205 @@ +// Step 273: Type System Annotations — Identity & Mutability (12 tests) +// Tests: IdentityAnnotation, MutAnnotation, TypeStateAnnotation +// + JSON roundtrip + compact AST + all 8 type annotation types together + +#include +#include +#include +#include "ast/ASTNode.h" +#include "ast/Module.h" +#include "ast/Function.h" +#include "ast/Annotation.h" +#include "ast/Serialization.h" +#include "ASTUtils.h" +#include "CompactAST.h" + +static int passed = 0; +static int failed = 0; + +static void check(bool cond, const std::string& name) { + if (cond) { std::cout << " PASS: " << name << "\n"; ++passed; } + else { std::cout << " FAIL: " << name << "\n"; ++failed; } +} + +// --- Test 1: IdentityAnnotation creation --- +static void test_identity_annotation() { + IdentityAnnotation ia; + check(ia.conceptType == "IdentityAnnotation", "conceptType is IdentityAnnotation"); + ia.mode = "nominal"; + check(ia.mode == "nominal", "mode field set to nominal"); +} + +// --- Test 2: MutAnnotation creation --- +static void test_mut_annotation() { + MutAnnotation ma; + check(ma.conceptType == "MutAnnotation", "conceptType is MutAnnotation"); + ma.depth = "deep"; + check(ma.depth == "deep", "depth field set to deep"); +} + +// --- Test 3: TypeStateAnnotation creation --- +static void test_typestate_annotation() { + TypeStateAnnotation ts; + check(ts.conceptType == "TypeStateAnnotation", "conceptType is TypeStateAnnotation"); + ts.state = "reified"; + check(ts.state == "reified", "state field set to reified"); +} + +// --- Test 4: IdentityAnnotation JSON roundtrip --- +static void test_identity_json_roundtrip() { + auto* ia = new IdentityAnnotation(); + ia->id = "id1"; + ia->mode = "structural"; + json j = toJson(ia); + check(j["properties"]["mode"] == "structural", "JSON mode correct"); + ASTNode* restored = fromJson(j); + auto* ria = dynamic_cast(restored); + check(ria != nullptr, "fromJson creates IdentityAnnotation"); + check(ria->mode == "structural", "roundtrip mode preserved"); + delete ia; + delete restored; +} + +// --- Test 5: MutAnnotation JSON roundtrip --- +static void test_mut_json_roundtrip() { + auto* ma = new MutAnnotation(); + ma->id = "mut1"; + ma->depth = "interior"; + json j = toJson(ma); + ASTNode* restored = fromJson(j); + auto* rma = dynamic_cast(restored); + check(rma != nullptr, "fromJson creates MutAnnotation"); + check(rma->depth == "interior", "roundtrip depth preserved"); + delete ma; + delete restored; +} + +// --- Test 6: TypeStateAnnotation JSON roundtrip --- +static void test_typestate_json_roundtrip() { + auto* ts = new TypeStateAnnotation(); + ts->id = "ts1"; + ts->state = "erased"; + json j = toJson(ts); + ASTNode* restored = fromJson(j); + auto* rts = dynamic_cast(restored); + check(rts != nullptr, "fromJson creates TypeStateAnnotation"); + check(rts->state == "erased", "roundtrip state preserved"); + delete ts; + delete restored; +} + +// --- Test 7: createNode factory for Step 273 types --- +static void test_create_node_factory() { + std::vector types = { + "IdentityAnnotation", "MutAnnotation", "TypeStateAnnotation" + }; + for (const auto& t : types) { + ASTNode* node = createNode(t); + check(node != nullptr && node->conceptType == t, + "createNode(" + t + ") works"); + delete node; + } +} + +// --- Test 8: Compact AST shows identity in semantic summary --- +static void test_compact_ast_identity() { + auto* func = new Function(); + func->id = "f1"; + func->name = "compare"; + auto* ia = new IdentityAnnotation(); + ia->mode = "nominal"; + func->addChild("annotations", ia); + json sem = extractSemanticSummary(func); + check(sem.contains("identity"), "identity in semantic summary"); + check(sem["identity"] == "nominal", "identity value correct"); + delete func; +} + +// --- Test 9: Compact AST shows mutability in semantic summary --- +static void test_compact_ast_mutability() { + auto* func = new Function(); + func->id = "f2"; + func->name = "freeze"; + auto* ma = new MutAnnotation(); + ma->depth = "deep"; + func->addChild("annotations", ma); + json sem = extractSemanticSummary(func); + check(sem.contains("mutability"), "mutability in semantic summary"); + check(sem["mutability"] == "deep", "mutability value correct"); + delete func; +} + +// --- Test 10: Compact AST shows typeState in semantic summary --- +static void test_compact_ast_typestate() { + auto* func = new Function(); + func->id = "f3"; + func->name = "reflect"; + auto* ts = new TypeStateAnnotation(); + ts->state = "reified"; + func->addChild("annotations", ts); + json sem = extractSemanticSummary(func); + check(sem.contains("typeState"), "typeState in semantic summary"); + check(sem["typeState"] == "reified", "typeState value correct"); + delete func; +} + +// --- Test 11: All 8 Subject 2 type annotations on one function --- +static void test_all_subject2_annotations() { + auto* func = new Function(); + func->id = "f4"; + func->name = "fullType"; + auto* bw = new BitWidthAnnotation(); bw->width = 32; + auto* ea = new EndianAnnotation(); ea->order = "little"; + auto* la = new LayoutAnnotation(); la->mode = "aligned"; la->alignment = 8; + auto* na = new NullabilityAnnotation(); na->nullable = false; na->strategy = "strict"; + auto* va = new VarianceAnnotation(); va->variance = "covariant"; + auto* id = new IdentityAnnotation(); id->mode = "nominal"; + auto* mu = new MutAnnotation(); mu->depth = "shallow"; + auto* ts = new TypeStateAnnotation(); ts->state = "erased"; + func->addChild("annotations", bw); + func->addChild("annotations", ea); + func->addChild("annotations", la); + func->addChild("annotations", na); + func->addChild("annotations", va); + func->addChild("annotations", id); + func->addChild("annotations", mu); + func->addChild("annotations", ts); + json sem = extractSemanticSummary(func); + check(sem.contains("bitWidth") && sem.contains("endian") && + sem.contains("layout") && sem.contains("nullability") && + sem.contains("variance") && sem.contains("identity") && + sem.contains("mutability") && sem.contains("typeState"), + "all 8 type system annotations in semantic summary"); + delete func; +} + +// --- Test 12: MutAnnotation drives const qualification hint --- +static void test_mut_const_qualification() { + // MutAnnotation("deep") → implies deeply immutable + MutAnnotation ma; + ma.depth = "deep"; + check(ma.depth == "deep", "deep mutability implies deeply immutable"); + // MutAnnotation("shallow") → only top-level const + MutAnnotation ma2; + ma2.depth = "shallow"; + check(ma2.depth == "shallow", "shallow mutability implies top-level const"); +} + +int main() { + std::cout << "=== Step 273: Type System Annotations — Identity & Mutability ===\n"; + test_identity_annotation(); + test_mut_annotation(); + test_typestate_annotation(); + test_identity_json_roundtrip(); + test_mut_json_roundtrip(); + test_typestate_json_roundtrip(); + test_create_node_factory(); + test_compact_ast_identity(); + test_compact_ast_mutability(); + test_compact_ast_typestate(); + test_all_subject2_annotations(); + test_mut_const_qualification(); + std::cout << "\nResults: " << passed << " passed, " << failed << " failed out of " + << (passed + failed) << "\n"; + return failed > 0 ? 1 : 0; +} diff --git a/editor/tests/step274_test.cpp b/editor/tests/step274_test.cpp new file mode 100644 index 0000000..11f8834 --- /dev/null +++ b/editor/tests/step274_test.cpp @@ -0,0 +1,188 @@ +// Step 274: Concurrency Annotations — Primitives & Memory Model (12 tests) +// Tests: AtomicAnnotation, SyncAnnotation, ThreadModelAnnotation, +// MemoryBarrierAnnotation + JSON roundtrip + compact AST + +#include +#include +#include +#include "ast/ASTNode.h" +#include "ast/Module.h" +#include "ast/Function.h" +#include "ast/Annotation.h" +#include "ast/Serialization.h" +#include "ASTUtils.h" +#include "CompactAST.h" + +static int passed = 0; +static int failed = 0; + +static void check(bool cond, const std::string& name) { + if (cond) { std::cout << " PASS: " << name << "\n"; ++passed; } + else { std::cout << " FAIL: " << name << "\n"; ++failed; } +} + +// --- Test 1: AtomicAnnotation creation --- +static void test_atomic_annotation() { + AtomicAnnotation aa; + check(aa.conceptType == "AtomicAnnotation", "conceptType is AtomicAnnotation"); + aa.consistency = "seq_cst"; + check(aa.consistency == "seq_cst", "consistency field set to seq_cst"); +} + +// --- Test 2: SyncAnnotation creation --- +static void test_sync_annotation() { + SyncAnnotation sa; + check(sa.conceptType == "SyncAnnotation", "conceptType is SyncAnnotation"); + sa.primitive = "monitor"; + check(sa.primitive == "monitor", "primitive field set to monitor"); +} + +// --- Test 3: ThreadModelAnnotation creation --- +static void test_threadmodel_annotation() { + ThreadModelAnnotation tm; + check(tm.conceptType == "ThreadModelAnnotation", "conceptType is ThreadModelAnnotation"); + tm.model = "green"; + check(tm.model == "green", "model field set to green"); +} + +// --- Test 4: MemoryBarrierAnnotation creation (marker, no fields) --- +static void test_memorybarrier_annotation() { + MemoryBarrierAnnotation mb; + check(mb.conceptType == "MemoryBarrierAnnotation", "conceptType is MemoryBarrierAnnotation"); +} + +// --- Test 5: AtomicAnnotation JSON roundtrip --- +static void test_atomic_json_roundtrip() { + auto* aa = new AtomicAnnotation(); + aa->id = "a1"; + aa->consistency = "relaxed"; + json j = toJson(aa); + check(j["properties"]["consistency"] == "relaxed", "JSON consistency correct"); + ASTNode* restored = fromJson(j); + auto* raa = dynamic_cast(restored); + check(raa != nullptr, "fromJson creates AtomicAnnotation"); + check(raa->consistency == "relaxed", "roundtrip consistency preserved"); + delete aa; + delete restored; +} + +// --- Test 6: SyncAnnotation JSON roundtrip --- +static void test_sync_json_roundtrip() { + auto* sa = new SyncAnnotation(); + sa->id = "s1"; + sa->primitive = "semaphore"; + json j = toJson(sa); + ASTNode* restored = fromJson(j); + auto* rsa = dynamic_cast(restored); + check(rsa != nullptr, "fromJson creates SyncAnnotation"); + check(rsa->primitive == "semaphore", "roundtrip primitive preserved"); + delete sa; + delete restored; +} + +// --- Test 7: ThreadModelAnnotation JSON roundtrip --- +static void test_threadmodel_json_roundtrip() { + auto* tm = new ThreadModelAnnotation(); + tm->id = "tm1"; + tm->model = "fiber"; + json j = toJson(tm); + ASTNode* restored = fromJson(j); + auto* rtm = dynamic_cast(restored); + check(rtm != nullptr, "fromJson creates ThreadModelAnnotation"); + check(rtm->model == "fiber", "roundtrip model preserved"); + delete tm; + delete restored; +} + +// --- Test 8: MemoryBarrierAnnotation JSON roundtrip --- +static void test_memorybarrier_json_roundtrip() { + auto* mb = new MemoryBarrierAnnotation(); + mb->id = "mb1"; + json j = toJson(mb); + check(j["concept"] == "MemoryBarrierAnnotation", "JSON concept correct"); + ASTNode* restored = fromJson(j); + auto* rmb = dynamic_cast(restored); + check(rmb != nullptr, "fromJson creates MemoryBarrierAnnotation"); + delete mb; + delete restored; +} + +// --- Test 9: createNode factory for Step 274 types --- +static void test_create_node_factory() { + std::vector types = { + "AtomicAnnotation", "SyncAnnotation", + "ThreadModelAnnotation", "MemoryBarrierAnnotation" + }; + for (const auto& t : types) { + ASTNode* node = createNode(t); + check(node != nullptr && node->conceptType == t, + "createNode(" + t + ") works"); + delete node; + } +} + +// --- Test 10: Compact AST shows atomic in semantic summary --- +static void test_compact_ast_atomic() { + auto* func = new Function(); + func->id = "f1"; + func->name = "incrementCounter"; + auto* aa = new AtomicAnnotation(); + aa->consistency = "seq_cst"; + func->addChild("annotations", aa); + json sem = extractSemanticSummary(func); + check(sem.contains("atomic"), "atomic in semantic summary"); + check(sem["atomic"] == "seq_cst", "atomic value correct"); + delete func; +} + +// --- Test 11: Compact AST shows memoryBarrier marker --- +static void test_compact_ast_memorybarrier() { + auto* func = new Function(); + func->id = "f2"; + func->name = "fence"; + auto* mb = new MemoryBarrierAnnotation(); + func->addChild("annotations", mb); + json sem = extractSemanticSummary(func); + check(sem.contains("memoryBarrier"), "memoryBarrier in semantic summary"); + check(sem["memoryBarrier"] == true, "memoryBarrier is true"); + delete func; +} + +// --- Test 12: All 4 concurrency annotations on one function --- +static void test_all_concurrency_annotations() { + auto* func = new Function(); + func->id = "f3"; + func->name = "concurrentOp"; + auto* aa = new AtomicAnnotation(); aa->consistency = "acquire"; + auto* sa = new SyncAnnotation(); sa->primitive = "spin"; + auto* tm = new ThreadModelAnnotation(); tm->model = "os"; + auto* mb = new MemoryBarrierAnnotation(); + func->addChild("annotations", aa); + func->addChild("annotations", sa); + func->addChild("annotations", tm); + func->addChild("annotations", mb); + json sem = extractSemanticSummary(func); + check(sem.contains("atomic") && sem.contains("sync") && + sem.contains("threadModel") && sem.contains("memoryBarrier"), + "all 4 concurrency annotations in semantic summary"); + delete func; +} + +int main() { + std::cout << "=== Step 274: Concurrency Annotations — Primitives & Memory Model ===\n"; + test_atomic_annotation(); + test_sync_annotation(); + test_threadmodel_annotation(); + test_memorybarrier_annotation(); + test_atomic_json_roundtrip(); + test_sync_json_roundtrip(); + test_threadmodel_json_roundtrip(); + test_memorybarrier_json_roundtrip(); + test_create_node_factory(); + test_compact_ast_atomic(); + test_compact_ast_memorybarrier(); + test_all_concurrency_annotations(); + std::cout << "\nResults: " << passed << " passed, " << failed << " failed out of " + << (passed + failed) << "\n"; + return failed > 0 ? 1 : 0; +} diff --git a/editor/tests/step275_test.cpp b/editor/tests/step275_test.cpp new file mode 100644 index 0000000..86b348e --- /dev/null +++ b/editor/tests/step275_test.cpp @@ -0,0 +1,221 @@ +// Step 275: Async, Parallelism & Error Handling Annotations (12 tests) +// Tests: ExecAnnotation, BlockingAnnotation, ParallelAnnotation, +// TrapAnnotation, ExceptionAnnotation, PanicAnnotation +// + JSON roundtrip + compact AST + +#include +#include +#include +#include "ast/ASTNode.h" +#include "ast/Module.h" +#include "ast/Function.h" +#include "ast/Annotation.h" +#include "ast/Serialization.h" +#include "ASTUtils.h" +#include "CompactAST.h" + +static int passed = 0; +static int failed = 0; + +static void check(bool cond, const std::string& name) { + if (cond) { std::cout << " PASS: " << name << "\n"; ++passed; } + else { std::cout << " FAIL: " << name << "\n"; ++failed; } +} + +// --- Test 1: ExecAnnotation creation --- +static void test_exec_annotation() { + ExecAnnotation ea; + check(ea.conceptType == "ExecAnnotation", "conceptType is ExecAnnotation"); + ea.mode = "async"; + ea.runtimeHint = "tokio"; + check(ea.mode == "async", "mode field set to async"); + check(ea.runtimeHint == "tokio", "runtimeHint field set to tokio"); +} + +// --- Test 2: BlockingAnnotation creation --- +static void test_blocking_annotation() { + BlockingAnnotation ba; + check(ba.conceptType == "BlockingAnnotation", "conceptType is BlockingAnnotation"); + ba.kind = "io"; + check(ba.kind == "io", "kind field set to io"); +} + +// --- Test 3: ParallelAnnotation creation --- +static void test_parallel_annotation() { + ParallelAnnotation pa; + check(pa.conceptType == "ParallelAnnotation", "conceptType is ParallelAnnotation"); + pa.kind = "data"; + check(pa.kind == "data", "kind field set to data"); +} + +// --- Test 4: TrapAnnotation, ExceptionAnnotation, PanicAnnotation --- +static void test_error_annotations() { + TrapAnnotation ta; + check(ta.conceptType == "TrapAnnotation", "TrapAnnotation conceptType"); + ta.signal = "SIGSEGV"; + check(ta.signal == "SIGSEGV", "signal set to SIGSEGV"); + + ExceptionAnnotation ea; + check(ea.conceptType == "ExceptionAnnotation", "ExceptionAnnotation conceptType"); + ea.style = "checked"; + check(ea.style == "checked", "style set to checked"); + + PanicAnnotation pa; + check(pa.conceptType == "PanicAnnotation", "PanicAnnotation conceptType"); + pa.behavior = "unwind"; + check(pa.behavior == "unwind", "behavior set to unwind"); +} + +// --- Test 5: ExecAnnotation JSON roundtrip --- +static void test_exec_json_roundtrip() { + auto* ea = new ExecAnnotation(); + ea->id = "e1"; + ea->mode = "event"; + ea->runtimeHint = "libuv"; + json j = toJson(ea); + check(j["properties"]["mode"] == "event", "JSON mode correct"); + check(j["properties"]["runtimeHint"] == "libuv", "JSON runtimeHint correct"); + ASTNode* restored = fromJson(j); + auto* rea = dynamic_cast(restored); + check(rea != nullptr, "fromJson creates ExecAnnotation"); + check(rea->mode == "event" && rea->runtimeHint == "libuv", + "roundtrip fields preserved"); + delete ea; + delete restored; +} + +// --- Test 6: PanicAnnotation JSON roundtrip --- +static void test_panic_json_roundtrip() { + auto* pa = new PanicAnnotation(); + pa->id = "p1"; + pa->behavior = "abort"; + json j = toJson(pa); + ASTNode* restored = fromJson(j); + auto* rpa = dynamic_cast(restored); + check(rpa != nullptr, "fromJson creates PanicAnnotation"); + check(rpa->behavior == "abort", "roundtrip behavior preserved"); + delete pa; + delete restored; +} + +// --- Test 7: createNode factory for Step 275 types --- +static void test_create_node_factory() { + std::vector types = { + "ExecAnnotation", "BlockingAnnotation", "ParallelAnnotation", + "TrapAnnotation", "ExceptionAnnotation", "PanicAnnotation" + }; + for (const auto& t : types) { + ASTNode* node = createNode(t); + check(node != nullptr && node->conceptType == t, + "createNode(" + t + ") works"); + delete node; + } +} + +// --- Test 8: Compact AST shows exec in semantic summary --- +static void test_compact_ast_exec() { + auto* func = new Function(); + func->id = "f1"; + func->name = "fetchData"; + auto* ea = new ExecAnnotation(); + ea->mode = "async"; + ea->runtimeHint = "tokio"; + func->addChild("annotations", ea); + json sem = extractSemanticSummary(func); + check(sem.contains("exec"), "exec in semantic summary"); + check(sem["exec"]["mode"] == "async", "exec mode correct"); + check(sem["exec"]["runtime"] == "tokio", "exec runtime correct"); + delete func; +} + +// --- Test 9: Compact AST shows parallel and blocking --- +static void test_compact_ast_parallel_blocking() { + auto* func = new Function(); + func->id = "f2"; + func->name = "processArray"; + auto* pa = new ParallelAnnotation(); pa->kind = "data"; + auto* ba = new BlockingAnnotation(); ba->kind = "compute"; + func->addChild("annotations", pa); + func->addChild("annotations", ba); + json sem = extractSemanticSummary(func); + check(sem["parallel"] == "data", "parallel in semantic summary"); + check(sem["blocking"] == "compute", "blocking in semantic summary"); + delete func; +} + +// --- Test 10: Compact AST shows error handling annotations --- +static void test_compact_ast_error_handling() { + auto* func = new Function(); + func->id = "f3"; + func->name = "riskyOp"; + auto* ta = new TrapAnnotation(); ta->signal = "SIGFPE"; + auto* ea = new ExceptionAnnotation(); ea->style = "unchecked"; + auto* pa = new PanicAnnotation(); pa->behavior = "unwind"; + func->addChild("annotations", ta); + func->addChild("annotations", ea); + func->addChild("annotations", pa); + json sem = extractSemanticSummary(func); + check(sem["trap"] == "SIGFPE", "trap in semantic summary"); + check(sem["exception"] == "unchecked", "exception in semantic summary"); + check(sem["panic"] == "unwind", "panic in semantic summary"); + delete func; +} + +// --- Test 11: All 6 async/error annotations on one function --- +static void test_all_async_error_annotations() { + auto* func = new Function(); + func->id = "f4"; + func->name = "fullAsync"; + func->addChild("annotations", [&]{ auto* a = new ExecAnnotation(); a->mode = "async"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new BlockingAnnotation(); a->kind = "io"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new ParallelAnnotation(); a->kind = "task"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new TrapAnnotation(); a->signal = "SIGSEGV"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new ExceptionAnnotation(); a->style = "checked"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new PanicAnnotation(); a->behavior = "abort"; return a; }()); + json sem = extractSemanticSummary(func); + check(sem.contains("exec") && sem.contains("blocking") && + sem.contains("parallel") && sem.contains("trap") && + sem.contains("exception") && sem.contains("panic"), + "all 6 async/error annotations in semantic summary"); + delete func; +} + +// --- Test 12: TrapAnnotation and ExceptionAnnotation JSON roundtrip --- +static void test_trap_exception_roundtrip() { + auto* ta = new TrapAnnotation(); + ta->id = "t1"; + ta->signal = "SIGABRT"; + json jt = toJson(ta); + ASTNode* rt = fromJson(jt); + auto* rta = dynamic_cast(rt); + check(rta != nullptr && rta->signal == "SIGABRT", "TrapAnnotation roundtrip"); + + auto* ea = new ExceptionAnnotation(); + ea->id = "ex1"; + ea->style = "checked"; + json je = toJson(ea); + ASTNode* re = fromJson(je); + auto* rea = dynamic_cast(re); + check(rea != nullptr && rea->style == "checked", "ExceptionAnnotation roundtrip"); + + delete ta; delete rt; delete ea; delete re; +} + +int main() { + std::cout << "=== Step 275: Async, Parallelism & Error Handling Annotations ===\n"; + test_exec_annotation(); + test_blocking_annotation(); + test_parallel_annotation(); + test_error_annotations(); + test_exec_json_roundtrip(); + test_panic_json_roundtrip(); + test_create_node_factory(); + test_compact_ast_exec(); + test_compact_ast_parallel_blocking(); + test_compact_ast_error_handling(); + test_all_async_error_annotations(); + test_trap_exception_roundtrip(); + std::cout << "\nResults: " << passed << " passed, " << failed << " failed out of " + << (passed + failed) << "\n"; + return failed > 0 ? 1 : 0; +} diff --git a/editor/tests/step276_test.cpp b/editor/tests/step276_test.cpp new file mode 100644 index 0000000..7d724a2 --- /dev/null +++ b/editor/tests/step276_test.cpp @@ -0,0 +1,211 @@ +// Step 276: Scope & Namespace Annotations (12 tests) +// Tests: BindingAnnotation, LookupAnnotation, CaptureAnnotation, +// VisibilityAnnotation, NamespaceAnnotation, ScopeAnnotation +// + JSON roundtrip + compact AST + +#include +#include +#include +#include "ast/ASTNode.h" +#include "ast/Module.h" +#include "ast/Function.h" +#include "ast/Annotation.h" +#include "ast/Serialization.h" +#include "ASTUtils.h" +#include "CompactAST.h" + +static int passed = 0; +static int failed = 0; + +static void check(bool cond, const std::string& name) { + if (cond) { std::cout << " PASS: " << name << "\n"; ++passed; } + else { std::cout << " FAIL: " << name << "\n"; ++failed; } +} + +// --- Test 1: BindingAnnotation creation --- +static void test_binding_annotation() { + BindingAnnotation ba; + check(ba.conceptType == "BindingAnnotation", "conceptType is BindingAnnotation"); + ba.time = "static"; + check(ba.time == "static", "time field set to static"); +} + +// --- Test 2: LookupAnnotation creation --- +static void test_lookup_annotation() { + LookupAnnotation la; + check(la.conceptType == "LookupAnnotation", "conceptType is LookupAnnotation"); + la.mode = "lexical"; + check(la.mode == "lexical", "mode field set to lexical"); +} + +// --- Test 3: CaptureAnnotation creation --- +static void test_capture_annotation() { + CaptureAnnotation ca; + check(ca.conceptType == "CaptureAnnotation", "conceptType is CaptureAnnotation"); + ca.strategy = "move"; + check(ca.strategy == "move", "strategy field set to move"); +} + +// --- Test 4: VisibilityAnnotation, NamespaceAnnotation, ScopeAnnotation --- +static void test_visibility_namespace_scope() { + VisibilityAnnotation va; + check(va.conceptType == "VisibilityAnnotation", "VisibilityAnnotation conceptType"); + va.level = "friend"; + check(va.level == "friend", "level set to friend"); + + NamespaceAnnotation na; + check(na.conceptType == "NamespaceAnnotation", "NamespaceAnnotation conceptType"); + na.style = "qualified"; + check(na.style == "qualified", "style set to qualified"); + + ScopeAnnotation sa; + check(sa.conceptType == "ScopeAnnotation", "ScopeAnnotation conceptType"); + sa.kind = "singleton"; + check(sa.kind == "singleton", "kind set to singleton"); +} + +// --- Test 5: CaptureAnnotation JSON roundtrip --- +static void test_capture_json_roundtrip() { + auto* ca = new CaptureAnnotation(); + ca->id = "c1"; + ca->strategy = "ref"; + json j = toJson(ca); + check(j["properties"]["strategy"] == "ref", "JSON strategy correct"); + ASTNode* restored = fromJson(j); + auto* rca = dynamic_cast(restored); + check(rca != nullptr, "fromJson creates CaptureAnnotation"); + check(rca->strategy == "ref", "roundtrip strategy preserved"); + delete ca; + delete restored; +} + +// --- Test 6: VisibilityAnnotation JSON roundtrip --- +static void test_visibility_json_roundtrip() { + auto* va = new VisibilityAnnotation(); + va->id = "v1"; + va->level = "internal"; + json j = toJson(va); + ASTNode* restored = fromJson(j); + auto* rva = dynamic_cast(restored); + check(rva != nullptr, "fromJson creates VisibilityAnnotation"); + check(rva->level == "internal", "roundtrip level preserved"); + delete va; + delete restored; +} + +// --- Test 7: ScopeAnnotation JSON roundtrip --- +static void test_scope_json_roundtrip() { + auto* sa = new ScopeAnnotation(); + sa->id = "s1"; + sa->kind = "global_leaked"; + json j = toJson(sa); + ASTNode* restored = fromJson(j); + auto* rsa = dynamic_cast(restored); + check(rsa != nullptr, "fromJson creates ScopeAnnotation"); + check(rsa->kind == "global_leaked", "roundtrip kind preserved"); + delete sa; + delete restored; +} + +// --- Test 8: createNode factory for Step 276 types --- +static void test_create_node_factory() { + std::vector types = { + "BindingAnnotation", "LookupAnnotation", "CaptureAnnotation", + "VisibilityAnnotation", "NamespaceAnnotation", "ScopeAnnotation" + }; + for (const auto& t : types) { + ASTNode* node = createNode(t); + check(node != nullptr && node->conceptType == t, + "createNode(" + t + ") works"); + delete node; + } +} + +// --- Test 9: Compact AST shows binding and lookup --- +static void test_compact_ast_binding_lookup() { + auto* func = new Function(); + func->id = "f1"; + func->name = "resolve"; + auto* ba = new BindingAnnotation(); ba->time = "dynamic"; + auto* la = new LookupAnnotation(); la->mode = "hoisted"; + func->addChild("annotations", ba); + func->addChild("annotations", la); + json sem = extractSemanticSummary(func); + check(sem["binding"] == "dynamic", "binding in semantic summary"); + check(sem["lookup"] == "hoisted", "lookup in semantic summary"); + delete func; +} + +// --- Test 10: Compact AST shows capture and visibility --- +static void test_compact_ast_capture_visibility() { + auto* func = new Function(); + func->id = "f2"; + func->name = "closureFactory"; + auto* ca = new CaptureAnnotation(); ca->strategy = "value"; + auto* va = new VisibilityAnnotation(); va->level = "private"; + func->addChild("annotations", ca); + func->addChild("annotations", va); + json sem = extractSemanticSummary(func); + check(sem["capture"] == "value", "capture in semantic summary"); + check(sem["visibility"] == "private", "visibility in semantic summary"); + delete func; +} + +// --- Test 11: All 6 scope annotations on one function --- +static void test_all_scope_annotations() { + auto* func = new Function(); + func->id = "f3"; + func->name = "fullScope"; + func->addChild("annotations", [&]{ auto* a = new BindingAnnotation(); a->time = "static"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new LookupAnnotation(); a->mode = "lexical"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new CaptureAnnotation(); a->strategy = "move"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new VisibilityAnnotation(); a->level = "public"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new NamespaceAnnotation(); a->style = "flat"; return a; }()); + func->addChild("annotations", [&]{ auto* a = new ScopeAnnotation(); a->kind = "local"; return a; }()); + json sem = extractSemanticSummary(func); + check(sem.contains("binding") && sem.contains("lookup") && + sem.contains("capture") && sem.contains("visibility") && + sem.contains("namespace") && sem.contains("scope"), + "all 6 scope annotations in semantic summary"); + delete func; +} + +// --- Test 12: BindingAnnotation and NamespaceAnnotation JSON roundtrip --- +static void test_binding_namespace_roundtrip() { + auto* ba = new BindingAnnotation(); + ba->id = "b1"; + ba->time = "dynamic"; + json jb = toJson(ba); + ASTNode* rb = fromJson(jb); + auto* rba = dynamic_cast(rb); + check(rba != nullptr && rba->time == "dynamic", "BindingAnnotation roundtrip"); + + auto* na = new NamespaceAnnotation(); + na->id = "n1"; + na->style = "qualified"; + json jn = toJson(na); + ASTNode* rn = fromJson(jn); + auto* rna = dynamic_cast(rn); + check(rna != nullptr && rna->style == "qualified", "NamespaceAnnotation roundtrip"); + + delete ba; delete rb; delete na; delete rn; +} + +int main() { + std::cout << "=== Step 276: Scope & Namespace Annotations ===\n"; + test_binding_annotation(); + test_lookup_annotation(); + test_capture_annotation(); + test_visibility_namespace_scope(); + test_capture_json_roundtrip(); + test_visibility_json_roundtrip(); + test_scope_json_roundtrip(); + test_create_node_factory(); + test_compact_ast_binding_lookup(); + test_compact_ast_capture_visibility(); + test_all_scope_annotations(); + test_binding_namespace_roundtrip(); + std::cout << "\nResults: " << passed << " passed, " << failed << " failed out of " + << (passed + failed) << "\n"; + return failed > 0 ? 1 : 0; +} diff --git a/editor/tests/step277_test.cpp b/editor/tests/step277_test.cpp new file mode 100644 index 0000000..7e31a2b --- /dev/null +++ b/editor/tests/step277_test.cpp @@ -0,0 +1,324 @@ +// Step 277: Phase 10c Integration Tests (8 tests) +// Cross-subject annotation workflows: type + concurrency + scope on AST, +// compact AST, sidecar roundtrip, RPC set/get for new types. + +#include +#include +#include +#include +#include "ast/ASTNode.h" +#include "ast/Module.h" +#include "ast/Function.h" +#include "ast/Variable.h" +#include "ast/Parameter.h" +#include "ast/Statement.h" +#include "ast/Expression.h" +#include "ast/Annotation.h" +#include "ast/Serialization.h" +#include "ASTUtils.h" +#include "CompactAST.h" +#include "SidecarPersistence.h" +#include "HeadlessEditorState.h" +#include + +static int passed = 0; +static int failed = 0; + +static void check(bool cond, const std::string& name) { + if (cond) { std::cout << " PASS: " << name << "\n"; ++passed; } + else { std::cout << " FAIL: " << name << "\n"; ++failed; } +} + +// Helper: build a simple function AST +static Module* buildTestAST() { + auto* mod = new Module(); + mod->id = "mod1"; + mod->name = "test_module"; + + auto* fn = new Function(); + fn->id = "fn1"; + fn->name = "processData"; + mod->addChild("functions", fn); + + auto* fn2 = new Function(); + fn2->id = "fn2"; + fn2->name = "transformItem"; + mod->addChild("functions", fn2); + + return mod; +} + +// Helper: invoke RPC +static json rpc(HeadlessEditorState& state, const std::string& method, + const json& params = {}, const std::string& session = "s1") { + json req = {{"jsonrpc", "2.0"}, {"id", 1}, {"method", method}}; + if (!params.empty()) req["params"] = params; + return handleHeadlessAgentRequest(state, req, session); +} + +// --- Test 1: Type annotations drive compact AST output --- +static void test_type_annotations_compact_ast() { + auto* mod = buildTestAST(); + auto* fn = findNodeById(mod, "fn1"); + + // Add type annotations + auto* bw = new BitWidthAnnotation(); bw->width = 32; + auto* la = new LayoutAnnotation(); la->mode = "aligned"; la->alignment = 8; + auto* mu = new MutAnnotation(); mu->depth = "deep"; + fn->addChild("annotations", bw); + fn->addChild("annotations", la); + fn->addChild("annotations", mu); + + json compact = toJsonCompactSummary(mod); + // Find fn1 in compact summary + bool found = false; + for (const auto& node : compact) { + if (node.value("id", "") == "fn1" && node.contains("semantic")) { + auto& sem = node["semantic"]; + found = sem.contains("bitWidth") && sem.contains("layout") && + sem.contains("mutability"); + } + } + check(found, "type annotations appear in compact AST summary"); + delete mod; +} + +// --- Test 2: Concurrency annotations in compact AST --- +static void test_concurrency_annotations_compact_ast() { + auto* mod = buildTestAST(); + auto* fn = findNodeById(mod, "fn1"); + + auto* aa = new AtomicAnnotation(); aa->consistency = "seq_cst"; + auto* sa = new SyncAnnotation(); sa->primitive = "monitor"; + fn->addChild("annotations", aa); + fn->addChild("annotations", sa); + + json compact = toJsonCompactSummary(mod); + bool found = false; + for (const auto& node : compact) { + if (node.value("id", "") == "fn1" && node.contains("semantic")) { + auto& sem = node["semantic"]; + found = sem.contains("atomic") && sem.contains("sync"); + } + } + check(found, "concurrency annotations appear in compact AST summary"); + delete mod; +} + +// --- Test 3: Scope annotations in compact AST --- +static void test_scope_annotations_compact_ast() { + auto* mod = buildTestAST(); + auto* fn = findNodeById(mod, "fn2"); + + auto* ca = new CaptureAnnotation(); ca->strategy = "ref"; + auto* va = new VisibilityAnnotation(); va->level = "private"; + fn->addChild("annotations", ca); + fn->addChild("annotations", va); + + json compact = toJsonCompactSummary(mod); + bool found = false; + for (const auto& node : compact) { + if (node.value("id", "") == "fn2" && node.contains("semantic")) { + auto& sem = node["semantic"]; + found = sem.contains("capture") && sem.contains("visibility"); + } + } + check(found, "scope annotations appear in compact AST summary"); + delete mod; +} + +// --- Test 4: All Subject 2-4 annotations survive sidecar save/load --- +static void test_sidecar_roundtrip() { + namespace fs = std::filesystem; + std::string workspace = "/tmp/step277_test_ws"; + fs::create_directories(workspace); + + auto* mod = buildTestAST(); + auto* fn1 = findNodeById(mod, "fn1"); + auto* fn2 = findNodeById(mod, "fn2"); + + // Add one annotation from each subject + auto* bw = new BitWidthAnnotation(); bw->width = 64; + fn1->addChild("annotations", bw); + auto* aa = new AtomicAnnotation(); aa->consistency = "relaxed"; + fn1->addChild("annotations", aa); + auto* ba = new BindingAnnotation(); ba->time = "static"; + fn2->addChild("annotations", ba); + + auto saveResult = saveSidecarAST(workspace, "test.wh", mod); + check(saveResult.success, "sidecar save succeeds"); + check(saveResult.annotationCount == 3, "3 annotations saved"); + + // Build fresh AST and load + auto* mod2 = buildTestAST(); + auto loadResult = loadSidecarAST(workspace, "test.wh", mod2); + check(loadResult.success, "sidecar load succeeds"); + check(loadResult.mergedCount == 3, "3 annotations merged"); + + // Verify annotations on reloaded AST + auto* rfn1 = findNodeById(mod2, "fn1"); + auto annos1 = rfn1->getChildren("annotations"); + bool hasBitWidth = false, hasAtomic = false; + for (auto* a : annos1) { + if (a->conceptType == "BitWidthAnnotation") hasBitWidth = true; + if (a->conceptType == "AtomicAnnotation") hasAtomic = true; + } + check(hasBitWidth && hasAtomic, "type and concurrency annotations survive roundtrip"); + + delete mod; + delete mod2; + fs::remove_all(workspace); +} + +// --- Test 5: Mixed annotations on single function --- +static void test_mixed_annotations_single_function() { + auto* func = new Function(); + func->id = "f1"; + func->name = "mixedOp"; + + // Subject 2: type + auto* bw = new BitWidthAnnotation(); bw->width = 16; + auto* id = new IdentityAnnotation(); id->mode = "structural"; + // Subject 3: concurrency + auto* tm = new ThreadModelAnnotation(); tm->model = "green"; + auto* ea = new ExecAnnotation(); ea->mode = "async"; + // Subject 4: scope + auto* va = new VisibilityAnnotation(); va->level = "public"; + auto* ca = new CaptureAnnotation(); ca->strategy = "value"; + + func->addChild("annotations", bw); + func->addChild("annotations", id); + func->addChild("annotations", tm); + func->addChild("annotations", ea); + func->addChild("annotations", va); + func->addChild("annotations", ca); + + json sem = extractSemanticSummary(func); + check(sem.contains("bitWidth") && sem.contains("identity") && + sem.contains("threadModel") && sem.contains("exec") && + sem.contains("visibility") && sem.contains("capture"), + "mixed annotations from 3 subjects on single function"); + delete func; +} + +// --- Test 6: getSemanticAnnotations returns Subject 2-4 types via RPC --- +static void test_rpc_get_annotations() { + HeadlessEditorState state; + state.openBuffer("test.wh", "", "python"); + auto* mod = buildTestAST(); + state.activeBuffer->sync.setAST(std::unique_ptr(mod)); + state.setAgentRole("s1", AgentRole::Refactor); + + // Set type annotation via RPC + auto r1 = rpc(state, "setSemanticAnnotation", { + {"nodeId", "fn1"}, {"type", "bitWidth"}, {"fields", {{"width", 32}}} + }); + check(r1.contains("result"), "setSemanticAnnotation bitWidth via RPC"); + + // Set concurrency annotation via RPC + auto r2 = rpc(state, "setSemanticAnnotation", { + {"nodeId", "fn1"}, {"type", "atomic"}, {"fields", {{"consistency", "seq_cst"}}} + }); + check(r2.contains("result"), "setSemanticAnnotation atomic via RPC"); + + // Set scope annotation via RPC + auto r3 = rpc(state, "setSemanticAnnotation", { + {"nodeId", "fn1"}, {"type", "visibility"}, {"fields", {{"level", "public"}}} + }); + check(r3.contains("result"), "setSemanticAnnotation visibility via RPC"); + + // Query all annotations + auto r4 = rpc(state, "getSemanticAnnotations", {{"nodeId", "fn1"}}); + auto annos = r4["result"]["annotations"]; + bool hasBW = false, hasAtom = false, hasVis = false; + for (const auto& a : annos) { + std::string t = a.value("type", ""); + if (t == "BitWidthAnnotation") hasBW = true; + if (t == "AtomicAnnotation") hasAtom = true; + if (t == "VisibilityAnnotation") hasVis = true; + } + check(hasBW && hasAtom && hasVis, + "getSemanticAnnotations returns Subject 2-4 types"); +} + +// --- Test 7: setSemanticAnnotation works for all new type keys --- +static void test_rpc_set_all_new_types() { + HeadlessEditorState state; + state.openBuffer("test.wh", "", "python"); + auto* mod = buildTestAST(); + state.activeBuffer->sync.setAST(std::unique_ptr(mod)); + state.setAgentRole("s1", AgentRole::Refactor); + + // Test a representative selection of new type keys + std::vector> tests = { + {"endian", {{"order", "big"}}}, + {"layout", {{"mode", "packed"}, {"alignment", 4}}}, + {"nullability", {{"nullable", true}, {"strategy", "strict"}}}, + {"variance", {{"variance", "covariant"}}}, + {"identity", {{"mode", "nominal"}}}, + {"mut", {{"depth", "deep"}}}, + {"typeState", {{"state", "reified"}}}, + {"sync", {{"primitive", "monitor"}}}, + {"threadModel", {{"model", "os"}}}, + {"memoryBarrier", json::object()}, + {"exec", {{"mode", "async"}, {"runtimeHint", "tokio"}}}, + {"blocking", {{"kind", "io"}}}, + {"parallel", {{"kind", "data"}}}, + {"trap", {{"signal", "SIGSEGV"}}}, + {"exception", {{"style", "checked"}}}, + {"panic", {{"behavior", "abort"}}}, + {"binding", {{"time", "static"}}}, + {"lookup", {{"mode", "lexical"}}}, + {"capture", {{"strategy", "move"}}}, + {"namespace", {{"style", "qualified"}}}, + {"scope", {{"kind", "local"}}}, + }; + + int successCount = 0; + for (const auto& [type, fields] : tests) { + auto r = rpc(state, "setSemanticAnnotation", { + {"nodeId", "fn2"}, {"type", type}, {"fields", fields} + }); + if (r.contains("result") && r["result"].value("success", false)) + ++successCount; + } + check(successCount == (int)tests.size(), + "all 21 new type keys accepted by setSemanticAnnotation RPC"); +} + +// --- Test 8: isSemanticAnnotation recognizes all new types --- +static void test_is_semantic_annotation() { + std::vector allTypes = { + "BitWidthAnnotation", "EndianAnnotation", "LayoutAnnotation", + "NullabilityAnnotation", "VarianceAnnotation", + "IdentityAnnotation", "MutAnnotation", "TypeStateAnnotation", + "AtomicAnnotation", "SyncAnnotation", "ThreadModelAnnotation", + "MemoryBarrierAnnotation", + "ExecAnnotation", "BlockingAnnotation", "ParallelAnnotation", + "TrapAnnotation", "ExceptionAnnotation", "PanicAnnotation", + "BindingAnnotation", "LookupAnnotation", "CaptureAnnotation", + "VisibilityAnnotation", "NamespaceAnnotation", "ScopeAnnotation" + }; + int recognized = 0; + for (const auto& t : allTypes) { + if (isSemanticAnnotation(t)) ++recognized; + } + check(recognized == 24, "isSemanticAnnotation recognizes all 24 new types"); + check(!isSemanticAnnotation("DerefStrategy"), + "isSemanticAnnotation rejects non-semantic DerefStrategy"); +} + +int main() { + std::cout << "=== Step 277: Phase 10c Integration Tests ===\n"; + test_type_annotations_compact_ast(); + test_concurrency_annotations_compact_ast(); + test_scope_annotations_compact_ast(); + test_sidecar_roundtrip(); + test_mixed_annotations_single_function(); + test_rpc_get_annotations(); + test_rpc_set_all_new_types(); + test_is_semantic_annotation(); + std::cout << "\nResults: " << passed << " passed, " << failed << " failed out of " + << (passed + failed) << "\n"; + return failed > 0 ? 1 : 0; +}