You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: TSPL.docc/LanguageGuide/Macros.md
+54-41Lines changed: 54 additions & 41 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,11 +1,11 @@
1
1
# Macros
2
2
3
-
Transform code at compile time to generate repetitive code.
3
+
Use macros to generate code at compile time.
4
4
5
5
Macros transform your source code when you compile it,
6
6
letting you avoid writing repetitive code by hand.
7
7
During compilation,
8
-
Swift expands macros before building your code as usual.
8
+
Swift expands any macros in your code before building your code as usual.
9
9
10
10

11
11
@@ -23,7 +23,7 @@ if the macro's implementation encounters an error when expanding that macro,
23
23
the compiler treats this as a compilation error.
24
24
These guarantees make it easier to reason about code that uses macros,
25
25
and they make it easier to identify issues
26
-
like using macro incorrectly
26
+
like using a macro incorrectly
27
27
or a macro implementation that has a bug.
28
28
29
29
Swift has two kinds of macros:
@@ -46,19 +46,26 @@ and you write any arguments to the macro in parentheses after its name.
46
46
For example:
47
47
48
48
```swift
49
-
let currentFunctionName =#function
50
-
#warning("Something's wrong")
49
+
funcmyFunction() {
50
+
print("Currently running \(#function)")
51
+
#warning("Something's wrong")
52
+
}
51
53
```
52
54
53
55
In the first line,
54
-
`#function` calls the `function` macro from the Swift standard library.
56
+
`#function` calls the [`function`][] macro from the Swift standard library.
55
57
When you compile this code,
56
58
Swift calls that macro's implementation,
57
59
which replaces `#function` with the name of the current function.
60
+
When you run this code and call `myFunction()`,
61
+
it prints `Currently running myFunction()`.
58
62
In the second line,
59
-
`#warning` calls another macro from the standard library
63
+
`#warning` calls the [`warning(_:)`][]macro from the Swift standard library
Freestanding macros can produce a value, like `#function` does,
63
70
or they can perform an action at compile time, like `#warning` does.
64
71
<!-- SE-0397: or they can generate new declarations. -->
@@ -144,20 +151,20 @@ comes from the `@OptionSet` macro.
144
151
The version of `SundaeToppings`
145
152
that uses a macro to generate all of the static variables
146
153
is easier to read and easier to maintain
147
-
than the manual-coded version, earlier.
154
+
than the manually coded version, earlier.
148
155
149
156
## Macro Declarations
150
157
151
158
In most Swift code,
152
-
you implement a symbol, like a function or type,
153
-
and there's no separate declaration.
159
+
when you implement a symbol, like a function or type,
160
+
there's no separate declaration.
154
161
However, for macros, the declaration and implementation are separate.
155
-
A macro's implementation contains the code
156
-
that expands the macro by generating Swift code,
157
-
and its declaration
158
-
as well as the macro's name, the parameters it takes,
162
+
A macro's declaration contains its name,
163
+
the parameters it takes,
159
164
where it can be used,
160
165
and what kind of code it generates.
166
+
A macro's implementation contains the code
167
+
that expands the macro by generating Swift code.
161
168
162
169
You introduce a macro declaration with the `macro` keyword.
163
170
For example,
@@ -170,18 +177,18 @@ public macro OptionSet<RawType>() =
170
177
```
171
178
172
179
The first line
173
-
specifies the macro's name, `OptionSet`,
174
-
and the arguments that takes, in this case none.
180
+
specifies the macro's name and its arguments ---
181
+
the name is `OptionSet`, and it doesn't take any arguments.
175
182
The second line
176
183
uses the `#externalMacro(module:type:)` macro from the Swift standard library
177
-
to tell Swift where the macro's implementation is.
184
+
to tell Swift where the macro's implementation is located.
178
185
In this case,
179
186
the `SwiftMacros` module
180
187
contains a type named `OptionSetMacro`,
181
188
which implements the `@OptionSet` macro.
182
189
183
190
Because `OptionSet` is an attached macro,
184
-
its name uses upper camel case
191
+
its name uses upper camel case,
185
192
like the names for structures and classes.
186
193
Freestanding macros have lower camel case names,
187
194
like the names for variables and functions.
@@ -198,7 +205,7 @@ and the kinds of code the macro can generate.
198
205
Every macro has one or more roles,
199
206
which you write as part of the attributes
200
207
at the beginning of the macro declaration.
201
-
Here's a partial declaration of `@OptionSet`,
208
+
Here's a bit more of the declaration for`@OptionSet`,
202
209
including the attributes for its roles:
203
210
204
211
```swift
@@ -230,6 +237,13 @@ public macro line<T: ExpressibleByIntegerLiteral>() -> T =
230
237
/* ... location of the macro implementation... */
231
238
```
232
239
240
+
<!--
241
+
Elided the implementation of #line above
242
+
because it's a compiler built-in:
243
+
244
+
public macro line<T: ExpressibleByIntegerLiteral>() -> T = Builtin.LineMacro
245
+
-->
246
+
233
247
The `#line` macro above has the `expression` role.
234
248
An expression macro produces a value,
235
249
or performs a compile-time action like generating a warning.
@@ -261,22 +275,24 @@ the macro declaration lists them explicitly.
261
275
The macro declaration also includes `arbitrary` after the list of names,
262
276
allowing the macro to generate declarations
263
277
whose names aren't known until you use the macro.
264
-
In this case,
265
-
for each case in the private `Options` enumeration,
266
-
`@OptionSet` generates a corresponding declaration with the same name.
278
+
For example,
279
+
when the `@OptionSet` macro is applied to the `SundaeToppings` above,
280
+
it generates type properties that correspond to the enumeration cases,
281
+
`nuts`, `cherry`, and `fudge`.
267
282
268
283
For more information,
269
284
including a full list of macro roles,
270
285
see <doc:Attributes#attached> and <doc:Attributes#freestanding>
271
-
in <doc:Attributes>
286
+
in <doc:Attributes>.
272
287
273
288
## Macro Expansion
274
289
275
-
As part of building Swift code that uses macros,
276
-
the compiler and the macro's implementation
277
-
pass that code back and forth to expand the macros.
290
+
When building Swift code that uses macros,
291
+
the compiler calls the macros' implementation to expand them.
278
292
279
-
Macros are expanded as follows:
293
+

