From 3522f35ab2b43852fd200fc5220189d02f6a5aa5 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 18 Jun 2026 14:12:32 +0200 Subject: [PATCH] unified/swift: add collections, optionals/errors --- .../extractor/src/languages/swift/swift.rs | 75 +++++++++++++++++++ .../extractor/tests/corpus/swift/closures.txt | 2 +- .../tests/corpus/swift/collections.txt | 18 ++++- .../extractor/tests/corpus/swift/loops.txt | 7 +- .../corpus/swift/optionals-and-errors.txt | 52 ++++++++++++- 5 files changed, 144 insertions(+), 10 deletions(-) diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 9c595c51aac..bdb985342f5 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -558,6 +558,81 @@ fn translation_rules() -> Vec { let name = __yeast_ctx.literal("identifier", &text[..text.len() - 1]); vec![__yeast_ctx.node("labeled_stmt", vec![("label", vec![name]), ("stmt", vec![stmt.into()])])] }}), + // ---- Collections ---- + // Array literal + rule!((array_literal element: _* @elems) => (array_literal element: {..elems})), + // Empty array literal + rule!((array_literal) => (array_literal)), + // Dictionary literal — zip keys and values into key_value_pairs + rule!( + (dictionary_literal key: _* @keys value: _* @vals) + => + (map_literal element: {..{ + keys.iter().zip(vals.iter()).map(|(&k, &v)| { + let k_id: usize = k.into(); + let v_id: usize = v.into(); + __yeast_ctx.node("key_value_pair", vec![ + ("key", vec![k_id]), + ("value", vec![v_id]), + ]) + }).collect::>() + }}) + ), + rule!((dictionary_literal element: _* @elems) => (map_literal element: {..elems})), + rule!((dictionary_literal_item key: @k value: @v) => (key_value_pair key: {k} value: {v})), + // ---- Optionals and errors ---- + // Optional chaining — unwrap the marker + rule!((optional_chain_marker expr: @inner) => {inner}), + // try/try?/try! expr → unary_expr with operator "try", "try?" or "try!" + rule!((try_expression (try_operator) @op expr: @inner) => (unary_expr operator: (prefix_operator #{op}) operand: {inner})), + rule!((try_expression operator: (try_operator) @op expr: @inner) => (unary_expr operator: (prefix_operator #{op}) operand: {inner})), + // Do-catch → try_expr + rule!( + (do_statement body: (block statement: _* @body) catch: (catch_block)* @catches) + => + (try_expr + body: (block stmt: {..body}) + catch_clause: {..catches}) + ), + // Catch block with bound identifier; optional where-clause guard. + rule!( + (catch_block + keyword: (catch_keyword) + error: @pattern + where: (where_clause expr: @guard)? + body: (block statement: _* @body)) + => + (catch_clause + pattern: {pattern} + guard: {..guard} + body: (block stmt: {..body})) + ), + // Catch block without error binding + rule!( + (catch_block keyword: (catch_keyword) body: (block statement: _* @body)) + => + (catch_clause body: (block stmt: {..body})) + ), + // Empty catch block: catch {} + rule!( + (catch_block (catch_keyword)) + => + (catch_clause body: (block)) + ), + // Catch block with unhandled pattern — preserve pattern; optional body. + rule!( + (catch_block keyword: (catch_keyword) error: @pat body: (block statement: _* @body)) + => + (catch_clause + pattern: {pat} + body: (block stmt: {..body})) + ), + // As expression (type cast) — as?, as! + rule!((as_expression (as_operator) @op expr: @val type: @ty) => (type_cast_expr expr: {val} operator: (infix_operator #{op}) type: {ty})), + // Check expression (`x is T`) → type_test_expr + rule!((check_expression op: @op target: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator #{op}) type: {ty})), + // Await expression → unary_expr with operator "await" + rule!((await_expression expr: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})), // ---- Fallbacks ---- rule!( (_) diff --git a/unified/extractor/tests/corpus/swift/closures.txt b/unified/extractor/tests/corpus/swift/closures.txt index 2d18062bb2c..638f8a32836 100644 --- a/unified/extractor/tests/corpus/swift/closures.txt +++ b/unified/extractor/tests/corpus/swift/closures.txt @@ -245,7 +245,7 @@ top_level call_expr callee: member_access_expr - base: unsupported_node "self?" + base: unsupported_node "self" member: identifier "doThing" capture_declaration: variable_declaration diff --git a/unified/extractor/tests/corpus/swift/collections.txt b/unified/extractor/tests/corpus/swift/collections.txt index 795bca6e6e2..5ff49dd4899 100644 --- a/unified/extractor/tests/corpus/swift/collections.txt +++ b/unified/extractor/tests/corpus/swift/collections.txt @@ -35,7 +35,12 @@ top_level pattern: name_pattern identifier: identifier "xs" - value: unsupported_node "[1, 2, 3]" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" === Empty array literal with type @@ -84,7 +89,7 @@ top_level name_pattern identifier: identifier "xs" type: unsupported_node ": [Int]" - value: unsupported_node "[]" + value: array_literal "[]" === Dictionary literal @@ -130,7 +135,7 @@ top_level pattern: name_pattern identifier: identifier "d" - value: unsupported_node "[\"a\": 1, \"b\": 2]" + value: map_literal "[\"a\": 1, \"b\": 2]" === Set literal @@ -188,7 +193,12 @@ top_level name_pattern identifier: identifier "s" type: unsupported_node ": Set" - value: unsupported_node "[1, 2, 3]" + value: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" === Tuple literal diff --git a/unified/extractor/tests/corpus/swift/loops.txt b/unified/extractor/tests/corpus/swift/loops.txt index 6fbd7ce1809..b0e25debff5 100644 --- a/unified/extractor/tests/corpus/swift/loops.txt +++ b/unified/extractor/tests/corpus/swift/loops.txt @@ -55,7 +55,12 @@ top_level pattern: name_pattern identifier: identifier "x" - iterable: unsupported_node "[1, 2, 3]" + iterable: + array_literal + element: + int_literal "1" + int_literal "2" + int_literal "3" === For-in over range diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors.txt b/unified/extractor/tests/corpus/swift/optionals-and-errors.txt index 6b8b62b2c2a..1e4df4274ba 100644 --- a/unified/extractor/tests/corpus/swift/optionals-and-errors.txt +++ b/unified/extractor/tests/corpus/swift/optionals-and-errors.txt @@ -92,7 +92,12 @@ top_level identifier: identifier "n" value: member_access_expr - base: unsupported_node "obj?.foo?" + base: + member_access_expr + base: + name_expr + identifier: identifier "obj" + member: identifier "foo" member: identifier "bar" === @@ -274,7 +279,32 @@ source_file top_level body: block - stmt: unsupported_node "do {\n try foo()\n} catch {\n print(error)\n}" + stmt: + try_expr + body: + block + stmt: + unary_expr + operand: + call_expr + callee: + name_expr + identifier: identifier "foo" + operator: prefix_operator "try" + catch_clause: + catch_clause + body: + block + stmt: + call_expr + argument: + argument + value: + name_expr + identifier: identifier "error" + callee: + name_expr + identifier: identifier "print" === Try? expression @@ -318,7 +348,14 @@ top_level pattern: name_pattern identifier: identifier "result" - value: unsupported_node "try? foo()" + value: + unary_expr + operand: + call_expr + callee: + name_expr + identifier: identifier "foo" + operator: prefix_operator "try?" === Try! expression @@ -362,4 +399,11 @@ top_level pattern: name_pattern identifier: identifier "result" - value: unsupported_node "try! foo()" + value: + unary_expr + operand: + call_expr + callee: + name_expr + identifier: identifier "foo" + operator: prefix_operator "try!"