unified: Port import rules to swift-syntax

Retarget imports to the swift-syntax AST, output unchanged. swift-syntax
represents the dotted path as a list of `importPathComponent`s, folded
into a `name_expr`/`member_access_expr` chain via `member_chain`. A
single rule handles both forms via an optional `importKindSpecifier`: a
scoped import (`import struct Foo.Bar`) has one and binds the last path
component as a `name_pattern`; a plain import (`import Foundation`) has
none and uses a `bulk_importing_pattern`. Leading attributes
(`@_exported`) and access modifiers (`public`) become `modifier`s.

The tree-sitter multi-part `identifier` rule is dropped: swift-syntax
qualified names are already `memberAccessExpr` chains, and import paths
are `importPathComponent`s.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Taus
2026-07-20 13:49:55 +00:00
parent 6275977bc5
commit 37654b4bcc

View File

@@ -911,35 +911,37 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// `forceUnwrapExpr` node (the tree-sitter path used the generic postfix
// operator rule instead).
rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})),
// A multi-part identifier (for example `Foo.Bar.Baz`) is translated to
// a member_access_expr chain with a name_expr base.
// ---- Imports ----
// An import declaration. The dotted path (a list of
// `importPathComponent`s) becomes a `name_expr`/`member_access_expr`
// chain (via `member_chain`). A scoped import (`import struct Foo.Bar`)
// has an `importKindSpecifier` and binds the last path component as a
// `name_pattern`; a plain import (`import Foundation`) has none and uses
// a `bulk_importing_pattern` spanning the whole declaration. Any leading
// attributes (`@_exported`) and access modifiers (`public`) become
// `modifier`s.
rule!(
(identifier part: _+ @parts)
(importDecl
attributes: _* @attrs
modifiers: _* @mods
importKindSpecifier: _? @@kind
path: (importPathComponent name: @@parts)*)
=>
expr { member_chain(&mut ctx, parts) }
),
// Scoped import declaration (for example `import struct Foo.Bar`):
// flatten the identifier parts into a member_access_expr and bind the
// final segment as a name_pattern.
rule!(
(import_declaration scoped_import_kind: @kind name: (identifier part: _+ @parts) @name modifiers: (modifiers)? @mods)
=>
(import_declaration
pattern: (name_pattern identifier: (identifier #{parts.last().unwrap()}))
imported_expr: {name}
modifier: (modifier #{kind})
modifier: {mods})
),
// Non-scoped import declaration (for example `import Foundation`):
// flatten the identifier parts into a member_access_expr and use a
// bulk_importing_pattern.
rule!(
(import_declaration name: @name modifiers: (modifiers)? @mods)
=>
(import_declaration
pattern: (bulk_importing_pattern)
imported_expr: {name}
modifier: {mods})
import_declaration {
let pattern = match kind {
Some(_) => {
let last = *parts.last().ok_or("import has no path")?;
tree!((name_pattern identifier: (identifier #{last})))
}
None => tree!((bulk_importing_pattern)),
};
tree!((import_declaration
modifier: {kind.map(|k| tree!((modifier #{k})))}
modifier: {attrs}
modifier: {mods}
pattern: {pattern}
imported_expr: {member_chain(&mut ctx, parts)}))
}
),
// ---- Types and classes ----
// Self expression → name_expr