unified/swift: add variable/property/accessor and enum mappings

This commit is contained in:
Asger F
2026-06-18 13:42:23 +02:00
parent 4e9c3fb436
commit d17fd2d964
6 changed files with 414 additions and 27 deletions

View File

@@ -83,6 +83,209 @@ fn translation_rules() -> Vec<yeast::Rule> {
// Blocks contain statement* directly.
rule!((block statement: _+ @stmts) => (block stmt: {..stmts})),
rule!((block) => (block)),
// ---- Variables ----
// property_binding rules — these produce variable_declaration and/or accessor_declaration
// nodes for individual declarators. The outer property_declaration rule splices these out
// and attaches binding/modifiers from the parent.
// Computed property with explicit accessors (get/set/modify) →
// a sequence of accessor_declaration nodes, each with the property name
// attached. Subsequent accessors will be tagged chained_declaration by
// the outer property_declaration rule.
rule!(
(property_binding
name: @pattern
type: _? @ty
computed_value: (computed_property accessor: _+ @accessors))
=>
{..{
let name_text = __yeast_ctx.ast.source_text(pattern.into());
let ty_ids: Vec<usize> = ty.iter().map(|&t| t.into()).collect();
let acc_ids: Vec<usize> = accessors.iter().map(|&a| a.into()).collect();
for &acc_id in &acc_ids {
let ident = __yeast_ctx.literal("identifier", &name_text);
__yeast_ctx.prepend_field(acc_id, "name", ident);
for &ty_id in ty_ids.iter().rev() {
__yeast_ctx.prepend_field(acc_id, "type", ty_id);
}
}
acc_ids
}}
),
// Computed property: shorthand getter (no explicit get/set, just statements) →
// a single accessor_declaration with kind "get".
rule!(
(property_binding
name: (pattern bound_identifier: @name)
type: _? @ty
computed_value: (computed_property statement: _* @body))
=>
(accessor_declaration
name: (identifier #{name})
type: {..ty}
accessor_kind: (accessor_kind "get")
body: (block stmt: {..body}))
),
// Stored property with willSet/didSet observers (initializer optional) →
// variable_declaration followed by one accessor_declaration per observer,
// each carrying the property name. Subsequent items are tagged
// chained_declaration by the outer property_declaration rule.
rule!(
(property_binding
name: (pattern bound_identifier: @name)
type: _? @ty
value: _? @val
observers: (willset_didset_block willset: _? @ws didset: _? @ds))
=>
{..{
let name_text = __yeast_ctx.ast.source_text(name.into());
let val_ids: Vec<usize> = val.iter().map(|&v| v.into()).collect();
let ty_ids: Vec<usize> = ty.iter().map(|&t| t.into()).collect();
let mut obs_ids: Vec<usize> = Vec::new();
obs_ids.extend(ws.iter().map(|&o| { let id: usize = o.into(); id }));
obs_ids.extend(ds.iter().map(|&o| { let id: usize = o.into(); id }));
let ident_for_var = __yeast_ctx.literal("identifier", &name_text);
let pat = __yeast_ctx.node("name_pattern", vec![("identifier", vec![ident_for_var])]);
let mut var_fields: Vec<(&str, Vec<usize>)> = vec![("pattern", vec![pat])];
if !ty_ids.is_empty() {
var_fields.push(("type", ty_ids));
}
if !val_ids.is_empty() {
var_fields.push(("value", val_ids));
}
let var_id = __yeast_ctx.node("variable_declaration", var_fields);
let mut result = vec![var_id];
for obs_id in obs_ids {
let ident = __yeast_ctx.literal("identifier", &name_text);
__yeast_ctx.prepend_field(obs_id, "name", ident);
result.push(obs_id);
}
result
}}
),
// property_binding with any pattern name (identifier or destructuring)
rule!(
(property_binding
name: @pattern
type: _? @ty
value: _? @val)
=>
(variable_declaration
pattern: {pattern}
type: {..ty}
value: {..val})
),
// property_declaration: splice declarators (each may translate to multiple nodes —
// variable_declaration and/or accessor_declaration), and attach the binding modifier
// (let/var) and any outer modifiers to each. All children after the first additionally
// get a synthetic chained_declaration modifier so the grouping can be recovered.
rule!(
(property_declaration
binding: (value_binding_pattern mutability: @binding_kind)
declarator: _* @decls
(modifiers)* @mods)
=>
{..{
let binding_text = __yeast_ctx.ast.source_text(binding_kind.into());
let mod_ids: Vec<usize> = mods.iter().map(|&m| m.into()).collect();
let decl_ids: Vec<usize> = decls.iter().map(|&d| d.into()).collect();
for (i, &decl_id) in decl_ids.iter().enumerate() {
if i > 0 {
let chained = __yeast_ctx.literal("modifier", "chained_declaration");
__yeast_ctx.prepend_field(decl_id, "modifier", chained);
}
for &mod_id in mod_ids.iter().rev() {
__yeast_ctx.prepend_field(decl_id, "modifier", mod_id);
}
let binding_mod = __yeast_ctx.literal("modifier", &binding_text);
__yeast_ctx.prepend_field(decl_id, "modifier", binding_mod);
}
decl_ids
}}
),
// ---- Enums ----
// enum_type_parameter → parameter (with optional name as pattern).
rule!(
(enum_type_parameter name: @name type: @ty)
=>
(parameter
pattern: (name_pattern identifier: (identifier #{name}))
type: {ty})
),
rule!(
(enum_type_parameter type: @ty)
=>
(parameter type: {ty})
),
// enum_case_entry with associated values → class_like_declaration containing
// a constructor whose parameters are the data parameters.
rule!(
(enum_case_entry
name: @name
data_contents: (enum_type_parameters parameter: _* @params))
=>
(class_like_declaration
modifier: (modifier "enum_case")
name: (identifier #{name})
member: (constructor_declaration parameter: {..params} body: (block)))
),
// enum_case_entry with explicit raw value → variable_declaration with that value.
rule!(
(enum_case_entry name: @name raw_value: @val)
=>
(variable_declaration
modifier: (modifier "enum_case")
pattern: (name_pattern identifier: (identifier #{name}))
value: {val})
),
// enum_case_entry without associated values → variable_declaration tagged enum_case.
rule!(
(enum_case_entry name: @name)
=>
(variable_declaration
modifier: (modifier "enum_case")
pattern: (name_pattern identifier: (identifier #{name})))
),
// enum_entry: flatten case entries; attach outer modifiers to each, and
// chained_declaration on every entry after the first.
rule!(
(enum_entry case: _+ @cases (modifiers)* @mods)
=>
{..{
let mod_ids: Vec<usize> = mods.iter().map(|&m| m.into()).collect();
let case_ids: Vec<usize> = cases.iter().map(|&c| c.into()).collect();
for (i, &case_id) in case_ids.iter().enumerate() {
if i > 0 {
let chained = __yeast_ctx.literal("modifier", "chained_declaration");
__yeast_ctx.prepend_field(case_id, "modifier", chained);
}
for &mod_id in mod_ids.iter().rev() {
__yeast_ctx.prepend_field(case_id, "modifier", mod_id);
}
}
case_ids
}}
),
// Plain assignment: `x = expr`
rule!(
(assignment operator: "=" target: (directly_assignable_expression expr: @target) result: @value)
=>
(assign_expr target: {target} value: {value})
),
// Compound assignment: `x += expr` etc.
rule!(
(assignment operator: @op target: (directly_assignable_expression expr: @target) result: @value)
=>
(compound_assign_expr target: {target} operator: (infix_operator #{op}) value: {value})
),
// Unwrap `type` wrapper node
rule!((type name: @inner) => {inner}),
// `directly_assignable_expression` is just a wrapper; unwrap it
rule!((directly_assignable_expression expr: @inner) => {inner}),
// Pattern with bound_identifier → name_pattern
rule!((pattern bound_identifier: @name) => (name_pattern identifier: (identifier #{name}))),
// Tuple pattern (destructuring)
rule!((pattern (pattern)* @elems) => (tuple_pattern element: {..elems})),
// ---- Fallbacks ----
rule!(
(_)

View File

@@ -51,7 +51,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let f = { (x: Int) -> Int in x * 2 }"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "f"
value: unsupported_node "{ (x: Int) -> Int in x * 2 }"
===
Closure with shorthand parameters
@@ -85,7 +91,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let f = { $0 + $1 }"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "f"
value: unsupported_node "{ $0 + $1 }"
===
Trailing closure
@@ -170,7 +182,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let f = { [weak self] in self?.doThing() }"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "f"
value: unsupported_node "{ [weak self] in self?.doThing() }"
===
Multi-statement closure
@@ -245,4 +263,10 @@ source_file
top_level
body:
block
stmt: unsupported_node "let f = { (x: Int) -> Int in\n let y = x + 1\n return y * 2\n}"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "f"
value: unsupported_node "{ (x: Int) -> Int in\n let y = x + 1\n return y * 2\n}"

View File

@@ -29,7 +29,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let xs = [1, 2, 3]"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "xs"
value: unsupported_node "[1, 2, 3]"
===
Empty array literal with type
@@ -71,7 +77,14 @@ source_file
top_level
body:
block
stmt: unsupported_node "let xs: [Int] = []"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "xs"
type: unsupported_node ": [Int]"
value: unsupported_node "[]"
===
Dictionary literal
@@ -111,7 +124,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let d = [\"a\": 1, \"b\": 2]"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "d"
value: unsupported_node "[\"a\": 1, \"b\": 2]"
===
Set literal
@@ -162,7 +181,14 @@ source_file
top_level
body:
block
stmt: unsupported_node "let s: Set<Int> = [1, 2, 3]"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "s"
type: unsupported_node ": Set<Int>"
value: unsupported_node "[1, 2, 3]"
===
Tuple literal
@@ -200,7 +226,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let t = (1, \"two\", 3.0)"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "t"
value: tuple_expr "(1, \"two\", 3.0)"
===
Subscript access
@@ -243,7 +275,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let first = xs[0]"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "first"
value: unsupported_node "xs[0]"
===
Dictionary subscript
@@ -286,7 +324,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let v = d[\"key\"]"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "v"
value: unsupported_node "d[\"key\"]"
===
Tuple member access
@@ -319,4 +363,10 @@ source_file
top_level
body:
block
stmt: unsupported_node "let n = t.0"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "n"
value: unsupported_node "t.0"

View File

@@ -288,7 +288,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let y = x > 0 ? 1 : -1"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "y"
value: unsupported_node "x > 0 ? 1 : -1"
===
Switch statement

View File

@@ -35,7 +35,14 @@ source_file
top_level
body:
block
stmt: unsupported_node "let x: Int? = nil"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "x"
type: unsupported_node ": Int?"
value: builtin_expr "nil"
===
Optional chaining
@@ -77,7 +84,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let n = obj?.foo?.bar"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "n"
value: unsupported_node "obj?.foo?.bar"
===
Force unwrap
@@ -108,7 +121,18 @@ source_file
top_level
body:
block
stmt: unsupported_node "let n = opt!"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "n"
value:
unary_expr
operand:
name_expr
identifier: identifier "opt"
operator: postfix_operator "!"
===
Nil-coalescing
@@ -139,7 +163,19 @@ source_file
top_level
body:
block
stmt: unsupported_node "let n = opt ?? 0"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "n"
value:
binary_expr
operator: infix_operator "??"
left:
name_expr
identifier: identifier "opt"
right: int_literal "0"
===
Throwing function
@@ -265,7 +301,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let result = try? foo()"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "result"
value: unsupported_node "try? foo()"
===
Try! expression
@@ -303,4 +345,10 @@ source_file
top_level
body:
block
stmt: unsupported_node "let result = try! foo()"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "result"
value: unsupported_node "try! foo()"

View File

@@ -24,7 +24,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let x = 1"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "x"
value: int_literal "1"
===
Var binding
@@ -52,7 +58,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "var x = 1"
stmt:
variable_declaration
modifier: modifier "var"
pattern:
name_pattern
identifier: identifier "x"
value: int_literal "1"
===
Let with type annotation
@@ -89,7 +101,14 @@ source_file
top_level
body:
block
stmt: unsupported_node "let x: Int = 1"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "x"
type: unsupported_node ": Int"
value: int_literal "1"
===
Var without initialiser
@@ -125,7 +144,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "var x: Int"
stmt:
variable_declaration
modifier: modifier "var"
pattern:
name_pattern
identifier: identifier "x"
type: unsupported_node ": Int"
===
Tuple destructuring binding
@@ -163,7 +188,13 @@ source_file
top_level
body:
block
stmt: unsupported_node "let (a, b) = pair"
stmt:
variable_declaration
modifier: modifier "let"
pattern: tuple_pattern "(a, b)"
value:
name_expr
identifier: identifier "pair"
===
Multiple bindings on one line
@@ -196,7 +227,21 @@ source_file
top_level
body:
block
stmt: unsupported_node "let x = 1, y = 2"
stmt:
variable_declaration
modifier: modifier "let"
pattern:
name_pattern
identifier: identifier "x"
value: int_literal "1"
variable_declaration
modifier:
modifier "let"
modifier "chained_declaration"
pattern:
name_pattern
identifier: identifier "y"
value: int_literal "2"
===
Assignment
@@ -220,7 +265,12 @@ source_file
top_level
body:
block
stmt: unsupported_node "x = 1"
stmt:
assign_expr
target:
name_expr
identifier: identifier "x"
value: int_literal "1"
===
Compound assignment
@@ -244,4 +294,10 @@ source_file
top_level
body:
block
stmt: unsupported_node "x += 1"
stmt:
compound_assign_expr
operator: infix_operator "+="
target:
name_expr
identifier: identifier "x"
value: int_literal "1"