Skip to content

Commit 9ddc15c

Browse files
authored
Merge pull request #22549 from asgerf/unified/string-interpolation
Unified: Support string interpolation
2 parents 0d2c679 + d9af62c commit 9ddc15c

10 files changed

Lines changed: 418 additions & 12 deletions

File tree

unified/extractor/ast_types.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ supertypes:
88
- boolean_literal
99
- string_literal
1010
- regex_literal
11+
- string_interpolation_expr
1112
- builtin_expr
1213
- binary_expr
1314
- unary_expr
@@ -129,6 +130,11 @@ named:
129130
# A regex literal
130131
regex_literal:
131132

133+
# A string interpolation expression. Constant parts are stored as string literals.
134+
string_interpolation_expr:
135+
modifier*: modifier
136+
element*: expr
137+
132138
# Application of a binary operator, such as `a + b`
133139
binary_expr:
134140
left: expr

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

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,27 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
173173
rule!((nilLiteralExpr) @@node => expr {
174174
tree!((builtin_expr #{node}))
175175
}),
176-
rule!((stringLiteralExpr) @@node => expr {
177-
tree!((string_literal #{node}))
178-
}),
176+
rule!((simpleStringLiteralExpr) @@node => (string_literal #{node})),
177+
// String literal with a single constant segment (for some reason not typed as simpleStringLiteralExpr)
178+
rule!(
179+
(stringLiteralExpr segments: (stringSegment) segments: _* @@rest) @@node
180+
where rest.is_empty()
181+
=>
182+
(string_literal #{node})
183+
),
184+
rule!(
185+
(stringLiteralExpr segments: _* @segments)
186+
=>
187+
(string_interpolation_expr element: {segments})
188+
),
189+
rule!((stringSegment content: @@content) => (string_literal #{content})),
190+
rule!(
191+
(expressionSegment expressions: _* @expressions)
192+
=>
193+
(call_expr
194+
callee: (builtin_expr "interpolation")
195+
argument: {expressions})
196+
),
179197
rule!((regexLiteralExpr) @@node => expr {
180198
tree!((regex_literal #{node}))
181199
}),

unified/extractor/tests/corpus/swift/literals/string-with-interpolation.output

Lines changed: 288 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
1+
// Simple interpolation
12
"hello \(name)"
23

4+
// Multiple interpolations
5+
"hello \(first) \(last)"
6+
7+
// Interpolation with expression
8+
"result: \(x + y)"
9+
10+
// Plain string before and after interpolation
11+
"prefix \(value) suffix"
12+
13+
// Calls to custom DefaultStringInterpolation.appendInterpolation impls
14+
"foo \(x, y)"
15+
"foo \(x, y, z)"
16+
"foo \(arg: x)"
17+
"foo \(arg: x, arg2: y)"
18+
319
---
420

521
sourceFile
@@ -24,10 +40,281 @@ sourceFile
2440
baseName: identifier "name"
2541
stringSegment
2642
content: stringSegment
43+
codeBlockItem
44+
item:
45+
stringLiteralExpr
46+
closingQuote: "
47+
openingQuote: "
48+
segments:
49+
stringSegment
50+
content: stringSegment "hello "
51+
expressionSegment
52+
leftParen: (
53+
rightParen: )
54+
backslash: \
55+
expressions:
56+
labeledExpr
57+
expression:
58+
declReferenceExpr
59+
baseName: identifier "first"
60+
stringSegment
61+
content: stringSegment " "
62+
expressionSegment
63+
leftParen: (
64+
rightParen: )
65+
backslash: \
66+
expressions:
67+
labeledExpr
68+
expression:
69+
declReferenceExpr
70+
baseName: identifier "last"
71+
stringSegment
72+
content: stringSegment
73+
codeBlockItem
74+
item:
75+
stringLiteralExpr
76+
closingQuote: "
77+
openingQuote: "
78+
segments:
79+
stringSegment
80+
content: stringSegment "result: "
81+
expressionSegment
82+
leftParen: (
83+
rightParen: )
84+
backslash: \
85+
expressions:
86+
labeledExpr
87+
expression:
88+
infixOperatorExpr
89+
operator:
90+
binaryOperatorExpr
91+
operator: binaryOperator "+"
92+
leftOperand:
93+
declReferenceExpr
94+
baseName: identifier "x"
95+
rightOperand:
96+
declReferenceExpr
97+
baseName: identifier "y"
98+
stringSegment
99+
content: stringSegment
100+
codeBlockItem
101+
item:
102+
stringLiteralExpr
103+
closingQuote: "
104+
openingQuote: "
105+
segments:
106+
stringSegment
107+
content: stringSegment "prefix "
108+
expressionSegment
109+
leftParen: (
110+
rightParen: )
111+
backslash: \
112+
expressions:
113+
labeledExpr
114+
expression:
115+
declReferenceExpr
116+
baseName: identifier "value"
117+
stringSegment
118+
content: stringSegment " suffix"
119+
codeBlockItem
120+
item:
121+
stringLiteralExpr
122+
closingQuote: "
123+
openingQuote: "
124+
segments:
125+
stringSegment
126+
content: stringSegment "foo "
127+
expressionSegment
128+
leftParen: (
129+
rightParen: )
130+
backslash: \
131+
expressions:
132+
labeledExpr
133+
expression:
134+
declReferenceExpr
135+
baseName: identifier "x"
136+
trailingComma: ,
137+
labeledExpr
138+
expression:
139+
declReferenceExpr
140+
baseName: identifier "y"
141+
stringSegment
142+
content: stringSegment
143+
codeBlockItem
144+
item:
145+
stringLiteralExpr
146+
closingQuote: "
147+
openingQuote: "
148+
segments:
149+
stringSegment
150+
content: stringSegment "foo "
151+
expressionSegment
152+
leftParen: (
153+
rightParen: )
154+
backslash: \
155+
expressions:
156+
labeledExpr
157+
expression:
158+
declReferenceExpr
159+
baseName: identifier "x"
160+
trailingComma: ,
161+
labeledExpr
162+
expression:
163+
declReferenceExpr
164+
baseName: identifier "y"
165+
trailingComma: ,
166+
labeledExpr
167+
expression:
168+
declReferenceExpr
169+
baseName: identifier "z"
170+
stringSegment
171+
content: stringSegment
172+
codeBlockItem
173+
item:
174+
stringLiteralExpr
175+
closingQuote: "
176+
openingQuote: "
177+
segments:
178+
stringSegment
179+
content: stringSegment "foo "
180+
expressionSegment
181+
leftParen: (
182+
rightParen: )
183+
backslash: \
184+
expressions:
185+
labeledExpr
186+
colon: :
187+
label: identifier "arg"
188+
expression:
189+
declReferenceExpr
190+
baseName: identifier "x"
191+
stringSegment
192+
content: stringSegment
193+
codeBlockItem
194+
item:
195+
stringLiteralExpr
196+
closingQuote: "
197+
openingQuote: "
198+
segments:
199+
stringSegment
200+
content: stringSegment "foo "
201+
expressionSegment
202+
leftParen: (
203+
rightParen: )
204+
backslash: \
205+
expressions:
206+
labeledExpr
207+
colon: :
208+
label: identifier "arg"
209+
expression:
210+
declReferenceExpr
211+
baseName: identifier "x"
212+
trailingComma: ,
213+
labeledExpr
214+
colon: :
215+
label: identifier "arg2"
216+
expression:
217+
declReferenceExpr
218+
baseName: identifier "y"
219+
stringSegment
220+
content: stringSegment
27221

28222
---
29223

30224
top_level
31225
body:
32226
block
33-
stmt: string_literal "\"hello \\(name)\""
227+
stmt:
228+
string_interpolation_expr
229+
element:
230+
string_literal "hello "
231+
call_expr
232+
callee: builtin_expr "interpolation"
233+
argument:
234+
argument
235+
value: identifier "name"
236+
string_literal
237+
string_interpolation_expr
238+
element:
239+
string_literal "hello "
240+
call_expr
241+
callee: builtin_expr "interpolation"
242+
argument:
243+
argument
244+
value: identifier "first"
245+
string_literal " "
246+
call_expr
247+
callee: builtin_expr "interpolation"
248+
argument:
249+
argument
250+
value: identifier "last"
251+
string_literal
252+
string_interpolation_expr
253+
element:
254+
string_literal "result: "
255+
call_expr
256+
callee: builtin_expr "interpolation"
257+
argument:
258+
argument
259+
value:
260+
binary_expr
261+
left: identifier "x"
262+
operator: infix_operator "+"
263+
right: identifier "y"
264+
string_literal
265+
string_interpolation_expr
266+
element:
267+
string_literal "prefix "
268+
call_expr
269+
callee: builtin_expr "interpolation"
270+
argument:
271+
argument
272+
value: identifier "value"
273+
string_literal " suffix"
274+
string_interpolation_expr
275+
element:
276+
string_literal "foo "
277+
call_expr
278+
callee: builtin_expr "interpolation"
279+
argument:
280+
argument
281+
value: identifier "x"
282+
argument
283+
value: identifier "y"
284+
string_literal
285+
string_interpolation_expr
286+
element:
287+
string_literal "foo "
288+
call_expr
289+
callee: builtin_expr "interpolation"
290+
argument:
291+
argument
292+
value: identifier "x"
293+
argument
294+
value: identifier "y"
295+
argument
296+
value: identifier "z"
297+
string_literal
298+
string_interpolation_expr
299+
element:
300+
string_literal "foo "
301+
call_expr
302+
callee: builtin_expr "interpolation"
303+
argument:
304+
argument
305+
name_node: identifier "arg"
306+
value: identifier "x"
307+
string_literal
308+
string_interpolation_expr
309+
element:
310+
string_literal "foo "
311+
call_expr
312+
callee: builtin_expr "interpolation"
313+
argument:
314+
argument
315+
name_node: identifier "arg"
316+
value: identifier "x"
317+
argument
318+
name_node: identifier "arg2"
319+
value: identifier "y"
320+
string_literal
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
1+
// Simple interpolation
12
"hello \(name)"
3+
4+
// Multiple interpolations
5+
"hello \(first) \(last)"
6+
7+
// Interpolation with expression
8+
"result: \(x + y)"
9+
10+
// Plain string before and after interpolation
11+
"prefix \(value) suffix"
12+
13+
// Calls to custom DefaultStringInterpolation.appendInterpolation impls
14+
"foo \(x, y)"
15+
"foo \(x, y, z)"
16+
"foo \(arg: x)"
17+
"foo \(arg: x, arg2: y)"

0 commit comments

Comments
 (0)