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: _overviews/scala3-macros/tutorial/macros.md
+34-15Lines changed: 34 additions & 15 deletions
Original file line number
Diff line number
Diff line change
@@ -14,13 +14,16 @@ Macros enable us to do exactly this: treat **programs as data** and manipulate t
14
14
15
15
## Macros Treat Programs as Values
16
16
With a macro, we can treat programs as values, which allows us to analyze and generate them at compile time.
17
+
17
18
A Scala expression with type `T` is represented by an instance of the type `scala.quoted.Expr[T]`.
18
19
19
20
We will dig into the details of the type `Expr[T]`, as well as the different ways of analyzing and constructing instances, when talking about [Quoted Code][quotes] and [Reflection][tasty].
20
21
For now, it suffices to know that macros are metaprograms that manipulate expressions of type `Expr[T]`.
21
22
22
-
The following macro implementation simply prints the expression of the provided argument:
23
+
The following macro implementation prints the expression of the provided argument:
@@ -138,12 +141,25 @@ This can only succeed, if the expression directly contains the code of a value,
138
141
Instead of `valueOrAbort`, we could also use the `value` operation, which will return an `Option`.
139
142
This way we can report the error with a custom error message.
140
143
144
+
#### Reporting Custom Error Messages
145
+
146
+
The contextual `Quotes` parameter provides a `report` object that we can use to report a custom error message.
147
+
Within a macro implementation method, you can access the contextual `Quotes` parameter with the `quotes` method
148
+
(imported with `import scala.quoted.*`), then import the `report` object by `import quotes.reflect.report`.
149
+
150
+
#### Providing the Custom Error
151
+
152
+
We will provide the custom error message by calling `errorAndAbort` on the `report` object as follows:
141
153
```scala
142
-
...
143
-
importquotes.reflect.*
154
+
defpowerCode(
155
+
x: Expr[Double],
156
+
n: Expr[Int]
157
+
)(usingQuotes):Expr[Double] =
158
+
importquotes.reflect.report
144
159
(x.value, n.value) match
145
160
case (Some(base), Some(exponent)) =>
146
-
pow(base, exponent)
161
+
valvalue:Double= pow(base, exponent)
162
+
Expr(value)
147
163
case (Some(_), _) =>
148
164
report.errorAndAbort("Expected a known value for the exponent, but was "+ n.show, n)
149
165
case _ =>
@@ -154,30 +170,32 @@ Alternatively, we can also use the `Expr.unapply` extractor
154
170
155
171
```scala
156
172
...
157
-
importquotes.reflect.*
158
173
(x, n) match
159
174
case (Expr(base), Expr(exponent)) =>
160
-
pow(base, exponent)
175
+
valvalue:Double= pow(base, exponent)
176
+
Expr(value)
161
177
case (Expr(_), _) => ...
162
178
case _ => ...
163
179
```
164
-
The operations `value`, `valueOrError`, and `Expr.unapply` will work for all _primitive types_, _tuples_ of any arity, `Option`, `Seq`, `Set`, `Map`, `Either` and `StringContext`.
180
+
The operations `value`, `valueOrAbort`, and `Expr.unapply` will work for all _primitive types_, _tuples_ of any arity, `Option`, `Seq`, `Set`, `Map`, `Either` and `StringContext`.
165
181
Other types can also work if an `FromExpr` is implemented for it, we will [see this later][quotes].
166
182
167
183
168
184
### Showing Expressions
169
185
170
186
In the implementation of `inspectCode`, we have already seen how to convert expressions to the string representation of their _source code_ using the `.show` method.
171
187
This can be useful to perform debugging on macro implementations:
188
+
189
+
<!-- The below code example does not use multi-line string because it causes syntax highlighting to break -->
172
190
```scala
173
191
defdebugPowerCode(
174
192
x: Expr[Double],
175
193
n: Expr[Int]
176
194
)(usingQuotes):Expr[Double] =
177
195
println(
178
-
s"""powerCode
179
-
| x := ${x.show}
180
-
| n := ${n.show}""".stripMargin)
196
+
s"powerCode\n"+
197
+
s"x := ${x.show}\n"+
198
+
s"n := ${n.show}")
181
199
valcode= powerCode(x, n)
182
200
println(s" code := ${code.show}")
183
201
code
@@ -190,23 +208,24 @@ Varargs in Scala are represented with `Seq`, hence when we write a macro with a
190
208
It is possible to recover each individual argument (of type `Expr[T]`) using the `scala.quoted.Varargs` extractor.
0 commit comments