294
+
295
+
Specifically, Swift expands macros in the following way:
280
296
281
297
1. The compiler reads the code,
282
298
creating an in-memory representation of the syntax.
@@ -290,29 +306,25 @@ Macros are expanded as follows:
290
306
1. The compiler continues with compilation,
291
307
using the expanded source code.
292
308
293
-
These steps transform the code as shown below:
294
-
295
-

296
-
297
309
To go through the specific steps, consider the following:
298
310
299
311
```
300
312
let magicNumber = #fourCharacterCode("ABCD")
301
313
```
302
314
303
315
The `#fourCharacterCode` macro takes a string that's four characters long
304
-
and returns a unsigned 32-bit integer
316
+
and returns an unsigned 32-bit integer
305
317
that corresponds to the ASCII values in the string joined together.
306
318
Some file formats use integers like this to identify data
307
319
because they're compact but still readable in a debugger.
308
-
The <doc:Macros#Implementing-Macros> section below
320
+
The <doc:Macros#Implementing-a-Macro> section below
309
321
shows how to implement this macro.
310
322
311
323
To expand the macros in the code above,
312
324
the compiler reads the Swift file
313
325
and creates an in-memory representation of that code
314
326
known an as *abstract syntax tree*, or AST.
315
-
The AST makes the code's meaning and structure explicit,
327
+
The AST makes the code's structure explicit,
316
328
which makes it easier to write code that interacts with that structure ---
317
329
like a compiler or a macro implementation.
318
330
Here's a representation of the AST for the code above,
@@ -322,15 +334,16 @@ slightly simplified by omitting some extra detail:
322
334
323
335
The diagram above shows how the structure of this code
324
336
is represented in memory.
325
-
Each of the elements in the AST
326
-
corresponds to part of the source code's meaning.
337
+
Each element in the AST
338
+
corresponds to a part of the source code.
327
339
The "Constant declaration" AST element
328
340
has two child elements under it,
329
341
which represent the two parts of a constant declaration:
330
342
its name and its value.
331
343
The "Macro call" element has child elements
332
344
that represent the macro's name
333
345
and the list of arguments being passed to the macro.
346
+
334
347
As part of constructing this AST,
335
348
the compiler checks that the source code is valid Swift.
336
349
For example, `#fourCharacterCode` takes a single argument,
@@ -370,7 +383,7 @@ by restricting the code that implements macros:
370
383
In addition to these safeguards,
371
384
the macro's author is responsible for not reading or modifying anything
372
385
outside of the macro's inputs.
373
-
For example, a macro's expansion can't depend on the current time of day.
386
+
For example, a macro's expansion must not depend on the current time of day.
374
387
375
388
The implementation of `#fourCharacterCode`
376
389
generates a new AST containing the expanded code.
@@ -469,7 +482,7 @@ and `MyProject` makes those macros available.
469
482
470
483
The implementation of a macro
471
484
uses the [SwiftSyntax][] module to interact with Swift code
472
-
in a structured way, using an abstract syntax trees (AST).
485
+
in a structured way, using an AST.
473
486
If you created a new macro package with Swift Package Manager,
474
487
the generated `Package.swift` file
475
488
automatically includes a dependency on SwiftSyntax.
@@ -538,7 +551,7 @@ conforms to the `ExpressionMacro` protocol.
538
551
The `ExpressionMacro` protocol has one requirement,
539
552
a `expansion(of:in:)` method that expands the AST.
540
553
For the list of macro roles and their corresponding SwiftSystem protocols,
541
-
see <doc:Attributes#attached> and <doc:Attributes:freestanding>
554
+
see <doc:Attributes#attached> and <doc:Attributes#freestanding>
0 commit comments