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
Templates are a common abstraction in definition trees that is used in new expressions, classes, traits, objects, package objects. Although there is no interpolator for it at the moment we can illustrate its structure on the example of new expression (similar handling will applly to all other template-bearing trees):
68
68
@@ -111,9 +111,9 @@ So template consists of:
111
111
scala> val q"new { ..$body }" = q"new { val x = 1; def y = 'y }"
112
112
body: List[universe.Tree] = List(val x = 1, def y = scala.Symbol("y"))
113
113
114
-
## Val and Var Definitions {:#val-var}
114
+
## Val and Var Definitions
115
115
116
-
Vals and vars allow you to define immutable and mutable variables correspondingly. Additionally they are also used to represent [function](/overviews/quasiquotes/expression-details.html#function), [class](#class) and [method](#method) paremeters.
116
+
Vals and vars allow you to define immutable and mutable variables correspondingly. Additionally they are also used to represent [function](/overviews/quasiquotes/expression-details.html#function), [class](#class-definition) and [method](#method-definition) paremeters.
117
117
118
118
Each val and var consistents of four components: modifiers, name, type tree and a right hand side:
119
119
@@ -126,7 +126,7 @@ Each val and var consistents of four components: modifiers, name, type tree and
126
126
tpt: universe.Tree = <type ?>
127
127
rhs: universe.Tree = 2
128
128
129
-
If type of the val isn't explicitly specified by the user an [empty type](/overviews/quasiquotes/type-details.html#empty) is used as tpt.
129
+
If type of the val isn't explicitly specified by the user an [empty type](/overviews/quasiquotes/type-details.html#empty-type) is used as tpt.
130
130
131
131
Vals and vars are disjoint (they don't match one another):
132
132
@@ -142,7 +142,7 @@ Vars always have `MUTABLE` flag in their modifiers:
142
142
tpt: universe.Tree = <type ?>
143
143
rhs: universe.Tree = 2
144
144
145
-
## Pattern Definitions {:#pattern}
145
+
## Pattern Definitions
146
146
147
147
Pattern definitions allow to use scala pattern matching capabilities to define variables. Unlike
148
148
val and var definitions, pattern definitions are not first-class and they are get represented
@@ -202,7 +202,7 @@ Simiarly one can also construct a mutable pattern definition:
202
202
203
203
q"$mods var $pat: $tpt = $rhs"
204
204
205
-
## Type Definition {:#type}
205
+
## Type Definition
206
206
207
207
Type definition have two possible shapes: abstract type definitions and alias type definitions.
208
208
@@ -237,7 +237,7 @@ Due to low level uniform representation of type aliases and abstract types one m
237
237
238
238
Where `tpt` has a `TypeBoundsTree(low, high)` shape.
239
239
240
-
## Method Definition {:#method}
240
+
## Method Definition
241
241
242
242
Each method consists of modifiers, name, type arguments, value arguments, return type and a body:
243
243
@@ -249,7 +249,7 @@ Each method consists of modifiers, name, type arguments, value arguments, return
249
249
tpt: universe.Tree = <type ?>
250
250
body: universe.Tree = 1
251
251
252
-
Type arguments are [type definitions](#type) and value arguments are [val definitions](#val-var). Inferred return type is represented as [empty type](/overviews/quasiquotes/type-details.html#empty). If body of the method is [empty expression](/overviews/quasiquotes/expression-details.html#empty) it means that method is abstract.
252
+
Type arguments are [type definitions](#type-definition) and value arguments are [val definitions](#val-and-var-definitions). Inferred return type is represented as [empty type](/overviews/quasiquotes/type-details.html#empty-type). If body of the method is [empty expression](/overviews/quasiquotes/expression-details.html#empty) it means that method is abstract.
253
253
254
254
Alternatively you can also deconstruct arguments separating implicit and non-implicit parameters:
255
255
@@ -267,7 +267,7 @@ This way of parameter handling will still work if method doesn\'t have any impli
267
267
implparams: List[universe.ValDef] = List()
268
268
body: universe.Tree = x.$plus(y)
269
269
270
-
## Secondary Constructor Definition {:#ctor}
270
+
## Secondary Constructor Definition
271
271
272
272
Secondary constructors are special kinds of methods that have following shape:
273
273
@@ -288,19 +288,19 @@ Due to low level underlying representation of trees secondary constructors are r
288
288
tpt: universe.Tree = <type ?>
289
289
body: universe.Tree = <init>(0)
290
290
291
-
## Class Definition {:#class}
291
+
## Class Definition
292
292
293
293
Classes have a following structure:
294
294
295
295
q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }"
296
296
297
297
As you probably already see the right part after extends is just a [template](#templates). Apart from it and modifiers classes
298
298
also have primary constructor which consists of constructor modifiers, type and value parameters which behave very much like
299
-
[method](#method) modifiers and parameters.
299
+
[method](#method-definition) modifiers and parameters.
300
300
301
-
## Trait Definition {:#trait}
301
+
## Trait Definition
302
302
303
-
Syntactically traits are quite similar to [classes](#class) sans value parameters and constructor modifiers:
303
+
Syntactically traits are quite similar to [classes](#class-definition) sans value parameters and constructor modifiers:
`q""` is used to indicate that some part of the tree is not provided by the user:
16
16
@@ -21,7 +21,7 @@ outof: 13
21
21
22
22
Default toString formats `q""` as `<empty>`.
23
23
24
-
## Literal {:#literal}
24
+
## Literal
25
25
26
26
Scala has a number of default built-in literals:
27
27
@@ -45,7 +45,7 @@ Thanks to [lifting](/overviews/quasiquotes/lifting.html) you can also easily cre
45
45
scala> val one = q"$x"
46
46
one: universe.Tree = 1
47
47
48
-
This would work the same way for all literal types (see [standard liftables](/overviews/quasiquotes/lifting.html#standard) except `Null`. Lifting of `null` value and `Null` type isn't supported, use `q"null"` if you really mean to create null literal:
48
+
This would work the same way for all literal types (see [standard liftables](/overviews/quasiquotes/lifting.html#standard-liftables) except `Null`. Lifting of `null` value and `Null` type isn't supported, use `q"null"` if you really mean to create null literal:
49
49
50
50
scala> val x = null
51
51
scala> q"$x"
@@ -58,9 +58,9 @@ During deconstruction you can use [unlifting](/overviews/quasiquotes/unlifting.h
58
58
scala> val q"${x: Int}" = q"1"
59
59
x: Int = 1
60
60
61
-
Similarly it would work with all the literal types except `Null`. (see [standard unliftables](/overviews/quasiquotes/unlifting.html#standard))
61
+
Similarly it would work with all the literal types except `Null`. (see [standard unliftables](/overviews/quasiquotes/unlifting.html#standard-unliftables))
62
62
63
-
## Identifier and Selection {:#ref}
63
+
## Identifier and Selection
64
64
65
65
Identifiers and member selections are two fundamental primitives that let you refer to other definitions. Combination of two of them is also known `RefTree`.
66
66
@@ -98,7 +98,7 @@ Similarly you can create and extract member selections:
98
98
scala> val q"foo.$name" = selected
99
99
name: universe.TermName = bar
100
100
101
-
## Super and This {:#super-this}
101
+
## Super and This
102
102
103
103
One can use this and super to select precise members within inheritance chain.
104
104
@@ -129,7 +129,7 @@ Similarly for super we have:
129
129
qual: universe.TypeName = T
130
130
field: universe.Name = foo
131
131
132
-
## Application and Type Application {:#application}
132
+
## Application and Type Application
133
133
134
134
Value applications and type applications are two fundamental parts out of which one can construct calls to Scala functions and methods. Lets assume that we would like to handle function calls to the following method:
135
135
@@ -187,7 +187,7 @@ Similarly to type arguments, implicit value arguments are automatically inferred
187
187
stats: List[universe.Tree] = List(def g(x: Int)(implicit y: Int): Int = x.+(y), implicit val y: Int = 3)
Assign and update are two related ways to explictly mutate a variable or collection:
193
193
@@ -222,7 +222,7 @@ On the other hand if you want to treat this two cases separately it's also possi
222
222
update array at List(0) with 1
223
223
224
224
225
-
## Return {:#return}
225
+
## Return
226
226
227
227
Return expressions is used to perform early return from a function.
228
228
@@ -232,7 +232,7 @@ Return expressions is used to perform early return from a function.
232
232
scala> val q"return $expr" = ret
233
233
expr: universe.Tree = 2.$plus(2)
234
234
235
-
## Throw {:#throw}
235
+
## Throw
236
236
237
237
Throw expression is used to throw a throwable:
238
238
@@ -242,7 +242,7 @@ Throw expression is used to throw a throwable:
242
242
scala> val q"throw $expr" = thr
243
243
expr: universe.Tree = new Exception()
244
244
245
-
## Ascription {:#ascription}
245
+
## Ascription
246
246
247
247
Ascriptions lets users to annotate type of intermidiate expression:
248
248
@@ -253,7 +253,7 @@ Ascriptions lets users to annotate type of intermidiate expression:
253
253
expr: universe.Tree = 1.$plus(1)
254
254
tpt: universe.Tree = Int
255
255
256
-
## Annotation {:#annotated}
256
+
## Annotation
257
257
258
258
Expressions can be annotated:
259
259
@@ -270,9 +270,9 @@ It's important to mention that such pattern won't match if we combine annotation
270
270
scala.MatchError: (1.$plus(1): Int @positive) (of class scala.reflect.internal.Trees$Typed)
271
271
... 32 elided
272
272
273
-
In this case we need to deconstruct it as [ascription](#ascription) and then deconstruct `tpt` as [annotated type](/overviews/quasiquotes/type-details.html#annotated).
273
+
In this case we need to deconstruct it as [ascription](#ascription) and then deconstruct `tpt` as [annotated type](/overviews/quasiquotes/type-details.html#annotated-type).
274
274
275
-
## Tuple {:#tuple}
275
+
## Tuple
276
276
277
277
Tuples are heteregeneous data structures with built-in user-friendly syntax. The syntax itself is just a sugar that maps onto `scala.TupleN` calls:
278
278
@@ -313,7 +313,7 @@ And unit as nullary tuple:
313
313
scala> val q"(..$elems)" = q"()"
314
314
elems: List[universe.Tree] = List()
315
315
316
-
## Block {:#block}
316
+
## Block
317
317
318
318
Blocks are a fundamental primitive to express sequence of actions or bindings. `q"..."` interpolator is an equivalent of a block. It allows to express more than one expression seperated by semicolon or a newline:
319
319
@@ -383,9 +383,9 @@ Zero-element block is equivalent to synthetic unit (one that was inserted by the
383
383
scala> val syntheticUnit = q"..$stats"
384
384
syntheticUnit: universe.Tree = ()
385
385
386
-
Such units are used in empty else branches of [ifs](#if) and empty bodies of [case clauses](#match) making it convenient to work with those cases as with zero-element blocks.
386
+
Such units are used in empty else branches of [ifs](#if) and empty bodies of [case clauses](#pattern-match) making it convenient to work with those cases as with zero-element blocks.
387
387
388
-
## If {:#if}
388
+
## If
389
389
390
390
There are two varieties of if expressions: those with else clause and without it:
391
391
@@ -401,7 +401,7 @@ There are two varieties of if expressions: those with else clause and without it
401
401
402
402
No-else clause is equivalent to else clause that contains a synthetic unit literal ([empty block](#block)).
403
403
404
-
## Pattern Match {:#match}
404
+
## Pattern Match
405
405
406
406
Pattern matching is cornerstone feature of Scala that lets you deconstruct values into their components:
407
407
@@ -433,7 +433,7 @@ Case clause without body is equivalent to one holding synthetic unit literal ([e
433
433
434
434
No-guard is represented with the help of [empty expression](#empty).
435
435
436
-
## Try {:#try}
436
+
## Try
437
437
438
438
Try expression is used to handle possible error conditions and ensure consistent state via finally. Both error handling cases and finally clause are optional.
439
439
@@ -454,9 +454,9 @@ Try expression is used to handle possible error conditions and ensure consistent
454
454
b: List[universe.CaseDef] = List()
455
455
c: universe.Tree = f
456
456
457
-
Similarly to [pattern matching](#match) cases can be further deconstructed with `cq"..."`. No-finally clause is represented with the help of [empty expression](#empty).
457
+
Similarly to [pattern matching](#pattern-match) cases can be further deconstructed with `cq"..."`. No-finally clause is represented with the help of [empty expression](#empty).
458
458
459
-
## Function {:#function}
459
+
## Function
460
460
461
461
There are three ways to create anonymous function:
462
462
@@ -474,8 +474,8 @@ on type inference to infer its type. Last one explicitly defines function parame
474
474
to implementation restriction second notation can only be used in parenthesis or inside other
475
475
expression. If you leave them out you have to specify parameter types.
476
476
477
-
Parameters are represented as [Vals](/overviews/quasiquotes/definition-details.html#val-var). If you want to programmatically create val that should have
478
-
its type inferred you need to use [empty type](/overviews/quasiquotes/type-details.html#empty):
477
+
Parameters are represented as [Vals](/overviews/quasiquotes/definition-details.html#val-and-var-definitions). If you want to programmatically create val that should have
478
+
its type inferred you need to use [empty type](/overviews/quasiquotes/type-details.html#empty-type):
479
479
480
480
scala> val tpt = tq""
481
481
tpt: universe.TypeTree = <type ?>
@@ -508,7 +508,7 @@ You can also tear arguments further apart:
508
508
It's recommended to use underscore pattern in place of [modifiers](/overviews/quasiquotes/definition-details.html#modifiers) even if you don't plan to work
509
509
with them as parameters may contains additional flags which might cause match errors.
510
510
511
-
## Partial Function {:#partial-function}
511
+
## Partial Function
512
512
513
513
Partial functions are a neat syntax that lets you express functions with
514
514
limited domain with the help of pattern matching:
@@ -528,7 +528,7 @@ trees for match expressions. Despite this fact they do not match one another:
528
528
scala> val q"$expr match { case ..$cases }" = pf
529
529
scala.MatchError: ...
530
530
531
-
## While and Do-While Loops {:#while}
531
+
## While and Do-While Loops
532
532
533
533
While and do-while loops are low-level control structures that used when performance of iteration
534
534
is critical:
@@ -563,7 +563,7 @@ is critical:
563
563
body: universe.Tree = x.$minus$eq(1)
564
564
cond: universe.Tree = x.$greater(0)
565
565
566
-
## For and For-Yield Loops {:#for}
566
+
## For and For-Yield Loops
567
567
568
568
For and For-Yield expressions allow to write monadic style comprehensions that desugar into calls to `map`, `flatMap`, `foreach` and `withFilter` methods:
569
569
@@ -595,7 +595,7 @@ It's important to mention that For and For-Yield do not cross-match each other:
595
595
scala> val q"for (..$enums) $body" = `for-yield`
596
596
scala.MatchError: ...
597
597
598
-
## New {:#new}
598
+
## New
599
599
600
600
New expression lets you construct an instance of given type possibly refining it with other types or definitions:
601
601
@@ -605,7 +605,7 @@ New expression lets you construct an instance of given type possibly refining it
605
605
606
606
See [templates](/overviews/quasiquotes/definition-details.html#templates) section for details.
607
607
608
-
## Import {:#import}
608
+
## Import
609
609
610
610
Import trees consist of reference and a list of selectors:
Copy file name to clipboardExpand all lines: overviews/quasiquotes/hygiene.md
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -16,7 +16,7 @@ Sophisticated macro systems such as Racket's have mechanisms that make macros hy
16
16
17
17
Preventing name clashes between regular and generated code means two things. First, we must ensure that regardless of the context in which we put generated code, its meaning isn't going to change (*referential transparency*). Second, we must make certain that regardless of the context in which we splice regular code, its meaning isn't going to change (often called *hygiene in the narrow sense*). Let's see what can be done to this end on a series of examples.
What referential transparency means is that quasiquotes should remember the lexical context in which they are defined. For instance, if there are imports provided at the definition site of the quasiquote, then these imports should be used to resolve names in the quasiquote. Unfortunately, this is not the case at the moment, and here's an example:
22
22
@@ -86,7 +86,7 @@ And wrapper will be resolved to `example.Test.wrapper` rather than intended `exa
86
86
q"$wrapper($x)"
87
87
}
88
88
89
-
## Hygiene in the narrow sense {:#hygiene-in-the-narrow-sense}
89
+
## Hygiene in the narrow sense
90
90
91
91
What hygiene in the narrow sense means is that quasiquotes shouldn't mess with the bindings of trees that are unquoted into them. For example, if a macro argument unquoted into a macro expansion was originally referring to some variable in enclosing lexical context, then this reference should remain in force after macro expansion, regardless of what code was generated for the macro expansion. Unfortunately, we don't have automatic facilities to ensure this, and that can lead to unexpected situations:
0 commit comments