@@ -3,34 +3,33 @@ layout: doc-page
3
3
title : " Macros"
4
4
---
5
5
6
- <!--
7
- Example introducing macros earlier, e.g.,
8
- http://dotty.epfl.ch/docs/reference/other-new-features/principled-meta-programming.html#relationship-with-inline-and-macros
9
-
10
-
11
- - Syntax (example through string interpolation)
12
- - Expr and Type
13
- - PCP
14
- - Quoted Functions and β-reduction
15
- - Types and PCP (e.g., healing)
16
- - Lifting
17
- - Expressions (http://dotty.epfl.ch/docs/reference/other-new-features/principled-meta-programming.html#the-liftable-type-class)
18
- - Types (http://dotty.epfl.ch/docs/reference/other-new-features/principled-meta-programming.html#lifting-types)
19
- - Scope Extrusion (needs new name)
20
- http://dotty.epfl.ch/docs/reference/other-new-features/principled-meta-programming.html#limitations-to-splicing
21
- - var references (e.g., let)
22
- - More Details include: spec syntax, formalization -->
23
-
24
6
### Macros: Quotes and Splices
25
7
26
8
Macros are built on two well-known fundamental operations: quotation and
27
9
splicing. Quotation is expressed as ` '{...} ` for expressions (both forms are
28
10
equivalent) and as ` '[...] ` for types. Splicing is expressed as ` ${ ... } ` .
11
+ Additionally, within a quote or a splice we can quote or splice identifiers
12
+ directly (i.e. ` 'e ` and ` $e ` ). Readers may notice the resemblance of the two
13
+ aforementioned syntactic schemes with the familiar string interpolation syntax.
14
+
15
+ ``` scala
16
+ println(s " Hello, $name, here is the result of 1 + 1 = ${1 + 1 }" )
17
+ ```
29
18
30
- For example, the code below presents an inline function ` assert `
31
- which calls at compile-time a method ` assertImpl ` with a boolean
32
- expression tree as argument. ` assertImpl ` evaluates the expression and
19
+ In string interpolation we _ quoted_ a string and then we _ spliced_ into it, two
20
+ others. The first, ` name ` , is a reference to a value of type ` string ` , and the
21
+ second is an arithmetic expression that will be _ evaluated_ followed by the
22
+ splicing of its string representation.
23
+
24
+ Quotes and splices in this section allow us to treat code in a similar way,
25
+ effectively supporting macros. The entry point for macros is an inline method
26
+ with a top-level splice. We call it a top-level because it is the only occation
27
+ where we encounter a splice outside a quote (consider as a quote the
28
+ compilation-unit at the call-site). For example, the code below presents an
29
+ ` inline ` method ` assert ` which calls at compile-time a method ` assertImpl ` with
30
+ a boolean expression tree as argument. ` assertImpl ` evaluates the expression and
33
31
prints it again in an error message if it evaluates to ` false ` .
32
+
34
33
``` scala
35
34
import scala .quoted ._
36
35
@@ -45,6 +44,7 @@ prints it again in an error message if it evaluates to `false`.
45
44
def showExpr (expr : Expr [Boolean ]): Expr [String ] =
46
45
' { " <some source code>" } // Better implementation later in this document
47
46
```
47
+
48
48
If ` e ` is an expression, then ` '{e} ` represent the typed
49
49
abstract syntax tree representing ` e ` . If ` T ` is a type, then ` '[T] `
50
50
represents the type structure representing ` T ` . The precise
@@ -264,7 +264,7 @@ several types including `Boolean`, `String`, and all primitive number
264
264
types. For example, ` Int ` values can be converted to ` Expr[Int] `
265
265
values by wrapping the value in a ` Literal ` tree node. This makes use
266
266
of the underlying tree representation in the compiler for
267
- efficiency. But the ` Liftable ` instances are nevertheless not "magic"
267
+ efficiency. But the ` Liftable ` instances are nevertheless not _ magic _
268
268
in the sense that they could all be defined in a user program without
269
269
knowing anything about the representation of ` Expr ` trees. For
270
270
instance, here is a possible instance of ` Liftable[Boolean] ` :
@@ -292,26 +292,26 @@ a `List` is liftable if its element type is:
292
292
``` scala
293
293
implied [T : Liftable ] for Liftable [List [T ]] {
294
294
def toExpr (xs : List [T ]): Expr [List [T ]] = xs match {
295
- case x :: xs1 => ' { $ { toExpr(x ) } :: $ { toExpr(xs1 ) } }
295
+ case head :: tail => ' { $ { toExpr(head ) } :: $ { toExpr(tail ) } }
296
296
case Nil => ' { Nil : List [T ] }
297
297
}
298
298
}
299
299
```
300
300
In the end, ` Liftable ` resembles very much a serialization
301
301
framework. Like the latter it can be derived systematically for all
302
302
collections, case classes and enums. Note also that the synthesis
303
- of "type-tag" values of type ` Type[T] ` is essentially the type-level
303
+ of _ type-tag _ values of type ` Type[T] ` is essentially the type-level
304
304
analogue of lifting.
305
305
306
306
Using lifting, we can now give the missing definition of ` showExpr ` in the introductory example:
307
307
``` scala
308
308
def showExpr [T ](expr : Expr [T ]): Expr [String ] = {
309
- val code = expr.show
309
+ val code : String = expr.show
310
310
code.toExpr
311
311
}
312
312
```
313
313
That is, the ` showExpr ` method converts its ` Expr ` argument to a string (` code ` ), and lifts
314
- the result back to an ` Expr[String] ` using the ` toExpr ` wrapper .
314
+ the result back to an ` Expr[String] ` using the ` toExpr ` method .
315
315
316
316
** Note** : the ` toExpr ` extension method can be ommited by importing an implicit
317
317
conversion with ` import scala.quoted.autolift._ ` . The programmer is able to
@@ -451,12 +451,12 @@ soundness: code in splices must be free of side effects. The restriction
451
451
prevents code like this:
452
452
453
453
``` scala
454
- var x : Expr [T ]
454
+ var x : Expr [T ] = ...
455
455
' { (y : T ) => $ { x = ' y ; 1 } }
456
456
```
457
457
458
- This code, if it was accepted, would "extrude" a reference to a quoted variable
459
- ` y ` from its scope. This means we an subsequently access a variable outside the
458
+ This code, if it was accepted, would _ extrude _ a reference to a quoted variable
459
+ ` y ` from its scope. This would subsequently allow access to a variable outside the
460
460
scope where it is defined, which is likely problematic. The code is clearly
461
461
phase consistent, so we cannot use PCP to rule it out. Instead we postulate a
462
462
future effect system that can guarantee that splices are pure. In the absence of
0 commit comments