Skip to content

Commit 55194dd

Browse files
committed
Unified: Support for calls and member access
1 parent cbe4c81 commit 55194dd

7 files changed

Lines changed: 224 additions & 18 deletions

File tree

unified/extractor/ast_types.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ supertypes:
55
- string_literal
66
- binary_expr
77
- unary_expr
8+
- call_expr
9+
- member_access_expr
810
- lambda_expr
911
- unsupported_node
1012
stmt:
@@ -52,6 +54,17 @@ named:
5254
operand: expr
5355
operator: operator
5456

57+
# A function or method call, such as `f(x)` or `obj.m(x)`. Method calls
58+
# are represented as a call whose `function` is a `member_access_expr`.
59+
call_expr:
60+
function: expr
61+
argument*: expr
62+
63+
# Member access, such as `obj.member`.
64+
member_access_expr:
65+
target: expr
66+
member: identifier
67+
5568
lambda_expr:
5669
parameter*: parameter
5770
body: [expr, stmt]

unified/extractor/src/languages/swift/swift.rs

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
use codeql_extractor::extractor::simple;
2-
use yeast::{rule, DesugaringConfig, PhaseKind};
2+
use yeast::{build::BuildCtx, rule, DesugaringConfig, PhaseKind};
3+
4+
/// Names of output AST kinds that belong to the `expr` supertype. Kept in
5+
/// sync with `ast_types.yml`. `unsupported_node` is intentionally omitted
6+
/// because it is also a member of the `stmt` supertype.
7+
const EXPR_KINDS: &[&str] = &[
8+
"name_expr",
9+
"int_literal",
10+
"string_literal",
11+
"binary_expr",
12+
"unary_expr",
13+
"call_expr",
14+
"member_access_expr",
15+
"lambda_expr",
16+
];
17+
18+
/// If `id` is an `expr`, wrap it in `expr_stmt` so it can sit in a `stmt`
19+
/// position; otherwise return it unchanged.
20+
fn wrap_expr_in_stmt(ctx: &mut BuildCtx, id: usize) -> usize {
21+
let kind = ctx.ast.get_node(id).map(|n| n.kind()).unwrap_or("");
22+
if EXPR_KINDS.contains(&kind) {
23+
yeast::tree!(ctx, (expr_stmt expr: {id}))
24+
} else {
25+
id
26+
}
27+
}
328

