diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 5e4a7df6b92..26ec4c1b0ee 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -665,6 +665,274 @@ fn translation_rules() -> Vec { imported_expr: {name} modifier: {..mods}) ), + // ---- Types and classes ---- + // Self expression → name_expr + rule!((self_expression) => (name_expr identifier: (identifier "self"))), + // Super expression → super_expr + rule!((super_expression) => (super_expr)), + // Modifiers — unwrap to individual modifier children + rule!((modifiers _* @mods) => {..mods}), + rule!((attribute) @m => (modifier #{m})), + rule!((visibility_modifier) @m => (modifier #{m})), + rule!((function_modifier) @m => (modifier #{m})), + rule!((member_modifier) @m => (modifier #{m})), + rule!((mutation_modifier) @m => (modifier #{m})), + rule!((ownership_modifier) @m => (modifier #{m})), + rule!((property_modifier) @m => (modifier #{m})), + 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) => {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})), + // Selector expression: `#selector(inner)` -- not yet supported + rule!( + (selector_expression _ @inner) + => + (unsupported_node) + ), + // Key path expressions are currently unsupported. + rule!((key_path_expression) => (unsupported_node)), + // Inheritance specifier → base_type + rule!((inheritance_specifier inherits_from: @ty) => (base_type type: {ty})), + // Class declaration with body containing members + rule!( + (class_declaration + declaration_kind: @kind + name: @name + body: (class_body member: _* @members) + (inheritance_specifier)* @bases + (modifiers)* @mods) + => + (class_like_declaration + modifier: (modifier #{kind}) + modifier: {..mods} + name: (identifier #{name}) + base_type: {..bases} + member: {..members}) + ), + // Enum class declaration: same as a regular class but with an enum body. + rule!( + (class_declaration + declaration_kind: @kind + name: @name + body: (enum_class_body member: _* @members) + (inheritance_specifier)* @bases + (modifiers)* @mods) + => + (class_like_declaration + modifier: (modifier #{kind}) + modifier: {..mods} + name: (identifier #{name}) + base_type: {..bases} + member: {..members}) + ), + // Class declaration with empty body + rule!( + (class_declaration + declaration_kind: @kind + name: @name + body: _ + (inheritance_specifier)* @bases + (modifiers)* @mods) + => + (class_like_declaration + modifier: (modifier #{kind}) + modifier: {..mods} + name: (identifier #{name}) + base_type: {..bases}) + ), + // Protocol declaration + rule!( + (protocol_declaration + name: @name + body: (protocol_body member: _* @members) + (inheritance_specifier)* @bases + (modifiers)* @mods) + => + (class_like_declaration + modifier: (modifier "protocol") + modifier: {..mods} + name: (identifier #{name}) + base_type: {..bases} + member: {..members}) + ), + // Protocol function — return type and body statements both optional. + rule!( + (protocol_function_declaration + name: @name + (parameter)* @params + return_type: _? @ret + body: (block statement: _* @body_stmts)? + (modifiers)* @mods) + => + (function_declaration + modifier: {..mods} + name: (identifier #{name}) + parameter: {..params} + return_type: {..ret} + body: (block stmt: {..body_stmts})) + ), + // Init declaration → constructor_declaration. Body statements optional; + // body itself is also optional (protocol requirement). + rule!( + (init_declaration + (parameter)* @params + body: (block statement: _* @body_stmts)? + (modifiers)* @mods) + => + (constructor_declaration + modifier: {..mods} + parameter: {..params} + body: (block stmt: {..body_stmts})) + ), + // Deinit declaration → destructor_declaration. Body statements optional. + rule!( + (deinit_declaration + body: (block statement: _* @body_stmts) + (modifiers)* @mods) + => + (destructor_declaration + modifier: {..mods} + body: (block stmt: {..body_stmts})) + ), + // Typealias declaration + rule!( + (typealias_declaration name: @name value: @val (modifiers)* @mods) + => + (type_alias_declaration + modifier: {..mods} + name: (identifier #{name}) + r#type: {val}) + ), + // Subscript declaration (not yet supported -- grammar needs to distinguish plain calls from subscript calls) + rule!( + (subscript_declaration (parameter)* @params (modifiers)* @mods) + => + (unsupported_node) + ), + // Associated type declaration (with optional bound) + rule!( + (associatedtype_declaration name: @name inherits_from: _? @bound (modifiers)* @mods) + => + (associated_type_declaration + modifier: {..mods} + name: (identifier #{name}) + bound: {..bound}) + ), + // Protocol property declaration: translate each accessor requirement to an + // accessor_declaration without a body, carrying the property name and type. + // Subsequent accessors get chained_declaration (same flattening as computed properties). + rule!( + (protocol_property_declaration + name: @pattern + requirements: (protocol_property_requirements accessor: _+ @accessors) + type: _? @ty + (modifiers)* @mods) + => + {..{ + let name_text = __yeast_ctx.ast.source_text(pattern.into()); + let mod_ids: Vec = mods.iter().map(|&m| m.into()).collect(); + let ty_ids: Vec = ty.iter().map(|&t| t.into()).collect(); + let acc_ids: Vec = accessors.iter().map(|&a| a.into()).collect(); + for (i, &acc_id) in acc_ids.iter().enumerate() { + if i > 0 { + let chained = __yeast_ctx.literal("modifier", "chained_declaration"); + __yeast_ctx.prepend_field(acc_id, "modifier", chained); + } + for &mod_id in mod_ids.iter().rev() { + __yeast_ctx.prepend_field(acc_id, "modifier", mod_id); + } + for &ty_id in ty_ids.iter().rev() { + __yeast_ctx.prepend_field(acc_id, "type", ty_id); + } + let ident = __yeast_ctx.literal("identifier", &name_text); + __yeast_ctx.prepend_field(acc_id, "name", ident); + } + acc_ids + }} + ), + // getter_specifier / setter_specifier → bodyless accessor_declaration + rule!((getter_specifier) => (accessor_declaration accessor_kind: (accessor_kind "get"))), + rule!((setter_specifier) => (accessor_declaration accessor_kind: (accessor_kind "set"))), + // protocol_property_requirements wrapper — should be consumed by above; fallback + rule!((protocol_property_requirements accessor: _* @accs) => {..accs}), + // Computed getter → accessor_declaration (body optional). + rule!( + (computed_getter body: (block statement: _* @body)?) + => + (accessor_declaration + accessor_kind: (accessor_kind "get") + body: (block stmt: {..body})) + ), + // Computed setter with explicit parameter name. + rule!( + (computed_setter parameter: @param body: (block statement: _* @body)) + => + (accessor_declaration + accessor_kind: (accessor_kind "set") + parameter: (parameter pattern: (name_pattern identifier: (identifier #{param}))) + body: (block stmt: {..body})) + ), + // Computed setter without explicit parameter name; body optional. + rule!( + (computed_setter body: (block statement: _* @body)?) + => + (accessor_declaration + accessor_kind: (accessor_kind "set") + body: (block stmt: {..body})) + ), + // Computed modify → accessor_declaration + rule!( + (computed_modify body: (block statement: _* @body)) + => + (accessor_declaration + accessor_kind: (accessor_kind "modify") + body: (block stmt: {..body})) + ), + // willset/didset block — spread to children + rule!((willset_didset_block _* @clauses) => {..clauses}), + // willset clause → accessor_declaration (body optional). + rule!( + (willset_clause body: (block statement: _* @body)?) + => + (accessor_declaration + accessor_kind: (accessor_kind "willSet") + body: (block stmt: {..body})) + ), + // didset clause → accessor_declaration (body optional). + rule!( + (didset_clause body: (block statement: _* @body)?) + => + (accessor_declaration + accessor_kind: (accessor_kind "didSet") + body: (block stmt: {..body})) + ), + // Preprocessor conditionals — unsupported + rule!((diagnostic) => (unsupported_node)), // ---- Fallbacks ---- rule!( (_) diff --git a/unified/extractor/tests/corpus/swift/closures.txt b/unified/extractor/tests/corpus/swift/closures.txt index 638f8a32836..1d058dfb1e3 100644 --- a/unified/extractor/tests/corpus/swift/closures.txt +++ b/unified/extractor/tests/corpus/swift/closures.txt @@ -73,8 +73,12 @@ top_level pattern: name_pattern identifier: identifier "x" - type: unsupported_node "Int" - return_type: unsupported_node "Int" + type: + named_type_expr + name: identifier "Int" + return_type: + named_type_expr + name: identifier "Int" === Closure with shorthand parameters @@ -245,11 +249,13 @@ top_level call_expr callee: member_access_expr - base: unsupported_node "self" + base: + name_expr + identifier: identifier "self" member: identifier "doThing" capture_declaration: variable_declaration - modifier: unsupported_node "weak" <-- ERROR: The field variable_declaration.modifier should contain modifier, but got unsupported_node + modifier: modifier "weak" pattern: name_pattern identifier: identifier "self" @@ -363,5 +369,9 @@ top_level pattern: name_pattern identifier: identifier "x" - type: unsupported_node "Int" - return_type: unsupported_node "Int" + type: + named_type_expr + name: identifier "Int" + return_type: + named_type_expr + name: identifier "Int" diff --git a/unified/extractor/tests/corpus/swift/collections.txt b/unified/extractor/tests/corpus/swift/collections.txt index 5ff49dd4899..2ecdf5a0179 100644 --- a/unified/extractor/tests/corpus/swift/collections.txt +++ b/unified/extractor/tests/corpus/swift/collections.txt @@ -88,7 +88,14 @@ top_level pattern: name_pattern identifier: identifier "xs" - type: unsupported_node ": [Int]" + type: + generic_type_expr + base: + named_type_expr + name: identifier "Array" + type_argument: + named_type_expr + name: identifier "Int" value: array_literal "[]" === @@ -192,7 +199,9 @@ top_level pattern: name_pattern identifier: identifier "s" - type: unsupported_node ": Set" + type: + named_type_expr + name: identifier "Set" value: array_literal element: diff --git a/unified/extractor/tests/corpus/swift/functions.txt b/unified/extractor/tests/corpus/swift/functions.txt index ce4b3e7524a..ed86618910c 100644 --- a/unified/extractor/tests/corpus/swift/functions.txt +++ b/unified/extractor/tests/corpus/swift/functions.txt @@ -135,7 +135,9 @@ top_level pattern: name_pattern identifier: identifier "b" - return_type: unsupported_node "Int" + return_type: + named_type_expr + name: identifier "Int" === Function with named parameters @@ -365,7 +367,9 @@ top_level pattern: name_pattern identifier: identifier "values" - return_type: unsupported_node "Int" + return_type: + named_type_expr + name: identifier "Int" === Function call @@ -554,7 +558,9 @@ top_level pattern: name_pattern identifier: identifier "x" - return_type: unsupported_node "T" + return_type: + named_type_expr + name: identifier "T" === Leading-dot expression value diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors.txt b/unified/extractor/tests/corpus/swift/optionals-and-errors.txt index 1e4df4274ba..23e545f5463 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors.txt +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors.txt @@ -41,7 +41,14 @@ top_level pattern: name_pattern identifier: identifier "x" - type: unsupported_node ": Int?" + type: + generic_type_expr + base: + named_type_expr + name: identifier "Optional" + type_argument: + named_type_expr + name: identifier "Int" value: builtin_expr "nil" === @@ -228,7 +235,9 @@ top_level return_expr value: string_literal "\"\"" name: identifier "read" - return_type: unsupported_node "String" + return_type: + named_type_expr + name: identifier "String" === Do-catch diff --git a/unified/extractor/tests/corpus/swift/types.txt b/unified/extractor/tests/corpus/swift/types.txt index 4eab7971642..ef15ad87f59 100644 --- a/unified/extractor/tests/corpus/swift/types.txt +++ b/unified/extractor/tests/corpus/swift/types.txt @@ -19,7 +19,10 @@ source_file top_level body: block - stmt: unsupported_node "class Foo {}" + stmt: + class_like_declaration + modifier: modifier "class" + name: identifier "Foo" === Class with stored properties @@ -82,7 +85,27 @@ source_file top_level body: block - stmt: unsupported_node "class Point {\n var x: Int\n var y: Int\n}" + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "y" + type: + named_type_expr + name: identifier "Int" + modifier: modifier "class" + name: identifier "Point" === Class with initializer @@ -157,7 +180,33 @@ source_file top_level body: block - stmt: unsupported_node "class Point {\n var x: Int\n init(x: Int) {\n self.x = x\n }\n}" + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + constructor_declaration + body: + block + stmt: + assign_expr + target: + member_access_expr + base: + name_expr + identifier: identifier "self" + member: identifier "x" + value: + name_expr + identifier: identifier "x" + modifier: modifier "class" + name: identifier "Point" === Class with method @@ -207,7 +256,28 @@ source_file top_level body: block - stmt: unsupported_node "class Counter {\n var n = 0\n func bump() {\n n += 1\n }\n}" + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "n" + value: int_literal "0" + function_declaration + body: + block + stmt: + compound_assign_expr + operator: infix_operator "+=" + target: + name_expr + identifier: identifier "n" + value: int_literal "1" + name: identifier "bump" + modifier: modifier "class" + name: identifier "Counter" === Class inheritance @@ -237,7 +307,10 @@ source_file top_level body: block - stmt: unsupported_node "class Dog: Animal {}" + stmt: + class_like_declaration + modifier: modifier "class" + name: identifier "Dog" === Struct @@ -300,7 +373,27 @@ source_file top_level body: block - stmt: unsupported_node "struct Point {\n let x: Int\n let y: Int\n}" + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "x" + type: + named_type_expr + name: identifier "Int" + variable_declaration + modifier: modifier "let" + pattern: + name_pattern + identifier: identifier "y" + type: + named_type_expr + name: identifier "Int" + modifier: modifier "struct" + name: identifier "Point" === Enum with cases @@ -345,7 +438,31 @@ source_file top_level body: block - stmt: unsupported_node "enum Direction {\n case north\n case south\n case east\n case west\n}" + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "north" + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "south" + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "east" + variable_declaration + modifier: modifier "enum_case" + pattern: + name_pattern + identifier: identifier "west" + modifier: modifier "enum" + name: identifier "Direction" === Enum with associated values @@ -404,7 +521,39 @@ source_file top_level body: block - stmt: unsupported_node "enum Shape {\n case circle(radius: Double)\n case square(side: Double)\n}" + stmt: + class_like_declaration + member: + class_like_declaration + member: + constructor_declaration + body: block "circle(radius: Double)" + parameter: + parameter + pattern: + name_pattern + identifier: identifier "radius" + type: + named_type_expr + name: identifier "Double" + modifier: modifier "enum_case" + name: identifier "circle" + class_like_declaration + member: + constructor_declaration + body: block "square(side: Double)" + parameter: + parameter + pattern: + name_pattern + identifier: identifier "side" + type: + named_type_expr + name: identifier "Double" + modifier: modifier "enum_case" + name: identifier "square" + modifier: modifier "enum" + name: identifier "Shape" === Protocol declaration @@ -431,7 +580,14 @@ source_file top_level body: block - stmt: unsupported_node "protocol Drawable {\n func draw()\n}" + stmt: + class_like_declaration + member: + function_declaration + body: block "func draw()" + name: identifier "draw" + modifier: modifier "protocol" + name: identifier "Drawable" === Extension @@ -482,7 +638,29 @@ source_file top_level body: block - stmt: unsupported_node "extension Int {\n func squared() -> Int { return self * self }\n}" + stmt: + class_like_declaration + member: + function_declaration + body: + block + stmt: + return_expr + value: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "self" + right: + name_expr + identifier: identifier "self" + name: identifier "squared" + return_type: + named_type_expr + name: identifier "Int" + modifier: modifier "extension" + name: identifier "Int" === Computed property @@ -576,7 +754,47 @@ source_file top_level body: block - stmt: unsupported_node "class Rect {\n var w: Double\n var h: Double\n var area: Double {\n return w * h\n }\n}" + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "w" + type: + named_type_expr + name: identifier "Double" + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "h" + type: + named_type_expr + name: identifier "Double" + accessor_declaration + body: + block + stmt: + return_expr + value: + binary_expr + operator: infix_operator "*" + left: + name_expr + identifier: identifier "w" + right: + name_expr + identifier: identifier "h" + modifier: modifier "var" + name: identifier "area" + type: + named_type_expr + name: identifier "Double" + accessor_kind: accessor_kind "get" + modifier: modifier "class" + name: identifier "Rect" === Property with getter and setter @@ -662,4 +880,47 @@ source_file top_level body: block - stmt: unsupported_node "class Box {\n private var _v = 0\n var v: Int {\n get { return _v }\n set { _v = newValue }\n }\n}" + stmt: + class_like_declaration + member: + variable_declaration + modifier: modifier "var" + pattern: + name_pattern + identifier: identifier "_v" + value: int_literal "0" + accessor_declaration + body: + block + stmt: + return_expr + value: + name_expr + identifier: identifier "_v" + modifier: modifier "var" + name: identifier "v" + type: + named_type_expr + name: identifier "Int" + accessor_kind: accessor_kind "get" + accessor_declaration + body: + block + stmt: + assign_expr + target: + name_expr + identifier: identifier "_v" + value: + name_expr + identifier: identifier "newValue" + modifier: + modifier "var" + modifier "chained_declaration" + name: identifier "v" + type: + named_type_expr + name: identifier "Int" + accessor_kind: accessor_kind "set" + modifier: modifier "class" + name: identifier "Box" diff --git a/unified/extractor/tests/corpus/swift/variables.txt b/unified/extractor/tests/corpus/swift/variables.txt index d7ff7a110a1..56d55313fb3 100644 --- a/unified/extractor/tests/corpus/swift/variables.txt +++ b/unified/extractor/tests/corpus/swift/variables.txt @@ -107,7 +107,9 @@ top_level pattern: name_pattern identifier: identifier "x" - type: unsupported_node ": Int" + type: + named_type_expr + name: identifier "Int" value: int_literal "1" === @@ -150,7 +152,9 @@ top_level pattern: name_pattern identifier: identifier "x" - type: unsupported_node ": Int" + type: + named_type_expr + name: identifier "Int" === Tuple destructuring binding