Status: PORT COMPLETE (2026-07-20) — walker codegraph-kernel/src/swift.rs,
all gates passed (bump validated standalone with the diff classified per the
error-union rule + ripple pairing + two gate-found categories 7/8 below;
parity sweeps 0-diff Alamofire 89/98 / vapor 224/247 / swift-nio 407/554 at
--max-deferral 0.3 with exactly the predicted deferral counts; dump gates
byte-identical ×3; the Alamofire census reproduced property=348 on the kernel
arm; kernel-swift-parity suite; DEFAULT_ROUTED += swift). One survey
correction found by the swift-nio sweep: §Shadow prune understated the case
list — the shared assignment prune case (tree-sitter.ts:829) is ALSO
swift-live (a declared-then-assigned let X: T + X = … branches bumps
per assignment via the directly_assignable_expression's simple_identifier,
pruning X — swift-nio's main.swift files pin it). Survey basis: every
TS-side branch a .swift file exercises, with file:line anchors as of
a6c62d7 (HEAD at survey time, clean main). Every grammar-shape and
emission claim below was probed against both the current production wasm
(tree-sitter-wasms 0.1.13 build of npm tree-sitter-swift ^0.4.0, ABI 13) and a
fresh crate-0.7.3 build (ABI 15) — CST probes for shapes, plus the built
dist/ extractor run end-to-end on a 106-line torture file and on all 98
Alamofire files (emissions, order, counts pinned from real output, not
inference). Probe scripts + raw outputs: session scratchpad svy-swift/
(§Probe artifacts). Read WITH docs/design/rust-kernel-migration-plan.md
(§0a recipe, §2 boundary, §5 gates) and the format precedents
(rust-lang-, csharp-, ruby-, php-kernel-port-checklist.md — php's
non-neutral-bump "enumerate + classify" gate is the template here).
Blocking findings: none. Three eyes-open findings that shape the port: (1) the grammar bump is NOT graph-neutral — the old→new delta is confined to error-set membership (65 files across the three gate repos parse differently-erroneously per arm; three NEW-only regression construct classes enumerated in §Grammar-bump deltas) while every clean-parse extractor-relevant shape probed byte-identical (53-line CST diff across the whole battery, all classified inert); the bump gate is php-style enumerate+classify, not expect-zero. (2) Swift error incidence is structurally high — 9.2–26.5% on the NEW arm (both-arm reality, not a bump artifact) — the parity-sweep deferral guard MUST be raised for swift (§Deferral policy); a 0.1 guard fails the sweep on all three gate repos. (3) The port's center of gravity is the dedicated in-class property branch in tree-sitter.ts (#1020) — it is NOT in languages/swift.ts, it attributes its refs to the enclosing type rather than the property node, and Alamofire's 348 computed-property nodes (re-counted at survey time: exactly 348) ride it (§Dedicated property branch).
swift is not in VENDORED_WASM_LANGS (grammars.ts:291) — production loads
require.resolve('tree-sitter-wasms/out/tree-sitter-swift.wasm') (mapping
swift: 'tree-sitter-swift.wasm' at grammars.ts:34; .swift → swift at
grammars.ts:105), a 2023/24-era ABI-13 build of npm tree-sitter-swift
^0.4.0 (sha256 41c4fdb2…, 3,147,876 bytes; 540 node types / 45 fields).
tree-sitter-swift = "=0.7.3" (crates.io max_stable,
published 2026-06-01; repo alex-pinkus/tree-sitter-swift).main;
tag 0.7.3-with-generated-files (commit
31d17fe7e818a2048c808b5c6fdc2dc792f4f5b5) ships an ABI-14
parser.c (LANGUAGE_VERSION 14, SYMBOL_COUNT 565 — an older-generator run,
plus parser_abi13.c/parser_abi14.c variants), while the crates.io
tarball ships an ABI-15 regeneration (LANGUAGE_VERSION 15, SYMBOL_COUNT
558, STATE_COUNT 10321). The two are the SAME grammar — grammar.json
rules and externals are JSON-equal between tag and crate (probed) — but
the parser.c bytes differ, so a tag-side sha-match is impossible.
Build the wasm from the CRATE TARBALL's src/ (that is literally what
the kernel's cargo build compiles → table-identity by construction, the
csharp-precedent verification posture). Never touch the tag's parser.c and
never run tree-sitter generate.
src/parser.c sha256
d3edff6effe31b9a507f496577407987343b101b23eb7bee7a9b050e8ab5d27a (20,642,243 bytes — expect slow builds)src/scanner.c sha256
f3d6271d64f58c39eed544104a70ca2cf9ecbf80c5d900620f1afd38836542cb
(== the tag's scanner.c byte-for-byte). External scanner: YES — the
crate build compiles it automatically; the wasm build picks it up from src/.Build (survey-verified commands):
curl -sL https://crates.io/api/v1/crates/tree-sitter-swift/0.7.3/download -o ts-swift-0.7.3.crate
tar xzf ts-swift-0.7.3.crate && cd tree-sitter-swift-0.7.3
# crate tarball lacks tree-sitter.json (metadata only — no effect on tables);
# copy it from the 0.7.3-with-generated-files tag clone:
cp ../tag-clone/tree-sitter.json .
npx -y tree-sitter-cli@0.25.10 build --wasm -o tree-sitter-swift.wasm .
(brew emcc present; one benign scanner warning. Survey artifact: ABI 15,
3,726,622 bytes, sha256
cc77a63b8487956270e2f385e29a03ba0773ba532a3c8a8844a26b4c98793843, 563 node
types / 46 fields, at scratchpad svy-swift/tree-sitter-swift.wasm.)
Version-choice rationale (evaluated, not defaulted): the feared
alex-pinkus shape churn did NOT materialize for extraction — the full
OLD-vs-NEW CST battery (types/funcs/props/calls/imports/statics/docs) diffs
in only 53 lines, all inert (§deltas). An older crate (0.5.0/0.6.0) was
considered as a closer-match alternative and REJECTED: clean-parse shapes are
already identical on 0.7.3, so an older pin buys no shape proximity and
loses the error-set wins that dominate the delta — swift-testing #expect
(Alamofire's whole test suite), #Preview/#GET-style freestanding macros
(vapor 57→23 error files), package access, and typed throws(E) all parse
ONLY on 0.7.x. 0.7.3's three regression construct classes (§deltas) are
net-smaller (21 files) than its fixes (63 files) on the gate repos.
Staging plan: vendor to src/extraction/wasm/tree-sitter-swift.wasm;
add 'swift' to VENDORED_WASM_LANGS (grammars.ts:291) with an R7b
comment noting the crate-tarball provenance (NOT tag-sha-matched — state
why); pin tree-sitter-swift = "=0.7.3" in codegraph-kernel/Cargo.toml
(crate + wasm move TOGETHER); add 'swift' to GRAMMAR_LANGUAGES in
__tests__/kernel-grammar-parity.test.ts:39; kernel symbol
tree_sitter_swift::LANGUAGE in langs.rs grammar_for + the LANGUAGES
const (langs.rs:18, [&str; 13] → 14). MIT license. copy-assets already
globs src/extraction/wasm/*.wasm.
Bump lands FIRST, standalone, full suite green + the enumerate+classify dump gate (§Gates) — the diff is expected NON-empty and must be confined to the classified categories.
Clean-parse shapes: byte-identical. The whole probe battery (class-family, functions, properties incl. wrappers/observers/tuple-lets, every call shape, imports, static reads, docstrings) produced a 53-line CST diff, fully decomposed into:
Inert (verified against every consuming branch):
#selector token split: OLD one anon #selector token; NEW anon # +
selector. selector_expression's NAMED children are unchanged →
normalizeSpecial (function-ref.ts:685) and the body walker see identical
trees. Inert.#warning(…) internals: OLD = one diagnostic leaf swallowing the full
text; NEW = diagnostic with an anon # child. diagnostic matches no
type list on either arm; no named children either way; no stray sibling
call on NEW (probed clean-file). Inert.Behavior-changing — ALL of it is error-set membership (the wasm arm never defers: production extracts from error-recovery trees, so files whose error-status or recovery changes WILL diff in the bump gate's dump):
#Preview { } (OLD: ERROR + orphan lambda; NEW:
macro_invocation — a NEW-only node type, in NO type list → recursed, its
lambda's calls attribute to the enclosing scope), swift-testing #expect(…)
(all 4 OLD-only Alamofire error files are Tests using it), vapor's #GET
route macros (drives vapor 57→23); package access modifier; typed throws
throws(ErrorType) (swift-nio ByteBuffer-views). Node/edge/ref diffs in
these files are expected and accepted.#if/#elseif between enum cases (enum E { case a\n#if DEBUG\n
case b\n#endif }) → NEW ERROR, OLD clean. (#if at top level, between
CLASS members, around postfix .modifier(x) chains, and with ||
conditions all stay clean on both.)#if (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && …)) → NEW
ERROR (swift-nio's lock/NIOLock family).info?["k"] as? String ?? "d") → NEW ERROR (Alamofire HTTPHeaders).`default` parameter
label with other syntax; the label alone parses clean on both.)
These files' dumps diff (different recovery trees). Accept as classified;
count them; they are the deferral set the kernel will hand to wasm anyway.if let c = try? await … — errors on both, different trees). Any hunk in
a file that is in EITHER arm's error list falls under this category — the
gate's mechanical rule is per-file, not per-construct (below).#if directives on CLEAN files. The NEW grammar's directive/comment
sibling structure changes what getPrecedingDocstring accumulates next to
#if/#endif lines: 7 clean-on-both files (5 Alamofire, 2 swift-nio
Mocking.swift) diff in the docstring field ONLY (verified mechanically:
every other node field byte-equal). Direction: NEW gains a docstring the
OLD chain dropped (webSocketRequest gains "Only Apple platforms…") or
extends it with directive-adjacent text (_withWindowsPaths gains a
leading "ENABLE_MOCKING" line). The walker reproduces this automatically
(same shared docstring code over the same NEW trees).calls refs whose callee text is a whole multi-line array literal —
a call_expression whose namedChild(0) is the array literal on NEW where
OLD parsed the same bytes as separate expressions. Same garbage-but-
deterministic family as m[i][j]; the walker reproduces it via the raw
func-text rule.Bump-gate rule (php precedent, adapted): run the old-wasm vs new-wasm
full-init dump diff on all three gate repos; every diffing file must be in
the union of the two arms' hasError file lists (compute both lists first —
svy-swift/error-incidence.cjs does exactly this); a diff in a clean-on-both
file blocks the bump. Expect RESOLUTION ripple beyond the erroring files
(recovered symbols re-resolve refs in OTHER files — php's category-3
mechanism); prove ripple hunks mechanically by ref↔edge pairing
(php checklist's ripple-proof.mjs pattern) instead of re-litigating per file.
.swift ≤1 MiB, both arms)| Repo | files | OLD (^0.4.0 ABI-13) | NEW (0.7.3) | OLD-only | NEW-only | both |
|---|---|---|---|---|---|---|
| Alamofire | 98 | 10 (10.20%) | 9 (9.18%) | 4 | 3 | 6 |
| vapor | 247 | 57 (23.08%) | 23 (9.31%) | 35 | 1 | 22 |
| swift-nio | 554 | 154 (27.80%) | 147 (26.53%) | 24 | 17 | 130 |
Swift sits FAR outside the ts/java/py/go norm (0–0.42%): heavy #if
platform-conditionalization (swift-nio), try? await in conditions, and
@storageRestrictions init-accessors error on BOTH arms. Per-file
has_error() → defer: like every walker; run parity sweeps with
--max-deferral 0.3 (covers swift-nio's 26.5% with headroom; Alamofire/vapor
sit under 10%). Double-digit deferral on swift is grammar reality, not a
walker bug — but a deferral-rate JUMP vs the table above is a walker bug.
Deferred files are served by wasm and byte-match by construction; the sweep's
compared set is the ~73–91% that parse clean.
swiftExtractor has no preParse hook (languages/swift.ts
— whole file, no such key) → preParsedSource (kernel/index.ts:96) is a
no-op; both arms parse raw bytes. Swift's #if is grammar-native
(directive nodes, both branches kept as siblings — probed) — nothing to
blank, unlike C/C#.extract() hooks (parse-worker.ts:93-99 forces any
language with an applicable framework extract() onto the decoded
extractFromSource path): swiftUIResolver (frameworks/swift.ts:11,
detect = any .swift containing import SwiftUI, else any file path ending
.xcodeproj/.xcworkspace — note getAllFiles() returns indexed files,
so the xcodeproj leg rarely fires; the pbxproj inside doesn't end with
.xcodeproj), uikitResolver (:136, detect = any .swift containing
import UIKit/UIViewController/UIView), vaporResolver (:269, detect
= Package.swift containing vapor, else import Vapor). Also
expoModulesResolver (expo-modules.ts:154, languages swift+kotlin, has
extract) and swiftObjcBridgeResolver (swift-objc.ts:251 — resolve-only,
NO extract, doesn't force decode). Gate-repo reality (verified):
Alamofire → decoded (Example/ imports UIKit; watchOS example imports
SwiftUI), vapor → decoded (Package.swift), swift-nio → RAW buffers
path (no detector fires) — one gate repo per transport, keep all three.struct/class/component resolution by name,
frameworks/swift.ts:432) and — for the closure-collection pass —
function/method node extents (§CC pass). Vapor's route refs carry
filePath+language but those are FRAMEWORK refs (TS-side, post-walk).codegraph-kernel/src/swift.rs), registered
in langs.rs (grammar_for → tree_sitter_swift::LANGUAGE.into(),
LANGUAGES += "swift"). Skeleton cribs: java.rs for the class-like
scope stack + static-member refs + decorators; ruby.rs/php.rs for
hook-heavy dispatch; rustlang.rs for the node_ids dedupe + import
hooks. The dedicated property branch has no precedent in any walker — it
is new logic, transcribe from §Dedicated property branch..swift → swift only (grammars.ts:105); no content sniffing, no
dialect. MAX_FILE_SIZE (1 MiB) and generated-file skips are
orchestrator/TS-side and shared.tryKernelExtractRaw stays eligible.Types: functionTypes=[function_declaration]; classTypes=[class_declaration];
methodTypes=function_declaration;
interfaceTypes=[protocol_declaration]; structTypes=struct_declaration; enumTypes=enum_declaration;
enumMemberTypes=[enum_entry]; typeAliasTypes=[typealias_declaration];
importTypes=[import_declaration]; callTypes=[call_expression];
variableTypes=property_declaration, constant_declaration. nameField=name, bodyField=body,
paramsField=parameter, returnField=return_type.
THE FIELD-LOOKUP SUBTLETY (do not trust CST dumps here):
fieldNameForChild labels a function's return type and a typealias's value
name: — but childForFieldName resolves MULTIPLE field names on those
children through hidden rules. Probed truth-table, IDENTICAL on both grammars
(svy-swift/field-probe.cjs):
| lookup | result |
|---|---|
function_declaration name |
the simple_identifier (function name) |
function_declaration parameter |
NULL (parameter children are unfielded) |
function_declaration return_type |
the return type node (user_type/optional_type/…) |
function_declaration body |
function_body |
typealias_declaration name |
type_identifier (alias name) |
typealias_declaration value |
the aliased type node |
property_declaration name |
the pattern node |
property_declaration value |
the initializer expression |
property_declaration computed_value |
computed_property |
enum_entry name |
the FIRST case-name simple_identifier only |
The Rust walker must reproduce these exact resolutions (tree-sitter's native
child_by_field_name has the same semantics — but pin them in the parity
fixture, this is the branch the whole type-ref story hangs on).
Hooks PRESENT (port each exactly):
simple_identifier (the
name; modifiers/type_parameters before it are skipped via the seenName
latch); after it, function_body → undefined (body reached); user_type →
that node; optional_type → its first namedChild of type user_type
(?? null); first such hit wins: text = getNodeText(typeNode).trim()
.replace(/<[^>]*>/g, ''), last .-segment (KF.Builder → Builder — the
comment explains why NOT the first type_identifier), must match
/^[A-Za-z_]\w*$/ and ≠ 'Void' else undefined. Probed results:
-> Widget → Widget; -> Foo? → Foo; -> KF.Builder → Builder;
-> Result<Foo, Err> → Result (single-level generic strip); nested
generics break like rust — Result<Vec<Foo>, E> → strip leaves
Result, E> → regex fails → undefined; -> Void/-> [Foo](array_type)/
-> (Int, Foo)(tuple_type)/-> (Int) -> Foo(function_type) → undefined.
Parameters never match (their node type is parameter, not user_type — the
scan does NOT descend).name field must be
a user_type with >1 type_identifier children → the LAST one's text
(extension KF.Builder → Builder, so extension members merge with the
extended type's simple name, #750). Single-segment (extension Plain) and
non-user_type names → undefined (default extraction).getChildByField(node,'parameter') is
ALWAYS NULL (table above) → if (!params) return undefined →
signature is undefined on EVERY swift function/method (probed: sig=null
across the torture file and Alamofire). The returnType concatenation is dead
code. The walker emits NO signature for swift, ever.modifiers; on its WHOLE text: .includes('public') →
'public', .includes('private') → 'private', .includes('internal') →
'internal', .includes('fileprivate') → 'private' (dead arm —
'fileprivate' contains 'private', the second check already caught it);
no modifiers / no match → 'internal'. QUIRKS, PRESERVE: open →
'internal' (not checked — probed: open class func classFunc →
vis=internal); public private(set) → 'public' (first match);
substring-matching runs over ATTRIBUTE text inside modifiers too (an
attribute whose lowercase text contains 'private'/'public' would flip
visibility — not expressible with real-world wrappers, but the walker must
substring-match the same way).modifiers child whose text includes
'static' OR 'class' → true. class func/class var → static ✓
deliberate. Same substring hazard (an @objc(myclassthing) attribute text
would set isStatic — match bug-for-bug).struct → 'struct', TYPE enum → 'enum', else 'class'. The grammar
puts the keyword in the declaration_kind: anon child (class/struct/
enum/actor/extension) → actor → 'class', extension → 'class'.async as an
anon child AFTER the parameter list, never inside modifiers (probed:
func asyncy() async throws → isAsync=false). The walker must reproduce
false — note extractFunction/extractMethod store isAsync: false (hook
present, returns false), NOT undefined.find(type === 'identifier') → moduleName = its
FULL text (Foundation, UIKit.UIView — dotted kept). Kinded imports
(import class Darwin.FILE — anon class child) and @testable import
(modifiers first — find skips it) still find the identifier (probed). No
identifier → null → because the hook exists, tree-sitter.ts:3350 fires →
nothing emitted (no generic fallback; not constructible in valid swift).
handledRefs never set → generic imports ref {from file node, name =
moduleName, line/col of the import node} (tree-sitter.ts:3183-3194). None
of the language-gated binding emitters (TS/py/rust/php/ruby, :3197-3234)
match swift.Hooks ABSENT (the walker must NOT do these): preParse, isConst (but
kinds still split let/const — via the swift-specific branches, not the
hook), isExported (undefined on every node except the file node's literal
false and extractVariable's ?? false), isStatic IS present (above),
getReceiverType (never diverts extractFunction at :1522; methods happen
ONLY via isInsideClassLikeNode; no receiver QN override, no :1799
owner-contains fallback), resolveBody, recoverMangledName,
isMisparsedFunction, classifyMethodNode, extractPropertyName,
propertyTypes, fieldTypes, extraClassNodeTypes, packageTypes/
extractPackage (no namespace node — top-level QNs are bare),
extractModifiers, synthesizeMembers, extractBareCall, visitNode hook,
skipBodilessClass (but extractStruct/extractEnum have their own bodiless
skip — §class-family), methodsAreTopLevel, interfaceKind (protocols
are kind interface, NOT protocol), resolveTypeAliasKind.
Registration: EXTRACTORS.swift (languages/index.ts:54), FN_REF_SPECS.swift
(function-ref.ts:392).
a6c62d7)| Node | Branch | Behavior |
|---|---|---|
function_declaration (top level) |
functionTypes:994 → extractFunction:1517 | no receiver hook → always extractFunction at file scope |
function_declaration (inside class-like) |
:995 → extractMethod:1737 | methodTypes includes it + isInsideClassLikeNode (nodeStack top kind ∈ class/struct/interface/trait/enum/module, :1486) |
class_declaration (class/struct/enum/actor/extension — ALL of them) |
classTypes:1005 → classify → extractClass:1679 / extractStruct:1869 / extractEnum:1914 | §class-family |
protocol_declaration |
interfaceTypes:1054 → extractInterface:1834 | kind interface; §class-family |
typealias_declaration |
typeAliasTypes:1071 → extractTypeAlias:2890 | §Type aliases. Returns false → children ALSO recursed (nothing matches — user_type/function_type have no branches) |
property_declaration (top level) |
variableTypes:1098 (!isInsideClassLikeNode()) → extractVariable:2538 swift branch :2851 |
§extractVariable. skipChildren=true + scanFnRefSubtree — top-level initializers are NEVER walked: no calls/instantiates from them (probed: var topVar = compute() emits nothing) |
property_declaration (inside class-like) |
DEDICATED swift branch :1121-1193 | §Dedicated property branch. The :1098 gate fails first (isClassScopeConstantAssignment:1508 needs node.type assignment → false) |
protocol_property_declaration |
same dedicated branch (:1123) | protocol pushed = interface = class-like ✓ |
constant_declaration |
variableTypes | DEAD — node type doesn't exist |
import_declaration |
importTypes:1209 → extractImport:3170 | hook (§Extractor config) |
call_expression (top-level statement / class-body initializer descent) |
callTypes:1248 → extractCall:3684 | §extractCall. skipChildren stays false → nested calls recursed |
init_declaration / deinit_declaration / subscript_declaration |
NO branch | recursed by the generic loop :1295. No node minted. Their body statements are visited by visitNode (NOT visitFunctionBody) with the CLASS still on the stack → their calls attribute to the CLASS node (probed: init { setupMonitor() } → calls setupMonitor from=class; deinit's cleanup, subscript accessor bodies same). Consequences of the visitNode route: fn-ref capture fires (:990) but extractStaticMemberRef does NOT (body-walker-only, :5218) — a Color.red read inside init emits NOTHING |
enum_entry |
(via extractEnum's body loop only) | §class-family |
associatedtype_declaration, protocol_function_declaration, macro_invocation (NEW), directive, diagnostic, operator_declaration-family, precedence_group_declaration |
no branch | recursed, nothing extracted. Protocol method requirements mint NO nodes (probed — func didFinish(_:)/static func build() in a protocol produce nothing; only protocol_property_declarations become nodes via the dedicated branch) |
navigation_expression (top level / class body) |
no branch in visitNode | recursed. Static-member refs come ONLY from the body walker + walkAttrArgs — a top-level Type.self statement emits nothing |
| INSTANTIATION_KINDS (:354) | — | contains NO swift node types → Foo() is a plain calls Foo ref via extractCall; NO instantiates refs exist for swift, ever (probed) |
generateNodeId(filePath, kind, name, startRow+1)
= `${kind}:${sha256(`${filePath}:${kind}:${name}:${line}`).hex.slice(0,32)}`
(tree-sitter-helpers.ts:18). File node id = literal file:${filePath}
(:509), name = basename, qualifiedName = filePath, endLine =
source.split('\n').length, isExported false. Dedupe/self-checks compare
ID STRINGS (node_ids vec pattern) — same-(kind,name,line) collisions are
legal.:: (buildQualifiedName:1447;
namespacePrefix always empty outside C/C++). No package node → top-level
QN = bare name; members Session::request. Extension members ride the
extension's class node name (Builder::done for extension KF.Builder).decorators node field stays unset (probed dec=null
everywhere) — decorator refs are separate unresolved refs.svy-swift/extract-probe.out):
file node → source-order walk (per construct: node + contains edge → its
refs in extractor-internal order) → fn-ref refs (flushFnRefCandidates :538)
→ value-ref EDGES (flushValueRefs :539, appended to edges LAST). Per
class: class node → extends refs (one per inheritance_specifier, source
order) → (extractCsharpPrimaryCtorParamRefs no-op — needs parameter_list
child type, absent) → decorates refs of the class → body members in source
order. Per dedicated-branch property: property/field/constant/variable
node → decorates (owner) → type-annotation refs (owner) → walkAttrArgs
static-member refs (owner) → then (stored only) initializer-descent refs.
Per method: node → type-annotation (return-type) refs → decorates → body
refs.classify → 'struct': extractStruct (:1869) — body = getChildByField(node,
'body') (class_body); bodiless → NO node (:1876; record_declaration
exemption is C#-only; a bodiless struct isn't valid swift anyway). Node kind
struct {docstring, visibility, isExported:undefined}. extractInheritance →
§below. NO extractDecoratorsFor — @main struct MyApp emits NO decorates
ref (probed; the asymmetry: class YES, struct/enum/interface NO). Body
namedChildren visited with the struct pushed.
classify → 'enum': extractEnum (:1914) — body field (enum_class_body);
bodiless → no node. Kind enum {docstring, visibility, isExported:undefined}.
extractInheritance (the raw-value type rides it — enum Suit: String →
extends String; extends refs have NO builtin filter, probed extends Int).
NO decorates. Body loop: enum_entry ∈ enumMemberTypes → extractEnumMembers
(:1958): name field path — getChildByField(node,'name') returns the
FIRST case name → ONE enum_member node, positioned at the enum_entry, then
RETURN. QUIRKS, PRESERVE (probed): multi-case case put, delete → ONLY
put (delete DROPPED — the identifier-scan fallback :1967 is dead for swift
since the field always exists); associated values (case success(Data) —
data_contents: enum_type_parameters) and raw values (= "H") are never
walked → NO refs from them; indirect case same. Non-enum_entry children
(computed properties, methods, nested types) → visitNode with the enum pushed.
classify → 'class' (incl. actor + extension): extractClass (:1679) — no
skipBodilessClass → a bodiless class_declaration would still mint (not valid
swift). Kind class {docstring, visibility, isExported:undefined}.
extractInheritance; extractCsharpPrimaryCtorParamRefs no-op;
extractDecoratorsFor DOES run (@Observable class Model → decorates
Observable). Push, visit body namedChildren via visitNode, no
synthesizeMembers, pop. Extensions: name via resolveName (multi-segment)
else raw name-field text — extension Point → class Point (a SECOND
class node named like the original — same name, different line → distinct
id); extension [ServerTrustEvaluating] → class named literally
[ServerTrustEvaluating] (raw sugar text, probed); extension Array
where Element: Equatable → class Array, and the type_constraints where
clause emits NOTHING (inheritance_constraint is not an inheritance_specifier).
extractInterface (:1834) — protocol_declaration → kind interface (no
interfaceKind hook) {docstring, isExported:undefined — NO visibility, NO
decorates}. extractInheritance on the protocol node (protocol inheritance
: AnyObject, Identifiable → extends refs). Body (protocol_body)
namedChildren visited with the interface pushed: protocol_property_declaration
→ dedicated branch (§below); protocol_function_declaration /
init_declaration / associatedtype_declaration → recursed, nothing.
Direct namedChildren scan of the declaration node; ONLY the
inheritance_specifier case matches swift (one specifier per conformance,
each inherits_from: user_type): userType = child.namedChildren
find(type==='user_type') → typeId = ITS namedChildren
find(type==='type_identifier') — the FIRST — → one extends ref
{from class/struct/enum/interface node, name = typeId text, line/col of the
TYPE IDENTIFIER}. QUIRKS, PRESERVE: everything is extends — protocol
conformance, protocol inheritance, raw-value types; swift emits NO
implements refs from extraction (resolution's supertype machinery handles
both kinds); a qualified base : Module.Base takes the FIRST segment
(Module) — the outer namespace, not the type. Where-clause constraints and
generic bounds (type_parameter name: bounds) emit nothing. None of the
other clause cases (extends_clause/base_class_clause/delegation_specifier/…)
match swift node types.
Fires for property_declaration | protocol_property_declaration when
language === 'swift' AND isInsideClassLikeNode(). Position in the else-if
ladder: AFTER variableTypes (:1098 — which in-class properties fail, see
dispatch table), BEFORE importTypes. Alamofire baseline (re-measured at
survey HEAD on the production path): 98 files → 3,988 nodes = method 1801 /
field 588 / class 379 / property 348 / enum_member 230 / import 183 / struct
111 / file 98 / constant 97 / enum 77 / type_alias 39 / interface 27 /
function 10; 16,426 refs. The 348 property nodes are exactly this
branch's computed path — the #1020 number reproduced to the digit.
pattern = childForFieldName('name')
?? namedChildren.find(t === 'value_binding_pattern' || t === 'pattern')
?? null
binding = namedChildren.find(t === 'value_binding_pattern') // DIRECT children only
isLet = binding != null && text(binding).trimStart().startsWith('let')
isComputed = namedChildren.some(t === 'computed_property' || t === 'protocol_property_requirements')
nameNode = firstSimpleIdentifier(pattern)
firstSimpleIdentifier (:261-273): BFS (shift from a queue) over
namedChildren, guard: at most 40 nodes popped; first simple_identifier
wins. Tuple pattern let (a, b) → a only (one node for the whole
declaration, PRESERVE).
Shape notes (probed, identical both grammars):
value_binding_pattern
(mutability let/var) and name: pattern > bound_identifier:
simple_identifier are SIBLING direct children → binding found → isLet real.name: pattern → the direct-children find MISSES it → binding null →
isLet always false for protocol requirements (irrelevant today — they
are all computed — but transcribe the miss).computed_value: computed_property carries the getter; the code matches by
TYPE not field.willSet/didSet observers are a willset_didset_block, NOT a
computed_property → an observed stored property (var observed: Int = 0
{ willSet {…} didSet {…} }) is isComputed=false → a field node, and
(stored-path descent, below) the observer bodies' calls attribute to the
CLASS (probed: calls prepare / calls react from=class).ownerId = nodeStack top (the class/struct/enum/interface node).createNode('property', name, node, {visibility: hook,
isStatic: hook ?? false}) — computed properties become property
nodes (the #1020 "var isCloudProxy: Bool" fix; SwiftUI var body: some
View is the canonical case). Note extras: NO docstring, NO signature,
NO returnType — visibility + isStatic ONLY (probed doc=null on all).isStatic = hook ?? false; kind = isStatic ? (isLet ?
'constant' : 'variable') : 'field'** —static let→constant,
static var→variable(class var→ isStatic via 'class' substring
→variable), instance stored (let OR var) →field`. Same extras.extractDecoratorsFor(node, ownerId) — refs attach to the
ENCLOSING TYPE, not the property (probed: @Published private var wrapped
→ decorates Published from=class:Session). §Decorators for mechanics.extractVariableTypeAnnotation(node, ownerId) (:6074) — finds
the direct type_annotation child → extractTypeRefsFromSubtree (:6090) →
one references ref per type_identifier leaf not in BUILTIN_TYPES,
from the OWNER (probed: let rootQueue: DispatchQueue → references
DispatchQueue from=class at the leaf's position). BUILTIN_TYPES nuances
(:5768): Int/String/Double/Float/Boolean/Long/Char are
suppressed (Scala rows), Bool is NOT (→ real references Bool
noise ref, probed), Void/Character/Self NOT. Wrappers recurse:
[Tag] → Tag; Session? → Session; some View (opaque_type) →
View.modifiers direct
child; if present, recursively run extractStaticMemberRef(n) over EVERY
node of the modifiers subtree. This is the Vapor @Siblings(through:
PivotModel.self, from: \.$left, …) mechanism: the attribute-argument
navigation_expression with target simple_identifier PivotModel +
suffix .self → references PivotModel from the OWNER at the RECEIVER's
position. Keypath args (\.$left — target is key_path_expression) and
the wrapper's own user_type are self-filtered (not MEMBER_ACCESS_TYPES /
not an accepted recv type). §Static-member refs for the shared mechanics.computed_property |
protocol_property_requirements); if found: push property id,
visitFunctionBody(getter, ''), pop; skipChildren = true. The
getter's calls/reads attribute to the PROPERTY node (probed: calls check
from=property:isCloudProxy; SwiftUI body's VStack/Text subtree
becomes the property's callees). protocol_property_requirements contains
only getter/setter specifiers → walks emit nothing.calls refs from the CLASS (let
stored = Session() → calls Session from=class; lazy var expensive =
Cache.build() → calls Cache.build from=class); willset/didset bodies
likewise; the modifiers subtree is re-walked harmlessly (attributes have
no visitNode branches; walkAttrArgs already emitted the static refs —
different ref kinds, no dupes). Value-position navigation reads (let m =
Suit.hearts as an in-class initializer) emit NOTHING here (no
static-member call in visitNode) — contrast bodies.value) → a
stored let cb: Handler = onFire captures onFire; computed properties
have no value field → nothing.Top-level property_declaration only (dispatch table). swiftPropertyInfo
again: nameNode && !isComputed → createNode(isLet ? 'constant' : 'variable',
name, NODE, {docstring, isExported}) — position = the whole declaration,
extras: docstring (getPrecedingDocstring — top-level consts DO get
docstrings, unlike the in-class branch), isExported = ?? false → literal
false (:2549; probed exp=false — the only swift nodes besides the file
node with a non-undefined isExported), NO signature (unlike the TS/Go
branches — no initializer capture), no visibility/isStatic. Computed
top-level (var topComputed: Int { 9 }) → skipped entirely (no node).
One node per declaration — tuple let (a, b) = … → a only. The :1098
dispatch sets skipChildren=true + scanFnRefSubtree (capture-only, halts at
functionTypes + lambda_literal :610) → top-level initializers emit NO
calls/instantiates refs (probed: var topVar: Int = compute() → nothing
but the node; no type-annotation refs either — extractVariableTypeAnnotation
is NOT called on this path, PRESERVE the asymmetry with the in-class branch).
name → the simpleidentifier. Operator functions: func <+>
(lhs:…) has name: custom_operator → extractName returns the raw operator
text → a function node named <+> (probed clean-parse on both arms).
<anonymous> never occurs (grammar requires a name; the arrow/function
expression paths are TS-only).static/class modifiers), returnType (hook).modifiers → real decorates refs (@objc func attributed → decorates
objc, position = the attribute node). Push, walk body field
(function_body) via visitFunctionBody, pop.function node contained by the
enclosing method/function (its QN prefixes the enclosing chain via
nodeStack). Closures (lambda_literal) are NOT functionTypes → no nodes;
their calls attribute to the enclosing symbol (probed: rootQueue.async {
self.perform(req) } → calls perform from=method:request).typealias_declaration → name field (alias name). No resolveTypeAliasKind →
plain type_alias node {docstring, isExported:undefined}. swift ∈
TYPE_ANNOTATION_LANGUAGES → value = getChildByField(node,'value') — the
multi-field lookup WORKS (table above) → extractTypeRefsFromSubtree over
the aliased type → refs per type_identifier leaf (probed: typealias Handler
= (Data) -> Void → references Data + references Void; typealias
BuilderAlias = KF.Builder → refs KF AND Builder — one per segment).
The TS-only member extraction (:2983) is gated away. Returns false →
children recursed (nothing matches).
Swift never hits the vbnet/erlang/objc/php/java branches (no name+object
fields on call_expression). Generic else :4312: func =
childForFieldName('function') ?? namedChild(0) — swift has NO function field
→ namedChild(0) always. cpp operator recovery (:4324) is cpp-gated. The
full observed matrix (every row probed via the built extractor):
| Call shape | func node | Path | Emitted ref |
|---|---|---|---|
helper() |
simple_identifier | else :4518 raw text | calls helper |
Foo() |
simple_identifier | same | calls Foo (constructor = plain call; NO instantiates, ever) |
Foo.init(raw:) |
navigation_expression | :4364 member branch | calls Foo.init |
obj.method(1) |
navigation_expression | member | calls obj.method |
self.own() |
nav, target self_expression |
receiver not identifier-typed → fallthrough | calls own (bare — swift self is its own node TYPE; SKIP_RECEIVERS:4400 {self,this,cls,super} is reached only for identifier-typed receivers, so the same net effect arrives via a different path than kotlin) |
super.parent() |
nav, target super_expression |
same | calls parent |
a.b.deep() |
nav, target inner nav | fallthrough | calls deep (bare — 2-hop receivers drop) |
x?.optCall() |
nav, targets [simple_identifier x, anon ?] |
receiver = namedChild(0) = x |
calls x.optCall (optional chaining keeps the receiver — the ? is a second anon target: child, invisible to namedChild) |
y!.forced() |
nav, target postfix_expression | fallthrough | calls forced |
Foo.make().draw() |
nav, target call_expression | #750 re-encode :4408-4442: swift-gated; innerNav = receiver.namedChild(0) (Foo.make nav or bare identifier), text ws-stripped; /^[A-Z]/ gate |
calls Foo.make().draw + (recursion) calls Foo.make |
foo.bar().baz() |
same | innerCallee foo.bar lowercase → reencode false |
calls baz + calls foo.bar |
"lit".upper() |
nav, target line_string_literal | LITERAL_RECEIVER_TYPES :4397 (line_string_literal ∈ set :377) |
NOTHING |
"""…""".trimmed() |
nav, target multi_line_string_literal | NOT in the literal set | calls trimmed (bare) — PRESERVE |
5.times() / [1,2].reduce(…) |
integer_literal / array_literal | literal set | NOTHING |
["k":1].lookup() |
dictionary_literal | NOT in the set (dictionary is, dictionary_literal isn't) |
calls lookup — PRESERVE |
(freestanding)() |
tuple_expression | else raw text (freestanding) → parenthesized-conversion regex :4530 FIRES |
calls freestanding |
closureTaking { } / multi-trailing |
simple_identifier (lambda in call_suffix) | else | calls closureTaking |
arr[0] (subscript READ) |
simple_identifier (bracket call_suffix) | else | calls arr — every subscript access parses as call_expression; huge-volume quirk, PRESERVE |
m[i][j] |
inner call_expression | receiver is call but func = call_expression not nav → else raw text | calls m[i] (garbage, PRESERVE) |
self.items[k] = 1 |
nav self.items | member, self receiver | calls items |
defer { cleanup() } |
simple_identifier defer |
else | calls defer + inner calls cleanup — defer parses as a trailing-closure call (both arms, probed) |
try f() / try? f() / await f() |
(wrapped in try_expression/await_expression) | recursion reaches the inner call_expression | normal ref, position = the CALL node (after the keyword) |
"count \(counter.next())" |
(interpolated_expression inside the literal) | recursion descends into string literals | calls counter.next — interpolation calls DO emit |
.make() (implicit member call) |
prefix_expression | else raw text | calls .make (leading dot, unresolvable — PRESERVE) |
macro #Preview { ContentView() } (NEW) |
(macro_invocation unhandled) | recursion | inner calls ContentView from the enclosing scope |
Post-processing: parenthesized-conversion (:4529) as noted; template-strip (:4542) and cpp fn-ptr fan-out (:4556) are c/cpp-gated. Final ref: {callerId = nodeStack top, name, line = call startRow+1, column = call startColumn (UTF-16)}. Inner nav/call children are ALSO visited after extractCall (callTypes doesn't skipChildren; body walker recurses) — chains emit inner refs, and the callee-position navigation_expression is exempted from static-member refs by the :4771 callee-of-call check.
Called from the body walker ONLY (:5218) plus the property branch's
walkAttrArgs. navigation_expression ∈ MEMBER_ACCESS_TYPES (:326). Mechanics
for swift: callee-of-call skip (:4771-4779 — parent ∈ callTypes and
parent.namedChild(0).startIndex === node.startIndex → the callee nav of a
call emits nothing); recv = object/expression/scope fields (all null for
swift — nav's fields are target/suffix) → namedChild(0) = the target.
Accepted recv types (:4791): identifier/type_identifier/simple_identifier/
name/scoped_type_identifier — swift targets are simple_identifier →
capitalized regex ^[A-Z][A-Za-z0-9_]*$ → references <target> from the
enclosing symbol at the RECEIVER's position. Probed rows: Color.red →
references Color; Suit.hearts.rawValue → outer nav recv = inner nav →
nothing, inner nav → references Suit; UserModel.self → references
UserModel; Deep.Nested.leaf → references Deep (inner nav only);
.implicitMember → prefix_expression, not a nav → NOTHING; lowercase.field
→ nothing; keypath \Foo.bar → recv = key_path_expression → nothing (the
type_identifier inside the keypath is never read). Remember the visitNode
gap: class-level initializer reads and init/deinit/subscript bodies emit NO
static-member refs (dispatch table).
For every function/method (extractTypeAnnotations :5788, called at
:1594/:1816): params = getChildByField(node, 'parameter') → NULL → NO
parameter type refs, ever (probed: @escaping (Int) -> Void param emits
nothing — Void would have shown). returnType = getChildByField(node,
'return_type') → WORKS (field table) → extractTypeRefsFromSubtree over
the return node → one references per type_identifier leaf not in
BUILTIN_TYPES: -> DataRequest → ref; -> KF.Builder → refs KF AND
Builder; -> Session? → Session; -> Result<Foo, Err> → Result,
Foo, Err (leaves); builtins suppressed per the §property-branch nuance
list (Bool NOT suppressed). The trailing direct type_annotation find
(:5873) is null for function_declarations. extractVariableTypeAnnotation
(:6074): the dedicated property branch (owner-attributed) and the body
walker's variable_declarator gate (:5230-5236 — dead for swift, no such
node type; body-local let x: Foo property_declarations emit NO type refs —
PRESERVE). property_signature/method_signature (:1282) — TS-only types.
attribute nodesconsider() (:4898) accepts type attribute; the target scan (:4937) finds
the attribute's first namedChild of accepted types — swift attribute →
user_type (:4950) → name = user_type text, strip <…> generic suffix,
strip to last ./:: segment, trim → decorates ref {from the decorated
node id (or the OWNER for the property branch), name, line/col of the
ATTRIBUTE node}. Attributes live INSIDE the declaration's modifiers child →
found via the modifiers descent (:4983); the preceding-sibling scan (:5013)
finds nothing for swift (attributes are never siblings) and stops at the
first non-decorator sibling. Coverage matrix (probed): function ✓ (@objc →
decorates objc), method ✓, class ✓ (@Observable), dedicated-branch
property ✓ (owner-attributed) — struct/enum/interface ✗ NO decorates
(extractStruct/extractEnum/extractInterface never call it — @main struct,
@objc enum, attributed protocols emit nothing, probed). Attribute ARGUMENTS
are never walked here — only walkAttrArgs (property branch) reads them, and
only for static-member shapes. Parameter attributes (@escaping etc. inside
parameter/parameter_modifiers) are never reached by any pass.
/// doc lines AND // plain comments are node type comment — accepted by
the sibling scan; consecutive runs accumulate (unshift → source order) and
// vs /// are NOT distinguished (a plain comment right above a decl IS
its docstring). /** */ and /* */ block comments are multiline_comment
— NOT in the accepted set (comment/line_comment/block_comment/
documentation_comment) → block docs are IGNORED and BREAK the accumulation
chain (probed: /** block doc */ func blockDoc → doc=null). PRESERVE.
DOCSTRING_WRAPPER_TYPES: no swift wrappers → no climbing. Attributes do NOT
break the chain (they're inside the declaration node — /// doc +
@objc func keeps its doc, probed). cleanCommentMarkers (:77): swift hits
^\/\/[/!]?\s? (gm) and — only if a multiline_comment ever reached it, which
it can't — the block strips. The gm per-line strips are the ONLY
CRLF-sensitive regexes on the swift path (#1329): use js_multiline_strip
in docstring.rs. Docstrings attach to: functions, methods, classes
(incl. extensions/actors), structs, enums, interfaces, top-level
constants/variables (extractVariable), type_aliases. NOT to: dedicated-branch
properties/fields/constants (extras carry no docstring — probed), enum
members, import nodes.
Port the full machinery (crib go.rs/java.rs): CODEGRAPH_VALUE_REFS=0 kill;
MAX_VALUE_REF_NODES = 20,000 caps the prune DFS and each reader scan;
isGeneratedFile skip.
/[A-Z_]/, parent id prefix ∈ {file:, class:, module:,
struct:, enum:} — the struct:/enum: rows exist FOR swift's
static-let-namespacing idiom (enum Constants { static let X }, comment at
:748-750). Swift targets: top-level let/var (under file:) and in-class
static let/static var (constant/variable under class:/struct:/enum:).
interface: NOT accepted → protocol statics (hypothetical) excluded.
Instance fields and computed propertys are NOT targets.property and field are NOT readers (probed: isCloudProxy's read
of SHARED_MAX emits no edge; method request's does).property_declaration case (:856-869) RESOLVES for swift (unlike
php): vd = find variable_declaration (Kotlin) — absent for swift → else
firstSimpleIdentifier(childForField('name') ?? find(value_binding_pattern
| pattern)) — the swift shape → bump() counts it when the text is a
target name (bump accepts identifier|simple_identifier :807). EVERY
property_declaration in the tree bumps — targets' own declarations, body
locals (let SHARED_MAX = 5 in a method — the shadow source), and
same-named instance properties. declCount > fileScopeCount → target
deleted. guard-let/if-let bindings do NOT bump (guard_statement/
if_statement hold bound_identifier directly, no property_declaration —
probed) → a guard let X = … shadow does NOT prune. PRESERVE both sides.simple_identifier (:908 — swift's every name reference) whose text maps
to a target, target ≠ self, name ≠ scope's own name, dedupe per
(scope,target) → EDGE {source: scopeId, target, kind:'references',
metadata:{valueRef:true}}, appended AFTER all other edges. Because every
simple_identifier matches — nav suffixes included — Session.SHARED_MAX
AND a bare SHARED_MAX both emit (probed: the single torture valueRef
edge method:request → constant:SHARED_MAX).idTypes: { simple_identifier }
dispatch: value_arguments → args
assignment → rhs (field 'result')
array_literal → list
property_declaration → varinit (field 'value')
layers: value_argument → 'value' // FIELD 'value', not null
special: { selector_expression }
No unwrap/ungatedModes/addressOfOnly. Mechanics (function-ref.ts:408-597 + :685-696), all probed:
simple_identifier
→ candidate (NAME_STOPLIST drops self/true/nil/…). reg2(onFire) →
onFire ✓; [cbA, cbB] → both ✓ (the array_literal's OWN dispatch —
varinit's normalizeValue over an array_literal yields [], the capture
happens when the walker/scan VISITS the array node).value_argument_label), value =
childForField('value') ?? last namedChild; label text === value text →
DROPPED (forward(value: value) → nothing; the Alamofire A/B finding).
Else descend the value field.result): param-storage skip — lhs =
left/lhs/target fields ?? namedChild(0) (swift's field is target, a
directly_assignable_expression); lhs text's last identifier === rhs text →
skip (self.raw = raw → nothing, probed). o.cb = handler → handler ✓.value): destructuring check
reads childForField('name') — swift's is type pattern, NOT in
{object_pattern, array_pattern, tuple_pattern, struct_pattern} → never
skipped; tuple-let values are non-normalizable expressions anyway.
Computed properties have no value field → nothing.#selector(fire) → fire); else
rightmost simple_identifier descendant (#selector(Holder.fire) → fire;
QUIRK: #selector(onNote(_:)) → the rightmost simple_identifier is the
argument label _ → candidate _, dropped by the gate in practice); else
trimmed inner text. explicitRef=true (not an idType).lambda_literal — closures halt the scan — and functionTypes).Foundation (SIMPLE)
and UIKit.UIView (QUALIFIED_IMPORT → last segment UIView) both land in
importedNames but almost never match a candidate → the swift gate is
effectively "defined in this file" (probed: #selector(Holder.fire)'s
fire dropped; onFire/handler/cbA/cbB survive as same-file
functions). Survivors dedupe on ${fromNodeId}|${name} →
{referenceKind:'function_ref'}, appended after all walk refs..forEach/.append(/.add(/.push(/.insert(
dispatch/registration pairs. Input contract on the walker: node kinds,
languages, and LINE EXTENTS byte-match — a wrong endLine silently changes
synthesis. The dump gate covers this; nothing extra to build.swiftObjcBridgeResolver) + the sendEvent scan
(callback-synthesizer.ts:1387-1438) read raw .swift file text — file-set
contract only.swiftUIResolver / uikitResolver / vaporResolver (resolution/frameworks/
swift.ts:11/:136/:269): extract() hooks emit component/class/route
nodes with LITERAL ids (view:${filePath}:${name}:${line},
route:${filePath}:${line}:${METHOD}:${path} — NOT hashed) + vapor handler
refs (which DO carry filePath+language — framework refs, not extraction
refs). resolve() consumes plain references names by suffix + kind + dir
conventions (getNodesByName — walker's node names/kinds are the contract).
Vapor's @Siblings metatype refs (§property branch step 5) are the
extraction-side feed that keeps pivot models un-orphaned on Fluent repos.
[ServerTrustEvaluating])
for sugar extensions, <+> for operator functions, the full dotted module
(UIKit.UIView) for import nodes; line = declaration start (= the
modifiers/attribute start when attributes precede the keyword — the
declaration node INCLUDES its modifiers).startIndex/endIndex substrings (getNodeText — getVisibility/
isStatic read child.text, same substring), and the .slice(0,100)-class
truncations (unused on the swift path — no signature/initializer capture).
Swift sources are emoji/CJK-heavy in tests — the torture fixture needs a
non-ASCII line before a symbol.gm strips (§Docstrings) → js_multiline_strip in
docstring.rs. trimStart()/startsWith('let') in swiftPropertyInfo are
whitespace-semantics-identical in Rust (trim_start). CRLF fixture
variants derived in-memory, per the tsjs pattern.has_error() → defer:; expected incidence
9–27% (§table); sweep with --max-deferral 0.3 — the c/cpp-style
exemption, justified by both-arm measurement, NOT a walker allowance: a
JUMP vs the table is a walker bug.sourceIsPreParsed never set for swift.=0.7.3 crate pin + VENDORED_WASM_LANGS + kernel-grammar-parity
GRAMMAR_LANGUAGES += 'swift' in one change, full suite green, before any
walker exists. Old-wasm vs new-wasm full-init dump diff on all three gate
repos (scripts/dump-graph.mjs, cmp): expected NON-empty; every
diffing file must be in the union of the two arms' hasError lists
(regenerate with svy-swift/error-incidence.cjs; categories in
§Grammar-bump deltas — macro/testing/package/typed-throws fixes, the three
NEW-regression classes, both-arm recovery drift); prove residual
resolution ripple mechanically by parked-ref↔edge pairing (php's
ripple-proof pattern). Any clean-on-both-arms file diffing blocks the bump.## Fixtures to build (+ CRLF variants derived
in-memory), exercised by the new parity suite.scripts/kernel-parity.mjs <dir>, order-sensitive
full-object, --max-deferral 0.3):
…/scratchpad/gate-repos/Alamofire (small, 98 files — the mandatory
#1020 gate, decoded path)…/scratchpad/gate-repos/vapor (medium, 247 files, decoded path,
Fluent/@Siblings + route shapes)…/scratchpad/gate-repos/swift-nio (large, 554 files, raw-buffers
path — no framework detects)
(all three cloned at survey time; re-clone fresh if gone). Then full-init
dump-diffs byte-identical (kernel arm vs CODEGRAPH_KERNEL=0,
dump-graph.mjs, cmp) on the same three.a6c62d7 + current Alamofire HEAD: property = 348
(the #1020 number, re-measured), field 588, method 1801, class 379
(extensions!), constant 97, struct 111, enum 77, enum_member 230,
interface 27, type_alias 39, function 10, import 183 (98 files, 3,988
nodes, 16,426 refs — svy-swift/count-props.cjs). A missing dedicated
branch shows up here as property→0 / field→0 before the dump diff even
runs.__tests__/kernel-swift-parity.test.ts — torture + CRLF
variants + an intentionally-erroring defer fixture (use a NEW-only
regression construct — e.g. #if DEBUG between enum cases — asserting the
kernel defers and wasm output is served); full suite ×2 green with
CODEGRAPH_KERNEL_EXPECT=1.DEFAULT_ROUTED += 'swift' (kernel/index.ts:37) only after ALL of the
above; changelog rides the existing kernel entry.torture.swift (seed: the survey's svy-swift/torture.swift, already
validated against the built extractor — extend it with the rows below),
a CRLF variant derived in-memory, one defer fixture (a NEW-only
regression construct, above), and keep every line traceable to a branch:
public final class C: Base, Proto1, Proto2
(extends ×3, all 'extends'); struct + bodiless-skip N/A; enum backed
(: String → extends String) + case a = "H" + multi-case case put,
delete (ONLY put minted) + associated values (no refs) + indirect +
computed property + static method in enum; actor (→ class); extension
Point: Hashable (second class node, extends); extension KF.Builder
(resolveName → Builder); extension Array where Element: Equatable
(class Array, NO constraint refs); extension [Proto] (class named
[Proto]); protocol with inheritance + var requirement {get set} (→
property node, isLet=false via the nested-binding miss) + static var
requirement + func/init/associatedtype requirements (NO nodes).static let SHARED_MAX (constant, value-ref target); static var
(variable); class var computed (property, isStatic via 'class');
lazy var x: Cache = Cache.build() (field + calls Cache.build
from class); public private(set) (→ 'public'); @Published private var
(decorates from OWNER + vis 'private'); @Siblings(through: Pivot.self,
from: \.$left) var siblings: [Tag] (decorates Siblings + walkAttrArgs
references Pivot + type-ref Tag, all from OWNER); computed
var isCloudProxy: Bool { check() } (property + calls check FROM the
property + references Bool — Bool not builtin); SwiftUI-shaped
var body: some View { VStack { Text(label) } } (property; VStack/Text
calls from the property; references View); observed var x = 0 {
willSet{prepare(newValue)} didSet{react(oldValue)} } (field, observer
calls from the CLASS); weak var delegate: SessionDelegate?; tuple
let (a, b) = makePair() (ONE node a, calls makePair from class);
open visibility (→ 'internal').sig=null, return-type
ref, NO param refs — include a Void-bearing param type to prove the
negative); -> KF.Builder (returnType 'Builder' + refs KF AND Builder);
-> Result<Foo, Err> (returnType 'Result'); -> Result<Vec<Foo>, E>-shaped
nested generic (returnType undefined); -> Foo? / -> [Foo] / -> (A,B)
/ -> (Int) -> Foo / -> Void; func f() async throws (isAsync FALSE);
static func / open class func (isStatic true, vis 'internal');
operator func <+> (lhs:…) (node named <+>); nested named func in a
body; @objc func (decorates objc); @main struct + @objc enum +
attributed protocol (NO decorates).init(raw:) { self.raw = raw; setupMonitor() }
(no node; calls setupMonitor from class; NO fn-ref for the param-storage
assignment); convenience init? (calls init bare from class); deinit;
subscript with get/set (calls store ×2 from class).Foo(),
Foo.init(), member, self/super (bare), 2-hop (bare), x?.m()
(receiver kept), y!.m() (bare), Foo.make().draw() re-encode + inner,
lowercase chain (bare + inner), "lit".upper() (nothing),
"""m""".t() (bare t), 5.times() / [1,2].reduce (nothing),
["k":1].lookup() (bare), (f)() (conv-regex → f), trailing + multi-
trailing closures, arr[0] (calls arr), m[i][j] (calls m[i]),
defer {} (calls defer), try/try?/await wraps, string-interpolation
call, implicit-member call .make() (calls .make), Task { await f() }.Color.red, Suit.hearts.rawValue
(Suit only), UserModel.self, Deep.Nested.leaf (Deep only),
.implicit (nothing), lowercase.f (nothing), keypath \Foo.bar
(nothing) — plus the SAME reads at class-initializer scope and inside
init (nothing — the visitNode gap).static let SHARED_MAX in a class/struct/enum read from a
method (edge) and from a computed property (NO edge — property not a
reader); a method-local let SHARED_MAX = 5 in a SECOND fixture variant
(prune kills the target); a guard let SHARED_MAX variant (NO prune);
top-level let TOP_LEVEL_MAX + reader.reg(onFire), reg(cb: onFire) (label≠value → survives),
forward(value: value) (label-forward skip), o.cb = handler,
self.x = x (param-storage skip), let table = [cbA, cbB],
#selector(fire) / #selector(Holder.fire) / #selector(onNote(_:))
(the _ gate-drop), an undefined-name arg (gate-drop).import Foundation, dotted import UIKit.UIView, kinded
import class Darwin.FILE, @testable import./// run (joined), // plain (IS a docstring), /** */
(ignored), /* */ between /// and decl (breaks chain), doc over an
attributed decl (kept), doc on top-level const (kept) vs in-class property
(dropped).#if os(iOS) around members (both branches extracted), #warning,
a macro_invocation file (NEW arm; on OLD this file is a defer candidate —
keep it in the DEFER fixture instead), a non-ASCII (UTF-16) line before a
symbol, guard/if-let/for-await bodies with calls.svy-swift/)probe-swift.cjs + shape-{OLD,NEW}.txt + shape.diff (the 53-line
classified battery diff), mini-probes.cjs + mini-probes.out (node-type
inventory, per-construct error matrix, defer/subscript/#if/async-let/regex
shapes), field-probe.cjs (the childForFieldName truth table),
regress-probe.cjs (NEW-regression minimal repros), error-incidence.cjs
(the §incidence table + per-file lists), error-diag.cjs (first-ERROR
diagnosis used for the delta classification), extract-probe.cjs +
torture.swift + extract-probe.out (the built-extractor emission pin),
sugar-probe.cjs (extension sugar/decorates asymmetry/implicit-member call),
count-props.cjs (the Alamofire census), tree-sitter-swift.wasm (the
staged-candidate 0.7.3 build), tree-sitter-swift-0.7.3/ (crate extract) +
tag-clone/ (0.7.3-with-generated-files) with the sha evidence.