429
fn translation_rules() -> Vec<yeast::Rule> {
530
vec![
@@ -149,11 +174,44 @@ fn translation_rules() -> Vec<yeast::Rule> {
149174
// ---- Block / statement wrapping ----
150175
// A `(statements ...)` node corresponds to a brace-delimited block.
151176
// Each child is mapped through translation; bare expression results
152-
// get wrapped in `expr_stmt`.
177+
// get wrapped in `expr_stmt` so they fit the `body*: stmt` field.
153178
rule!(
154179
(statements (_)* @stmts)
155180
=>
156-
(block_stmt body: {..stmts})
181+
(block_stmt body: {..stmts.iter().copied().map(|n|
182+
wrap_expr_in_stmt(&mut __yeast_ctx, n.into())
183+
).collect::<Vec<usize>>()})
184+
),
185+
// ---- Calls and member access ----
186+
// Member access, e.g. `obj.member`. The Swift parser wraps the
187+
// member name as `(navigation_suffix suffix: (simple_identifier))`.
188+
rule!(
189+
(navigation_expression
190+
target: (_) @target
191+
suffix: (navigation_suffix
192+
suffix: (simple_identifier) @member))
193+
=>
194+
(member_access_expr
195+
target: {target}
196+
member: (identifier #{member}))
197+
),
198+
// Function / method call. The callee is the first child of
199+
// `call_expression`; the second is a `call_suffix` whose
200+
// `value_arguments` (if present) hold the parenthesized args. A
201+
// trailing closure (`call_suffix` with a `lambda_literal` child)
202+
// is appended as a final argument.
203+
rule!(
204+
(call_expression
205+
(_) @callee
206+
(call_suffix
207+
(value_arguments
208+
(value_argument value: (_) @args)*)?
209+
(lambda_literal)? @trailing))
210+
=>
211+
(call_expr
212+
function: {callee}
213+
argument: {..args.iter().copied().map(Into::into)
214+
.chain(trailing.map(Into::into)).collect::<Vec<usize>>()})
157215
),
158216
// ---- Guard statement ----
159217
// `guard let x = e else { ... }` — currently only handles the

unified/extractor/tests/corpus/swift/closures.txt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,23 @@ source_file
123123
---
124124

125125
top_level
126-
body: unsupported_node "xs.map { $0 * 2 }"
126+
body:
127+
call_expr
128+
argument:
129+
lambda_expr
130+
body:
131+
binary_expr
132+
operator: operator "*"
133+
left:
134+
name_expr
135+
identifier: identifier "$0"
136+
right: int_literal "2"
137+
function:
138+
member_access_expr
139+
target:
140+
name_expr
141+
identifier: identifier "xs"
142+
member: identifier "map"
127143

128144
===
129145
Closure with capture list
@@ -168,7 +184,13 @@ top_level
168184
variable_declarator
169185
value:
170186
lambda_expr
171-
body: unsupported_node "self?.doThing()"
187+
body:
188+
call_expr
189+
argument:
190+
function:
191+
member_access_expr
192+
target: unsupported_node "self"
193+
member: identifier "doThing"
172194
pattern:
173195
var_pattern
174196
identifier: identifier "f"

unified/extractor/tests/corpus/swift/collections.txt

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,17 @@ top_level
187187
Subscript access
188188
===
189189

190+
// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape
191+
// as `xs(0)`), so the mapping currently produces a call_expr. Update the
192+
// parser / add a separate subscript_expr node and remap when fixed.
190193
let first = xs[0]
191194

192195
---
193196

194197
source_file
198+
comment "// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape"
199+
comment "// as `xs(0)`), so the mapping currently produces a call_expr. Update the"
200+
comment "// parser / add a separate subscript_expr node and remap when fixed."
195201
property_declaration
196202
name:
197203
pattern
@@ -210,10 +216,18 @@ source_file
210216

211217
top_level
212218
body:
219+
unsupported_node "// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape"
220+
unsupported_node "// as `xs(0)`), so the mapping currently produces a call_expr. Update the"
221+
unsupported_node "// parser / add a separate subscript_expr node and remap when fixed."
213222
variable_declaration_stmt
214223
variable_declarator:
215224
variable_declarator
216-
value: unsupported_node "xs[0]"
225+
value:
226+
call_expr
227+
argument: int_literal "0"
228+
function:
229+
name_expr
230+
identifier: identifier "xs"
217231
pattern:
218232
var_pattern
219233
identifier: identifier "first"
@@ -222,11 +236,15 @@ top_level
222236
Dictionary subscript
223237
===
224238

239+
// TODO: same parser issue as the array subscript case above —
240+
// `d["key"]` is parsed as `call_expression(d, ("key"))`.
225241
let v = d["key"]
226242

227243
---
228244

229245
source_file
246+
comment "// TODO: same parser issue as the array subscript case above —"
247+
comment "// `d[\"key\"]` is parsed as `call_expression(d, (\"key\"))`."
230248
property_declaration
231249
name:
232250
pattern
@@ -247,10 +265,17 @@ source_file
247265

248266
top_level
249267
body:
268+
unsupported_node "// TODO: same parser issue as the array subscript case above —"
269+
unsupported_node "// `d[\"key\"]` is parsed as `call_expression(d, (\"key\"))`."
250270
variable_declaration_stmt
251271
variable_declarator:
252272
variable_declarator
253-
value: unsupported_node "d[\"key\"]"
273+
value:
274+
call_expr
275+
argument: string_literal "\"key\""
276+
function:
277+
name_expr
278+
identifier: identifier "d"
254279
pattern:
255280
var_pattern
256281
identifier: identifier "v"

unified/extractor/tests/corpus/swift/control-flow.txt

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,16 @@ top_level
3939
right: int_literal "0"
4040
then:
4141
block_stmt
42-
body: unsupported_node "print(x)"
42+
body:
43+
expr_stmt
44+
expr:
45+
call_expr
46+
argument:
47+
name_expr
48+
identifier: identifier "x"
49+
function:
50+
name_expr
51+
identifier: identifier "print"
4352

4453
===
4554
If-else
@@ -95,10 +104,31 @@ top_level
95104
right: int_literal "0"
96105
else:
97106
block_stmt
98-
body: unsupported_node "print(-x)"
107+
body:
108+
expr_stmt
109+
expr:
110+
call_expr
111+
argument:
112+
unary_expr
113+
operator: operator "-"
114+
operand:
115+
name_expr
116+
identifier: identifier "x"
117+
function:
118+
name_expr
119+
identifier: identifier "print"
99120
then:
100121
block_stmt
101-
body: unsupported_node "print(x)"
122+
body:
123+
expr_stmt
124+
expr:
125+
call_expr
126+
argument:
127+
name_expr
128+
identifier: identifier "x"
129+
function:
130+
name_expr
131+
identifier: identifier "print"
102132

103133
===
104134
If-else-if chain
@@ -178,13 +208,34 @@ top_level
178208
right: int_literal "0"
179209
else:
180210
block_stmt
181-
body: unsupported_node "print(3)"
211+
body:
212+
expr_stmt
213+
expr:
214+
call_expr
215+
argument: int_literal "3"
216+
function:
217+
name_expr
218+
identifier: identifier "print"
182219
then:
183220
block_stmt
184-
body: unsupported_node "print(2)"
221+
body:
222+
expr_stmt
223+
expr:
224+
call_expr
225+
argument: int_literal "2"
226+
function:
227+
name_expr
228+
identifier: identifier "print"
185229
then:
186230
block_stmt
187-
body: unsupported_node "print(1)"
231+
body:
232+
expr_stmt
233+
expr:
234+
call_expr
235+
argument: int_literal "1"
236+
function:
237+
name_expr
238+
identifier: identifier "print"
188239

189240
===
190241
If-let optional binding
@@ -227,7 +278,16 @@ top_level
227278
identifier: identifier "value"
228279
then:
229280
block_stmt
230-
body: unsupported_node "print(value)"
281+
body:
282+
expr_stmt
283+
expr:
284+
call_expr
285+
argument:
286+
name_expr
287+
identifier: identifier "value"
288+
function:
289+
name_expr
290+
identifier: identifier "print"
231291

232292
===
233293
Guard let

unified/extractor/tests/corpus/swift/functions.txt

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,14 @@ source_file
207207
---
208208

209209
top_level
210-
body: unsupported_node "foo(1, 2)"
210+
body:
211+
call_expr
212+
argument:
213+
int_literal "1"
214+
int_literal "2"
215+
function:
216+
name_expr
217+
identifier: identifier "foo"
211218

212219
===
213220
Function call with labelled arguments
@@ -233,7 +240,12 @@ source_file
233240
---
234241

235242
top_level
236-
body: unsupported_node "greet(person: \"Bob\")"
243+
body:
244+
call_expr
245+
argument: string_literal "\"Bob\""
246+
function:
247+
name_expr
248+
identifier: identifier "greet"
237249

238250
===
239251
Method call
@@ -258,7 +270,15 @@ source_file
258270
---
259271

260272
top_level
261-
body: unsupported_node "list.append(1)"
273+
body:
274+
call_expr
275+
argument: int_literal "1"
276+
function:
277+
member_access_expr
278+
target:
279+
name_expr
280+
identifier: identifier "list"
281+
member: identifier "append"
262282

263283
===
264284
Generic function

unified/extractor/tests/corpus/swift/optionals-and-errors.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,15 @@ top_level
6969
variable_declaration_stmt
7070
variable_declarator:
7171
variable_declarator
72-
value: unsupported_node "obj?.foo?.bar"
72+
value:
73+
member_access_expr
74+
target:
75+
member_access_expr
76+
target:
77+
name_expr
78+
identifier: identifier "obj"
79+
member: identifier "foo"
80+
member: identifier "bar"
7381
pattern:
7482
var_pattern
7583
identifier: identifier "n"

0 commit comments

Comments
 (0)