unified: Port type-expression rules to swift-syntax

Retarget type expressions to the swift-syntax AST, output unchanged:

- `user_type` -> `identifierType` (its `name` is the type-name token).
- The sugared types keep desugaring to `generic_type_expr`:
  `optionalType` -> Optional<T>, `arrayType` -> Array<T>,
  `dictionaryType` -> Dictionary<K, V>.
- A generic type with explicit arguments (`Set<Int>`) stays opaque (its
  whole source text as the name), matched before the plain
  `identifierType` rule.
  This matches the tree-sitter `user_type` rule, which was also opaque.
- Tuple types (`(Int, String)`) -> `tuple_type_expr` and function types
  (`(Int) -> Bool`) -> `function_type_expr`. swift-syntax holds both as
  `tupleTypeElement`s but a tuple element maps to `tuple_type_element`
   while a function parameter maps to `parameter`; the containers set
  `SwiftContext::in_function_type` for their direct children so the
  shared `tupleTypeElement` rule emits the right kind (and nested types
  stay correct).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Taus
2026-07-17 15:36:03 +00:00
parent 437e48239b
commit 191fc542ba

View File

@@ -37,6 +37,14 @@ struct SwiftContext {
/// `chained_declaration` modifier so the original grouping can be
/// recovered downstream.
is_chained: bool,
/// True while translating the parameters of a `functionType`. swift-syntax
/// models a function type's parameters with the same `tupleTypeElement`
/// kind as a tuple type's elements, so the shared `tupleTypeElement` rule
/// reads this to emit a `parameter` (function-type param) rather than a
/// `tuple_type_element` (tuple-type element). The `tupleType` /
/// `functionType` rules each set it for their direct children, so nested
/// types are translated in the correct context.
in_function_type: bool,
}
impl SwiftContext {
@@ -920,32 +928,83 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
rule!((parameter_modifier) @m => (modifier #{m})),
rule!((inheritance_modifier) @m => (modifier #{m})),
rule!((property_behavior_modifier) @m => (modifier #{m})),
// Type annotations — unwrap
rule!((type_annotation type: @inner) => type_expr { inner }),
// user_type is split into simple_user_type parts.
// Keep a conservative textual fallback to avoid dropping type information.
rule!((user_type) @ty => (named_type_expr name: (identifier #{ty}))),
// Tuple type → tuple_type_expr
rule!((tuple_type element: _* @elems) => (tuple_type_expr element: {elems})),
rule!((tuple_type_item name: @name type: @ty) => (tuple_type_element name: (identifier #{name}) type: {ty})),
rule!((tuple_type_item type: @ty) => (tuple_type_element type: {ty})),
// Array type `[T]` → generic_type_expr with Array base
rule!((array_type element: @e) => (generic_type_expr
base: (named_type_expr name: (identifier "Array"))
type_argument: {e})),
// Dictionary type `[K: V]` → generic_type_expr with Dictionary base
rule!((dictionary_type key: @k value: @v) => (generic_type_expr
base: (named_type_expr name: (identifier "Dictionary"))
type_argument: {k}
type_argument: {v})),
// Optional type `T?` → generic_type_expr with Optional base
rule!((optional_type wrapped: @w) => (generic_type_expr
base: (named_type_expr name: (identifier "Optional"))
type_argument: {w})),
// Function type `(Params) -> Ret` → function_type_expr.
rule!((function_type parameter: _* @ps return_type: @ret) => (function_type_expr parameter: {ps} return_type: {ret})),
rule!((function_type_parameter name: @name type: @ty) => (parameter external_name: (identifier #{name}) type: {ty})),
rule!((function_type_parameter type: @ty) => (parameter type: {ty})),
// Type expressions. A generic type applied with explicit arguments
// (`Set<Int>`) is represented opaquely, using the whole source text as
// the name (PARITY(tree-sitter): the generic arguments are not
// structured `type_argument`s). Matched before the plain `identifierType`
// rule, which would otherwise drop the arguments.
rule!(
(identifierType genericArgumentClause: (genericArgumentClause)) @@ty
=>
(named_type_expr name: (identifier #{ty}))
),
// A named type (`Int`). `identifierType.name` is the type-name token.
rule!((identifierType name: @@n) => (named_type_expr name: (identifier #{n}))),
// A qualified type (`Outer.Inner`, `NSString.CompareOptions`). swift-syntax
// nests these as `memberType` nodes; like the old tree-sitter `user_type`
// rule, we keep the whole dotted path as the opaque `named_type_expr` name.
rule!((memberType) @ty => (named_type_expr name: (identifier #{ty}))),
// Sugared types desugar to `generic_type_expr`: `T?` -> Optional<T>,
// `[T]` -> Array<T>, `[K: V]` -> Dictionary<K, V>.
rule!(
(optionalType wrappedType: @w)
=>
(generic_type_expr base: (named_type_expr name: (identifier "Optional")) type_argument: {w})
),
rule!(
(arrayType element: @e)
=>
(generic_type_expr base: (named_type_expr name: (identifier "Array")) type_argument: {e})
),
rule!(
(dictionaryType key: @k value: @v)
=>
(generic_type_expr base: (named_type_expr name: (identifier "Dictionary")) type_argument: {k} type_argument: {v})
),
// A tuple type (`(Int, String)`) or function type (`(Int) -> Bool`).
// Both hold their contents as `tupleTypeElement`s, but a tuple element
// maps to `tuple_type_element` while a function parameter maps to
// `parameter`. Each container sets `ctx.in_function_type` for its direct
// children (and translates them explicitly, so a nested type is
// translated in the right context) and the shared `tupleTypeElement`
// rule below reads it. An element's label (`firstName`) is optional.
rule!(
(tupleType elements: _* @@elems)
=>
tuple_type_expr {
ctx.in_function_type = false;
let mut out = Vec::new();
for e in elems {
out.extend(ctx.translate(e)?);
}
tree!((tuple_type_expr element: {out}))
}
),
rule!(
(functionType parameters: _* @@params returnClause: (returnClause type: @ret))
=>
function_type_expr {
ctx.in_function_type = true;
let mut out = Vec::new();
for p in params {
out.extend(ctx.translate(p)?);
}
ctx.in_function_type = false;
tree!((function_type_expr parameter: {out} return_type: {ret}))
}
),
rule!(
(tupleTypeElement firstName: _? @@name type: @ty)
=>
tuple_type_element {
let name = name.map(|n| tree!((identifier #{n})));
if ctx.in_function_type {
tree!((parameter external_name: {name} type: {ty}))
} else {
tree!((tuple_type_element name: {name} type: {ty}))
}
}
),
// Selector expression: `#selector(inner)` -- not yet supported
rule!(
(selector_expression _ @inner)