feat(kernel): R7b Swift walker — swift module, tree-sitter-swift 0.7.3 bump, swift default-routed (#1381)

Fifth R7b batch-3 port, checklist-first recipe
(docs/design/swift-kernel-port-checklist.md, 1,056 lines — the largest of the
arc, with a built-extractor-validated emission pin and a childForFieldName
truth table).

Grammar bump first, validated standalone: tree-sitter-wasms ^0.4.0 (ABI 13) →
crate 0.7.3 — with a provenance twist: the wasm is built from the CRATE
TARBALL's src/ (alex-pinkus keeps generated files off main and the
0.7.3-with-generated-files tag ships an older ABI-14 generation that can never
sha-match; grammar.json rules are JSON-equal; the tarball is byte-for-byte
what the kernel's cargo build compiles — table identity by construction).
Older crates evaluated and rejected: clean-parse shapes are byte-identical on
0.7.3 (53-line CST battery diff, all inert), so an older pin buys nothing and
loses the macro-era wins. Delta = error-set membership (63 old-error files
parse clean: swift-testing #expect, #Preview/#GET macros, package access,
typed throws — vapor 23.1%→9.3%; 21 NEW-only regressions in 3 probed
construct classes) + two gate-found categories: docstring boundaries near #if
directives (7 clean files, docstring-field-only — verified mechanically) and
array-literal-callee call refs (2 refs, 1 file). Every hunk classified via
the error-union rule + parked-ref↔edge ripple pairing.

Walker (the arc's biggest) centers on the #1020 DEDICATED property branch:
computed properties → property nodes with the getter walked under the
property (SwiftUI body), static let/var → constant/variable, stored → field,
decorator/type-annotation/@Siblings-attr-arg refs all attached to the
ENCLOSING TYPE, stored initializer calls attributed to the class. Preserved
bug-for-bug: the never-resolving 'parameter' field (zero param type refs,
zero signatures), present-false isAsync, open→internal visibility,
everything-is-extends inheritance (first type_identifier per specifier), no
instantiates refs ever, subscript reads as `calls arr`, `defer` as `calls
defer`, multi-case enum entries minting only the first case, /** */ block
docs ignored AND chain-breaking, init/deinit/subscript minting no nodes with
visitNode-routed bodies (calls → class, static reads → nothing), multi-
segment extension resolveName, sugar extension names, the #selector shapes,
and the value_argument label-forward skip. ONE fix found by the sweep (then
pinned in the fixture + checklist): the shared `assignment` shadow-prune case
is swift-live — declared-then-assigned `let X: T` prunes X as a value-ref
target.

Gates: sweeps 0-diff Alamofire 89/98, vapor 224/247, swift-nio 407/554
(--max-deferral 0.3 — swift error incidence is 9–27% on BOTH arms,
structural; every deferral count matches the survey's table exactly);
full-init dumps byte-identical ×3 (31.9k/20.7k/126.3k lines); the Alamofire
census reproduces property=348 (the #1020 number) on the kernel arm;
kernel-swift-parity suite (206-line torture + CRLF + the #if-between-enum-
cases defer fixture) + swift grammar-parity row; full suite 2,626 green ×2
under CODEGRAPH_KERNEL_EXPECT=1. DEFAULT_ROUTED += swift (14 langs).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-07-20 17:09:12 -05:00
committed by GitHub
co-authored by Claude Fable 5
parent a6c62d77df
commit 09e301bbfa
16 changed files with 4185 additions and 6 deletions
+2 -1
View File
@@ -11,7 +11,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### New Features
- Indexing TypeScript, TSX, JavaScript, JSX, Java, Python, Go, C, C++, Rust, C#, Ruby, and PHP projects is faster: parsing and symbol extraction now run in a native engine when a prebuilt binary is available for your platform (release bundles include one), producing exactly the same graph — verified byte-for-byte against the previous engine on real repositories, from small libraries up to vscode-, dubbo-, django-, git-, protobuf-, tokio-, rust-analyzer-, jellyfin-, rails-, and symfony-scale codebases (Lombok-generated members, C function-pointer tables, and Unreal-Engine-style macro-heavy headers included; CUDA and Metal sources ride the C++ path). The speedup is largest on resource-constrained machines like CI runners. No setup needed: platforms without the native binary, and individual files with syntax errors, automatically use the previous engine, and `CODEGRAPH_KERNEL=0` turns the native path off entirely.
- Indexing TypeScript, TSX, JavaScript, JSX, Java, Python, Go, C, C++, Rust, C#, Ruby, PHP, and Swift projects is faster: parsing and symbol extraction now run in a native engine when a prebuilt binary is available for your platform (release bundles include one), producing exactly the same graph — verified byte-for-byte against the previous engine on real repositories, from small libraries up to vscode-, dubbo-, django-, git-, protobuf-, tokio-, rust-analyzer-, jellyfin-, rails-, symfony-, and swift-nio-scale codebases (Lombok-generated members, C function-pointer tables, and Unreal-Engine-style macro-heavy headers included; CUDA and Metal sources ride the C++ path). The speedup is largest on resource-constrained machines like CI runners. No setup needed: platforms without the native binary, and individual files with syntax errors, automatically use the previous engine, and `CODEGRAPH_KERNEL=0` turns the native path off entirely.
- Reference resolution now runs in parallel on large projects. When a project has enough pending references to make it worthwhile (roughly 150k+, typical for big Java/Kotlin/Spring codebases), resolution fans out across worker threads while results are applied in the exact order the single-threaded path would have used — the graph comes out byte-for-byte identical, about twice as fast end-to-end on a 4,000-file Java project in our testing. Small projects keep the single-threaded path automatically (the fan-out costs more than it saves there). Set `CODEGRAPH_NO_PARALLEL_RESOLVE=1` to disable, or `CODEGRAPH_PARALLEL_RESOLVE_MIN=<count>` to tune when it engages.
- Indexing large projects got another sizeable speedup — about a quarter less wall-clock on the same 4,000-file Java project, with the graph still byte-for-byte identical. Two changes: the database no longer interleaves expensive checkpoint housekeeping into the middle of resolution on a fresh index (it's folded once at the end instead), and while one batch's results are being written out, the worker threads are already resolving the next batch instead of sitting idle.
- The dynamic-dispatch analysis that runs at the end of indexing (callback, event, and framework wiring) now runs its passes in parallel on large projects, cutting that stage roughly in half there — and a pass that crashes now retries safely instead of failing the whole index, which also makes very large codebases that previously died in this stage more likely to index to completion. Graphs remain byte-for-byte identical.
@@ -31,6 +31,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Rust files also parse with an up-to-date grammar now (the previously bundled build dated from 2023), which additionally sharpens method-call attribution: calls through struct fields resolve with receiver context instead of falling back to ambiguous bare-name matching, removing a class of wrong call edges on common names like `len` and `start`.
- Ruby files also parse with an up-to-date grammar now (the previously bundled build dated from early 2024), which fixes a misparse of safe-navigation operator-method calls (`recv&.!= x`) that had recorded the wrong callee name.
- PHP files also parse with an up-to-date grammar now (the previously bundled build dated from 2023): files using modern PHP features — enum constants, PHP 8.4 property hooks, parenthesis-free `new X()->method()` chaining — no longer hit parse errors or misparses that dropped or garbled their symbols, so codebases like Symfony and Laravel index substantially more accurately.
- Swift files also parse with an up-to-date grammar now (the previously bundled build dated from 2023): swift-testing `#expect`, `#Preview`-style macros, the `package` access modifier, and typed `throws` no longer produce parse errors that dropped surrounding symbols — server-side Swift projects like Vapor see the biggest recovery.
- Searching or exploring by field names now finds the code that defines them. A query made of object keys or API field names (`profileInfo isTrialEligible quotaInfo billingMethod`) used to return unrelated results while the defining files never appeared, because three retrieval steps each dropped multi-word camelCase terms: an internal case-comparison bug, a match step that only considered classes (never functions or methods), and exploration seeding that required exact symbol-name matches. All three are fixed — `codegraph_explore` with a bag of field names now surfaces the controllers and services that assemble those fields. (#1196)
- `codegraph.json`'s `includeIgnored` works again for the "folder of repos" layout: when one `.gitignore` rule covers a parent directory (`/repos/`) holding several embedded git repositories, opting in the individual repos (`"includeIgnored": ["repos/a/"]` — the exact spelling `codegraph init`'s own hint suggests) previously matched nothing and indexed zero files, looping the same suggestion back at you. Both spellings now work — name the parent directory to opt in everything under it, or name individual repos to opt in just those — and the hint no longer re-suggests repos that are already configured. (#1295)
- Method calls on literals (`", ".join(...)` in Python, `"x".split(...)` in JavaScript, and the like) no longer produce call edges to unrelated project functions that happen to share the builtin's name — a codebase with a function called `join`, `get`, or `update` could show phantom callers from every string-builtin use. Additionally, a function nested inside another function is now only matched as a call target from inside its container, since it isn't reachable from anywhere else. Blast-radius and affected-test results get cleaner on Python and JavaScript codebases especially. (#1230)
@@ -0,0 +1,206 @@
import Foundation
import UIKit.UIView
/// Class doc line one
/// Class doc line two
public final class Session: NSObject, RequestDelegate {
let rootQueue: DispatchQueue = DispatchQueue(label: "root")
var mutable = 0
static let SHARED_MAX: Int = 5
static var counter = 0
lazy var expensive: Cache = Cache.build()
@Published private var wrapped: Bool = false
weak var delegate: SessionDelegate?
var observed: Int = 0 {
willSet { prepare(newValue) }
didSet { react(oldValue) }
}
var isCloudProxy: Bool { return check(SHARED_MAX) }
open class func classFunc() {}
/// method doc
public func request(_ convertible: URLConvertible, method: HTTPMethod) -> DataRequest {
let req = DataRequest.make().validate()
let m = HTTPMethod.get
let g = Session.SHARED_MAX
self.own()
super.retain()
rootQueue.async { self.perform(req) }
return req
}
init(raw: String) {
self.raw = raw
setupMonitor()
}
deinit { cleanup() }
subscript(index: Int) -> Foo { get { store[index] } set { store[index] = newValue } }
}
struct HTTPMethod: RawRepresentable, Equatable {
let rawValue: String
static let get = HTTPMethod(rawValue: "GET")
}
enum AFError: Error, CustomStringConvertible {
case invalidURL(url: URLConvertible)
case explicitlyCancelled, sessionDeinitialized
indirect case wrapped(AFError)
var description: String { renderDescription() }
static func make() -> AFError { .explicitlyCancelled }
}
protocol RequestDelegate: AnyObject {
var sessionState: Int { get }
func didFinish(_ request: Request)
static func build() -> Self
}
extension Session: EventMonitor {
func heard(event: Event) { record(event) }
}
extension KF.Builder {
func done() -> KF.Builder { self }
}
extension Array where Element: Equatable {
func dedup() -> [Element] { self }
}
actor Counter {
var n = 0
func bump() { n += 1 }
}
typealias Handler = (Data) -> Void
typealias BuilderAlias = KF.Builder
let TOP_LEVEL_MAX = 3
var topVar: Int = compute()
func freeFn(a: Int, cb: @escaping (Int) -> Void) -> Session? {
helper()
Foo()
obj.method(1)
a.b.deep()
x?.optCall()
y!.forced()
Foo.make().draw()
foo.bar().baz()
"lit".upper()
arr.map { $0.name }
let tbl = [cbA, cbB]
o.cb = handler
reg2(onFire)
forward(value: value)
let sel = #selector(Holder.fire)
defer { cleanup() }
let d = dict["k"]
return nil
}
func onFire() {}
func handler() {}
func cbA() {}
func cbB() {}
// ---- extension rows (checklist inventory) ----
// non-ASCII line before a symbol: café ünïcode 😀
@objc enum Suit: Int {
case hearts = 1
case spades
}
@main struct MainApp {
var body: some View { VStack { Text(label) } }
}
/** block doc is IGNORED and breaks the chain */
func blockDoc() {}
/// kept over attribute
@objc func attributed() {}
func <+> (lhs: Session, rhs: Session) -> Session { lhs }
public class Visi {
public private(set) var setterGated = 1
static let A_B: Int = 2
let (tup, tup2) = makePair()
@Siblings(through: Pivot.self, from: \.$left) var siblings: [Tag]
}
protocol Inherited: AnyObject, Identifiable {
var reqComputed: String { get set }
static var reqStatic: Int { get }
}
extension [ServerTrustEvaluating] {
func sugarExt() {}
}
func voidParamProof(cb: (Void) -> Void) -> Result<Foo, Err> {
callMe()
return .success(Foo())
}
func nestedGenericRet() -> Result<Array<Foo>, Err> { fail() }
func voidRet() -> Void { noop() }
func tupleRet() -> (Int, Foo) { (1, Foo()) }
func fnRet() -> (Int) -> Foo { { _ in Foo() } }
func optRet() -> Session? { nil }
func builderRet() -> KF.Builder { KF.Builder() }
func callZooExtra(m: [[Int]], arr: [Int], f: () -> Void) {
Foo.init(raw: "x")
"""
multi
""".trimmed()
["k": 1].lookup()
(f)()
arr[0]
m[1][2]
.make()
try? thrower()
Task { await asyncFn() }
let msg = "count \(counter.next())"
#warning("torture warning")
}
func staticReads(u: User) {
let c = Color.red
let r = Suit.hearts.rawValue
let s = UserModel.self
let d = Deep.Nested.leaf
let i = lowercase.field
let k = \Foo.bar
}
#if os(iOS)
func insideDirective() { directiveCall() }
#endif
// declared-then-assigned: the assignment-prune case (kernel-sweep-caught)
// laterAssigned MUST be pruned as a value-ref target.
let laterAssigned: Int
if TOP_LEVEL_MAX > 2 {
laterAssigned = 1
} else {
laterAssigned = 2
}
let readsLater = laterAssigned + TOP_LEVEL_MAX
func guardNoPrune() {
guard let TOP_LEVEL_MAX = optSource() else { return }
use(TOP_LEVEL_MAX)
}
func fnRefExtras() {
reg(cb: onFire)
let sel1 = #selector(fire)
let sel2 = #selector(onNote(_:))
self.x = x
}
import class Darwin.FILE
@testable import TortureKit
+1 -1
View File
@@ -36,7 +36,7 @@ const kernelBuilt = fs.existsSync(KERNEL_PATH);
// Every kernel-capable language. `jsx` shares the javascript grammar on BOTH
// paths (langs.rs mirrors WASM_GRAMMAR_FILES), so the distinct grammars are:
const GRAMMAR_LANGUAGES: Language[] = ['typescript', 'tsx', 'javascript', 'java', 'python', 'go', 'c', 'cpp', 'rust', 'csharp', 'ruby', 'php'];
const GRAMMAR_LANGUAGES: Language[] = ['typescript', 'tsx', 'javascript', 'java', 'python', 'go', 'c', 'cpp', 'rust', 'csharp', 'ruby', 'php', 'swift'];
describe.skipIf(!kernelBuilt)('kernel↔wasm grammar parity', () => {
beforeAll(async () => {
+127
View File
@@ -0,0 +1,127 @@
/**
* Kernelwasm Swift extraction parity (R7b of the kernel migration).
*
* Asserts the native walker (codegraph-kernel/src/swift.rs) produces the SAME
* ExtractionResult as the wasm TreeSitterExtractor nodes, edges, and
* unresolved refs compared as canonicalized multisets over the checked-in
* torture fixture (torture.swift: the DEDICATED in-class property branch
* (#1020 computedproperty with getter walk, static let/var→constant/
* variable, storedfield, owner-attributed decorator/type/attr-arg refs,
* observed-property field + class-attributed observer calls), extensions
* (multi-segment resolveName, sugar `[Proto]` names, where-clauses),
* everything-is-extends inheritance, the full call matrix (subscript reads,
* `defer`, optional-chaining receivers, #750 re-encode, literal-set
* membership quirks, implicit members), positional return types with the
* nested-generic failure, present-false isAsync, `open`internal visibility,
* multi-case enum first-only minting, `/** */` docs ignored-and-chain-
* breaking, value-ref targets incl. the declared-then-assigned
* assignment-prune case the swift-nio sweep caught, SWIFT_SPEC fn-refs with
* the label-forward skip and #selector shapes) and its CRLF variant (derived
* in-memory #1329).
*
* The full-repo sweep lives in scripts/kernel-parity.mjs (Alamofire/vapor/
* swift-nio, --max-deferral 0.3 swift error incidence is structurally
* 927% on BOTH arms); this suite keeps the invariant alive in `npm test`.
* Skips when no kernel binary is staged; CODEGRAPH_KERNEL_EXPECT=1 turns
* that into a failure (kernel-scaffold.test.ts).
*/
import { describe, it, expect, beforeAll, beforeEach, afterEach } from 'vitest';
import * as fs from 'fs';
import * as path from 'path';
import { extractFromSource } from '../src/extraction';
import { initGrammars, loadGrammarsForLanguages } from '../src/extraction/grammars';
import { tryKernelExtract, resetKernelForTests } from '../src/extraction/kernel';
import type { ExtractionResult } from '../src/types';
const KERNEL_PATH = path.join(
__dirname,
'..',
'codegraph-kernel',
'prebuilds',
`${process.platform}-${process.arch}`,
'codegraph-kernel.node'
);
const kernelBuilt = fs.existsSync(KERNEL_PATH);
const FIXTURE_DIR = path.join(__dirname, 'fixtures', 'kernel-parity');
function canon(result: ExtractionResult): { nodes: string[]; edges: string[]; refs: string[] } {
return {
nodes: result.nodes
.map(({ updatedAt: _u, ...n }) => JSON.stringify(n, Object.keys(n).sort()))
.sort(),
edges: result.edges.map((e) => JSON.stringify(e, Object.keys(e).sort())).sort(),
refs: result.unresolvedReferences
.map((r) => JSON.stringify(r, Object.keys(r).sort()))
.sort(),
};
}
const ENV_KEYS = ['CODEGRAPH_KERNEL', 'CODEGRAPH_KERNEL_LANGS'] as const;
let savedEnv: Record<string, string | undefined>;
describe.skipIf(!kernelBuilt)('kernel Swift extraction parity', () => {
beforeAll(async () => {
await initGrammars();
await loadGrammarsForLanguages(['swift']);
});
beforeEach(() => {
savedEnv = Object.fromEntries(ENV_KEYS.map((k) => [k, process.env[k]]));
resetKernelForTests();
});
afterEach(() => {
for (const k of ENV_KEYS) {
if (savedEnv[k] === undefined) delete process.env[k];
else process.env[k] = savedEnv[k];
}
resetKernelForTests();
});
function assertParity(filePath: string, source: string, minNodes = 3): void {
process.env.CODEGRAPH_KERNEL_LANGS = 'all';
delete process.env.CODEGRAPH_KERNEL;
const viaKernel = tryKernelExtract(filePath, source, 'swift');
expect(viaKernel, `kernel extraction failed for ${filePath}`).not.toBeNull();
process.env.CODEGRAPH_KERNEL = '0';
const viaWasm = extractFromSource(filePath, source, 'swift');
delete process.env.CODEGRAPH_KERNEL;
const k = canon(viaKernel!);
const w = canon(viaWasm);
expect(k.nodes, `${filePath}: nodes`).toEqual(w.nodes);
expect(k.edges, `${filePath}: edges`).toEqual(w.edges);
expect(k.refs, `${filePath}: refs`).toEqual(w.refs);
expect(viaWasm.nodes.length).toBeGreaterThanOrEqual(minNodes);
}
it('torture fixture: property branch, extensions, call matrix, value refs, fn-refs', () => {
const file = path.join(FIXTURE_DIR, 'torture.swift');
assertParity('fixtures/torture.swift', fs.readFileSync(file, 'utf8'), 40);
});
// CRLF variant — the shape every Windows autocrlf checkout has. Derived in
// memory so no platform or editor can silently normalize it away; pins the
// JS-multiline-^ docstring semantics for `///` runs (#1329).
it('torture fixture CRLF parity', () => {
const file = path.join(FIXTURE_DIR, 'torture.swift');
const crlf = fs.readFileSync(file, 'utf8').replace(/(?<!\r)\n/g, '\r\n');
assertParity('fixtures/torture.swift (crlf)', crlf, 40);
});
it('files with parse errors defer to the wasm extractor (recovery is encoding-dependent)', () => {
// A NEW-only regression construct (`#if` between enum cases — the swift
// checklist's grammar-bump delta 5) — errors on the 0.7.3 grammar.
const broken = 'enum E {\n case a\n#if DEBUG\n case b\n#endif\n}\n';
process.env.CODEGRAPH_KERNEL_LANGS = 'all';
delete process.env.CODEGRAPH_KERNEL;
expect(tryKernelExtract('src/Broken.swift', broken, 'swift')).toBeNull();
process.env.CODEGRAPH_KERNEL = '0';
const viaWasm = extractFromSource('src/Broken.swift', broken, 'swift');
delete process.env.CODEGRAPH_KERNEL;
expect(viaWasm.nodes.some((n) => n.kind === 'file')).toBe(true);
});
});
+11
View File
@@ -62,6 +62,7 @@ dependencies = [
"tree-sitter-python",
"tree-sitter-ruby",
"tree-sitter-rust",
"tree-sitter-swift",
"tree-sitter-typescript",
]
@@ -594,6 +595,16 @@ dependencies = [
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-swift"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe36052155b9dd69ca82b3b8f1b4ccfb2d867125ac1a4db1dd7331829242668c"
dependencies = [
"cc",
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-typescript"
version = "0.23.2"
+5
View File
@@ -41,6 +41,11 @@ tree-sitter-ruby = "=0.23.1"
# php: the walker calls LANGUAGE_PHP (the full HTML-interleaving variant the
# wasm ships) — NEVER LANGUAGE_PHP_ONLY, which errors on leading HTML.
tree-sitter-php = "=0.24.2"
# swift: the vendored wasm is built from THIS crate's tarball src/ (the tag's
# checked-in parser.c is an older ABI-14 generation that can never sha-match;
# grammar.json rules are JSON-equal — swift checklist header). parser.c is
# ~20MB generated — expect slow compiles.
tree-sitter-swift = "=0.7.3"
[build-dependencies]
napi-build = "2"
+5 -2
View File
@@ -15,9 +15,9 @@ use tree_sitter::Language;
/// Languages this kernel binary can extract (reported by contractInfo;
/// TS-side routing policy decides what actually routes).
pub const LANGUAGES: [&str; 13] = [
pub const LANGUAGES: [&str; 14] = [
"typescript", "tsx", "javascript", "jsx", "java", "python", "go", "c", "cpp", "rust",
"csharp", "ruby", "php",
"csharp", "ruby", "php", "swift",
];
pub fn grammar_for(language: &str) -> Option<Language> {
@@ -44,6 +44,9 @@ pub fn grammar_for(language: &str) -> Option<Language> {
// R7b: v0.24.2, the full HTML-interleaving variant — LANGUAGE_PHP,
// NEVER LANGUAGE_PHP_ONLY (which errors on leading HTML).
"php" => Some(tree_sitter_php::LANGUAGE_PHP.into()),
// R7b: crate 0.7.3 — the vendored wasm is built from this crate's own
// tarball src/ (table identity by construction; see grammars.ts).
"swift" => Some(tree_sitter_swift::LANGUAGE.into()),
_ => None,
}
}
+2
View File
@@ -28,6 +28,7 @@ mod langs;
mod php;
mod ruby;
mod rustlang;
mod swift;
mod textutil;
mod python;
mod tsjs;
@@ -219,6 +220,7 @@ pub fn extract_file(file_path: String, content: String, language: String) -> Res
"csharp" => csharp::extract(&file_path, &content).map_err(Error::from_reason)?,
"ruby" => ruby::extract(&file_path, &content).map_err(Error::from_reason)?,
"php" => php::extract(&file_path, &content).map_err(Error::from_reason)?,
"swift" => swift::extract(&file_path, &content).map_err(Error::from_reason)?,
_ => tsjs::extract(&file_path, &content, &language).map_err(Error::from_reason)?,
};
Ok(ExtractBuffers {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -610,7 +610,7 @@ parity before porting the language.
| rust | `languages/rust.ts` | T1 | crates.io | **DONE (R7b #1, 2026-07-20)**`rustlang.rs` walker; grammar bumped to v0.24.2 (crate + vendored wasm together). Parity 0-diff on ripgrep/tokio/rust-analyzer + dump byte-identical ×3; rust-analyzer's parser crates defer 18% (token-macro tables, both-arm parse errors — grammar-inherent). Quirk list: docs/design/rust-lang-kernel-port-checklist.md. | ☑ |
| dart, scala, lua, luau, r | dedicated files | T1 | crates.io (luau/r/scala: verify crate freshness vs our wasm) | Long-tail T1; port opportunistically after the big five. | ☐ |
| kotlin | `languages/kotlin.ts` | T1½ | crates.io | Expect/actual pairing is synthesis-side (fine); extraction is clean but validate against a KMP repo. | ☐ |
| swift | shared + dedicated branch | T1½ | crates.io | **Trap:** in-class property extraction lives in `tree-sitter.ts`'s DEDICATED branch, not `swift.ts` (#1020 — Alamofire went 0→348 props). Gate on Alamofire. | |
| swift | shared + dedicated branch | T1½ | crates.io | **DONE (R7b #5, 2026-07-20)**`swift.rs` walker incl. the #1020 dedicated property branch (Alamofire's 348 property nodes reproduced exactly on the kernel arm); grammar bumped to crate 0.7.3 (wasm built from the CRATE TARBALL's src — the tag ships an older ABI-14 generation; delta = error-set membership + 2 gate-found categories, all classified). Parity 0-diff Alamofire/vapor/swift-nio (720 clean files; deferral 927% both-arm structural — sweeps use --max-deferral 0.3). One walker fix found by the sweep: the shared `assignment` shadow-prune case is swift-live (declared-then-assigned `let X: T`). Quirk list: docs/design/swift-kernel-port-checklist.md. | |
| c, cpp | `languages/c-cpp.ts` | **T2** | crates.io | **DONE (R7a, 2026-07-17)**`ccpp/` walker; ALL pre-passes stayed TS-side via the route-point preParse hoist (+6 new blanks added during gating — see the checklist doc); content-based `.h` C-vs-C++ detection stays upstream at detectLanguage. Parity 0-diff + dump byte-identical on redis/git/fmt/protobuf/ALS. | ☑ |
| metal, cuda | dialects over the cpp grammar | **T2** (rides c/cpp) | crates.io (cpp) | **DONE (rides R7a)**`.metal`/`.cu`/`.cuh` map to 'cpp' and their blanks run in the hoisted preParse (filePath rides along for the extension gates); hoist-parity pinned in kernel-ccpp-parity.test.ts + the metal/cuda suites. | ☑ |
| objc | `languages/objc.ts` | T2 | crates.io | Rides the c-cpp trap family; RN bridge extraction feeds `rnCrossPlatformEdges` (synthesis-side, fine). | ☐ |
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -48,7 +48,7 @@ if (paths.length === 0) {
process.exit(2);
}
const KERNEL_LANGS = new Set(['typescript', 'tsx', 'javascript', 'jsx', 'java', 'python', 'go', 'c', 'cpp', 'rust', 'csharp', 'ruby', 'php']);
const KERNEL_LANGS = new Set(['typescript', 'tsx', 'javascript', 'jsx', 'java', 'python', 'go', 'c', 'cpp', 'rust', 'csharp', 'ruby', 'php', 'swift']);
const EXTS = new Map([
['.ts', 'typescript'], ['.mts', 'typescript'], ['.cts', 'typescript'],
['.tsx', 'tsx'], ['.js', 'javascript'], ['.mjs', 'javascript'],
@@ -62,6 +62,7 @@ const EXTS = new Map([
['.cs', 'csharp'], // R7b
['.rb', 'ruby'], ['.rake', 'ruby'], // R7b
['.php', 'php'], ['.module', 'php'], ['.install', 'php'], ['.theme', 'php'], ['.inc', 'php'], // R7b
['.swift', 'swift'], // R7b
]);
/** Collect candidate files. */
+9
View File
@@ -313,6 +313,15 @@ const VENDORED_WASM_LANGS: ReadonlySet<GrammarLanguage> = new Set([
// tarball. Replaces the ^0.22 tree-sitter-wasms build (ABI 14 → 15). NOT
// graph-neutral — the classified delta list lives in the php checklist doc.
'php',
// R7b (Swift kernel port prep): tree-sitter-swift crate 0.7.3. Built from
// the CRATE TARBALL's src/ (NOT a tag sha-match: alex-pinkus keeps
// generated files off main and the 0.7.3-with-generated-files tag ships an
// older ABI-14 generation; grammar.json rules are JSON-equal, and the crate
// tarball is byte-for-byte what the kernel's cargo build compiles — table
// identity by construction). Replaces the ^0.4.0 tree-sitter-wasms build
// (ABI 13 → 15). NOT graph-neutral — delta is error-set membership only;
// classified list in the swift checklist doc.
'swift',
]);
/** Absolute path of a language's grammar WASM (vendored or tree-sitter-wasms). */
+6
View File
@@ -68,6 +68,12 @@ const DEFAULT_ROUTED: ReadonlySet<Language> = new Set<Language>([
// symfony (13,950 files byte-parity) + full-init dump-diffs byte-identical
// ×3. Deferral ≈00.1% (genuinely-broken fixtures) — default sweep guard.
'php',
// R7b (2026-07-20): parity swept 0-diff on Alamofire/vapor/swift-nio (720
// clean files byte-parity; Alamofire's 348 #1020 property nodes reproduced
// exactly) + full-init dump-diffs byte-identical ×3. Swift error incidence
// is structurally 927% on BOTH arms (heavy #if conditionalization) —
// sweeps run --max-deferral 0.3; a deferral-rate JUMP is the bug signal.
'swift',
]);
/**
Binary file not shown.