0
# Expressions and Reification
1
2
Typed AST wrappers and reification system for converting between runtime values and compile-time AST representations. Expressions provide a bridge between runtime computation and compile-time code generation and manipulation.
3
4
## Capabilities
5
6
### Expression Wrapper
7
8
Typed wrapper around AST trees providing type-safe access to code representations.
9
10
```scala { .api }
11
/**
12
* Typed expression wrapper providing access to AST and type information
13
*/
14
trait ExprApi[+T] { this: Expr[T] =>
15
/** Underlying abstract syntax tree */
16
def tree: Tree
17
18
/** Static type as determined at compile time */
19
def staticType: Type
20
21
/** Actual type considering runtime type refinements */
22
def actualType: Type
23
24
/** Splice the expression back into code context */
25
def splice: T
26
27
/** Convert to different universe */
28
def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U#Expr[T]
29
}
30
31
/**
32
* Create expression wrapper from tree
33
*/
34
def Expr[T: WeakTypeTag](tree: Tree): Expr[T]
35
```
36
37
**Basic Expression Usage:**
38
39
```scala
40
import scala.reflect.runtime.universe._
41
42
// Create expressions from values
43
val intExpr = Expr[Int](Literal(Constant(42)))
44
val stringExpr = Expr[String](Literal(Constant("hello")))
45
46
println(s"Int expression tree: ${intExpr.tree}")
47
println(s"Int expression type: ${intExpr.staticType}")
48
println(s"String expression tree: ${stringExpr.tree}")
49
println(s"String expression type: ${stringExpr.staticType}")
50
51
// Access expression properties
52
def analyzeExpression[T](expr: Expr[T]): Unit = {
53
println(s"Tree: ${expr.tree}")
54
println(s"Static type: ${expr.staticType}")
55
println(s"Actual type: ${expr.actualType}")
56
println(s"Tree class: ${expr.tree.getClass.getSimpleName}")
57
println()
58
}
59
60
analyzeExpression(intExpr)
61
analyzeExpression(stringExpr)
62
```
63
64
### Reification
65
66
Converting runtime expressions and values into compile-time AST representations.
67
68
```scala { .api }
69
/**
70
* Reify runtime expressions into AST form
71
*/
72
def reify[T](expr: T): Expr[T]
73
74
/**
75
* Reification with explicit type
76
*/
77
def reifyType[T: TypeTag](expr: T): Expr[T]
78
79
/**
80
* Reify expressions with free variables
81
*/
82
def reifyEnclosingRuntimeClass[T](expr: T): Expr[T]
83
```
84
85
**Reification Examples:**
86
87
```scala
88
import scala.reflect.runtime.universe._
89
90
// Simple value reification
91
val numReified = reify(42)
92
val stringReified = reify("Hello World")
93
val boolReified = reify(true)
94
95
println(s"Number: ${numReified.tree}")
96
println(s"String: ${stringReified.tree}")
97
println(s"Boolean: ${boolReified.tree}")
98
99
// Expression reification
100
val mathReified = reify(2 + 3 * 4)
101
val comparisonReified = reify(10 > 5)
102
103
println(s"Math: ${mathReified.tree}")
104
println(s"Comparison: ${comparisonReified.tree}")
105
106
// Complex expression reification
107
val complexReified = reify {
108
val x = 10
109
val y = 20
110
if (x < y) x + y else x - y
111
}
112
113
println(s"Complex: ${complexReified.tree}")
114
115
// Method call reification
116
def greet(name: String): String = s"Hello $name"
117
val methodCallReified = reify(greet("Alice"))
118
119
println(s"Method call: ${methodCallReified.tree}")
120
```
121
122
### Splicing
123
124
Converting AST representations back into runtime values and expressions.
125
126
```scala { .api }
127
/**
128
* Splice expressions back into code context
129
*/
130
trait Splicing {
131
/** Splice expression into surrounding code */
132
def splice[T](expr: Expr[T]): T
133
134
/** Splice with explicit evaluation context */
135
def eval[T](expr: Expr[T]): T
136
137
/** Splice tree directly */
138
def spliceTree[T](tree: Tree): T
139
}
140
```
141
142
**Splicing Examples:**
143
144
```scala
145
import scala.reflect.runtime.universe._
146
147
// Create expressions
148
val addExpr = reify(5 + 3)
149
val stringExpr = reify("Hello".toUpperCase)
150
151
// Splice back to values (conceptual - actual splicing happens at compile time)
152
// In practice, splicing is primarily used within macro contexts
153
154
println(s"Add expression: ${addExpr.tree}")
155
println(s"String expression: ${stringExpr.tree}")
156
157
// Splicing in macro context example (conceptual)
158
def macroWithSplicing(c: scala.reflect.macros.blackbox.Context)(expr: c.Expr[Int]): c.Expr[String] = {
159
import c.universe._
160
161
// Create new expression using spliced value
162
val newExpr = reify {
163
val value = expr.splice // Splice the expression
164
s"The value is: $value"
165
}
166
167
newExpr
168
}
169
```
170
171
### Expression Transformation
172
173
Transforming expressions while preserving type information.
174
175
```scala { .api }
176
/**
177
* Expression transformation operations
178
*/
179
trait ExpressionTransformation[T] { this: Expr[T] =>
180
/** Transform underlying tree */
181
def transform(transformer: Tree => Tree): Expr[T]
182
183
/** Map over expression value */
184
def map[U: WeakTypeTag](f: T => U): Expr[U]
185
186
/** FlatMap over expression */
187
def flatMap[U: WeakTypeTag](f: T => Expr[U]): Expr[U]
188
189
/** Filter expression */
190
def filter(p: T => Boolean): Expr[Option[T]]
191
192
/** Combine with another expression */
193
def zip[U](other: Expr[U]): Expr[(T, U)]
194
}
195
```
196
197
**Expression Transformation Examples:**
198
199
```scala
200
import scala.reflect.runtime.universe._
201
202
// Create base expressions
203
val numExpr = reify(10)
204
val listExpr = reify(List(1, 2, 3, 4, 5))
205
206
// Transform expressions (conceptual API)
207
def transformExpression[T, U: WeakTypeTag](expr: Expr[T])(f: Tree => Tree): Expr[U] = {
208
val transformedTree = f(expr.tree)
209
Expr[U](transformedTree)
210
}
211
212
// Example transformation: double all numbers
213
val doubledExpr = transformExpression[Int, Int](numExpr) { tree =>
214
Apply(Select(tree, TermName("$times")), List(Literal(Constant(2))))
215
}
216
217
println(s"Original: ${numExpr.tree}")
218
println(s"Doubled: ${doubledExpr.tree}")
219
```
220
221
### Expression Composition
222
223
Composing multiple expressions into larger expressions.
224
225
```scala { .api }
226
/**
227
* Expression composition utilities
228
*/
229
object ExprComposition {
230
/** Combine two expressions with binary operation */
231
def combine[A, B, C: WeakTypeTag](
232
exprA: Expr[A],
233
exprB: Expr[B]
234
)(op: (A, B) => C): Expr[C]
235
236
/** Sequence multiple expressions */
237
def sequence[T: WeakTypeTag](exprs: List[Expr[T]]): Expr[List[T]]
238
239
/** Conditional expression composition */
240
def conditional[T: WeakTypeTag](
241
condition: Expr[Boolean],
242
thenExpr: Expr[T],
243
elseExpr: Expr[T]
244
): Expr[T]
245
246
/** Block expression from statements and result */
247
def block[T: WeakTypeTag](
248
statements: List[Expr[Any]],
249
result: Expr[T]
250
): Expr[T]
251
}
252
```
253
254
**Expression Composition Examples:**
255
256
```scala
257
import scala.reflect.runtime.universe._
258
259
// Create component expressions
260
val aExpr = reify(10)
261
val bExpr = reify(20)
262
val condExpr = reify(true)
263
264
// Combine expressions
265
val addExpr = reify(aExpr.splice + bExpr.splice)
266
val multExpr = reify(aExpr.splice * bExpr.splice)
267
268
println(s"Add: ${addExpr.tree}")
269
println(s"Multiply: ${multExpr.tree}")
270
271
// Conditional expression
272
val conditionalExpr = reify {
273
if (condExpr.splice) aExpr.splice else bExpr.splice
274
}
275
276
println(s"Conditional: ${conditionalExpr.tree}")
277
278
// Block expression
279
val blockExpr = reify {
280
val temp1 = aExpr.splice
281
val temp2 = bExpr.splice
282
temp1 + temp2
283
}
284
285
println(s"Block: ${blockExpr.tree}")
286
```
287
288
### Expression Analysis
289
290
Analyzing expressions for various properties and patterns.
291
292
```scala { .api }
293
/**
294
* Expression analysis utilities
295
*/
296
object ExpressionAnalysis {
297
/** Check if expression is pure (no side effects) */
298
def isPure[T](expr: Expr[T]): Boolean
299
300
/** Extract free variables from expression */
301
def freeVariables[T](expr: Expr[T]): Set[String]
302
303
/** Get expression complexity score */
304
def complexity[T](expr: Expr[T]): Int
305
306
/** Check if expression contains specific patterns */
307
def containsPattern[T](expr: Expr[T], pattern: Tree => Boolean): Boolean
308
309
/** Extract all method calls from expression */
310
def extractMethodCalls[T](expr: Expr[T]): List[(String, List[Tree])]
311
312
/** Get all referenced types */
313
def referencedTypes[T](expr: Expr[T]): Set[Type]
314
}
315
```
316
317
**Expression Analysis Examples:**
318
319
```scala
320
import scala.reflect.runtime.universe._
321
322
def analyzeExpression[T](expr: Expr[T]): Unit = {
323
println(s"=== Analyzing Expression ===")
324
println(s"Tree: ${expr.tree}")
325
println(s"Type: ${expr.staticType}")
326
327
// Manual analysis functions (conceptual implementations)
328
def countNodes(tree: Tree): Int = {
329
1 + tree.children.map(countNodes).sum
330
}
331
332
def findLiterals(tree: Tree): List[Any] = {
333
tree.collect {
334
case Literal(Constant(value)) => value
335
}
336
}
337
338
def findIdentifiers(tree: Tree): List[String] = {
339
tree.collect {
340
case Ident(name) => name.toString
341
}
342
}
343
344
def findMethodCalls(tree: Tree): List[String] = {
345
tree.collect {
346
case Apply(Select(_, name), _) => name.toString
347
case Apply(Ident(name), _) => name.toString
348
}
349
}
350
351
println(s"Node count: ${countNodes(expr.tree)}")
352
println(s"Literals: ${findLiterals(expr.tree)}")
353
println(s"Identifiers: ${findIdentifiers(expr.tree)}")
354
println(s"Method calls: ${findMethodCalls(expr.tree)}")
355
println()
356
}
357
358
// Analyze various expressions
359
analyzeExpression(reify(42))
360
analyzeExpression(reify("hello".toUpperCase))
361
analyzeExpression(reify(List(1, 2, 3).map(_ * 2).sum))
362
analyzeExpression(reify {
363
val x = 10
364
val y = 20
365
if (x < y) x + y else x * y
366
})
367
```
368
369
### Advanced Expression Patterns
370
371
Advanced patterns for working with expressions in complex scenarios.
372
373
```scala { .api }
374
/**
375
* Advanced expression patterns and utilities
376
*/
377
object AdvancedExpressionPatterns {
378
/** Partial evaluation of expressions */
379
def partialEval[T](expr: Expr[T]): Expr[T]
380
381
/** Expression memoization */
382
def memoize[T](expr: Expr[T]): Expr[T]
383
384
/** Expression optimization */
385
def optimize[T](expr: Expr[T]): Expr[T]
386
387
/** Dead code elimination */
388
def eliminateDeadCode[T](expr: Expr[T]): Expr[T]
389
390
/** Constant folding */
391
def foldConstants[T](expr: Expr[T]): Expr[T]
392
393
/** Expression serialization */
394
def serialize[T](expr: Expr[T]): String
395
396
/** Expression deserialization */
397
def deserialize[T: WeakTypeTag](serialized: String): Expr[T]
398
}
399
```
400
401
**Complete Expression and Reification Example:**
402
403
```scala
404
import scala.reflect.runtime.universe._
405
406
// Comprehensive expression manipulation example
407
object ExpressionWorkshop {
408
409
// Create various types of expressions
410
val simpleExpr = reify(42)
411
val stringExpr = reify("Hello World")
412
val mathExpr = reify(2 + 3 * 4)
413
val listExpr = reify(List(1, 2, 3, 4, 5))
414
415
val complexExpr = reify {
416
val numbers = List(1, 2, 3, 4, 5)
417
val doubled = numbers.map(_ * 2)
418
val filtered = doubled.filter(_ > 5)
419
filtered.sum
420
}
421
422
// Expression introspection
423
def inspectExpression[T](name: String, expr: Expr[T]): Unit = {
424
println(s"=== $name ===")
425
println(s"Tree: ${expr.tree}")
426
println(s"Static type: ${expr.staticType}")
427
println(s"Actual type: ${expr.actualType}")
428
println(s"Tree structure:")
429
printTreeStructure(expr.tree, 0)
430
println()
431
}
432
433
def printTreeStructure(tree: Tree, indent: Int): Unit = {
434
val spaces = " " * indent
435
println(s"$spaces${tree.getClass.getSimpleName}: $tree")
436
tree.children.foreach(printTreeStructure(_, indent + 1))
437
}
438
439
// Pattern matching on expressions
440
def analyzeExpressionPattern[T](expr: Expr[T]): String = {
441
expr.tree match {
442
case Literal(Constant(value)) =>
443
s"Literal value: $value (${value.getClass.getSimpleName})"
444
case Ident(name) =>
445
s"Identifier: $name"
446
case Apply(Select(obj, method), args) =>
447
s"Method call: $obj.$method(${args.mkString(", ")})"
448
case Apply(fun, args) =>
449
s"Function call: $fun(${args.mkString(", ")})"
450
case Block(statements, expr) =>
451
s"Block with ${statements.length} statements, result: $expr"
452
case If(condition, thenp, elsep) =>
453
s"Conditional: if ($condition) $thenp else $elsep"
454
case ValDef(mods, name, tpt, rhs) =>
455
s"Value definition: $name = $rhs"
456
case _ =>
457
s"Other: ${tree.getClass.getSimpleName}"
458
}
459
}
460
461
// Expression transformation
462
def transformExpression[T](expr: Expr[T]): Expr[T] = {
463
val transformer = new Transformer {
464
override def transform(tree: Tree): Tree = tree match {
465
// Double all integer literals
466
case Literal(Constant(n: Int)) =>
467
Literal(Constant(n * 2))
468
// Convert string literals to uppercase
469
case Literal(Constant(s: String)) =>
470
Literal(Constant(s.toUpperCase))
471
case _ =>
472
super.transform(tree)
473
}
474
}
475
476
Expr[T](transformer.transform(expr.tree))
477
}
478
479
// Run analysis
480
def runAnalysis(): Unit = {
481
// Inspect all expressions
482
inspectExpression("Simple", simpleExpr)
483
inspectExpression("String", stringExpr)
484
inspectExpression("Math", mathExpr)
485
inspectExpression("List", listExpr)
486
inspectExpression("Complex", complexExpr)
487
488
// Pattern analysis
489
println("=== Pattern Analysis ===")
490
println(s"Simple: ${analyzeExpressionPattern(simpleExpr)}")
491
println(s"String: ${analyzeExpressionPattern(stringExpr)}")
492
println(s"Math: ${analyzeExpressionPattern(mathExpr)}")
493
println(s"List: ${analyzeExpressionPattern(listExpr)}")
494
println()
495
496
// Transformation
497
println("=== Transformation ===")
498
val transformedSimple = transformExpression(simpleExpr)
499
val transformedString = transformExpression(stringExpr)
500
501
println(s"Original simple: ${simpleExpr.tree}")
502
println(s"Transformed simple: ${transformedSimple.tree}")
503
println(s"Original string: ${stringExpr.tree}")
504
println(s"Transformed string: ${transformedString.tree}")
505
506
// Expression composition
507
println("=== Composition ===")
508
val combinedExpr = reify {
509
val a = simpleExpr.splice
510
val b = transformedSimple.splice
511
a + b
512
}
513
println(s"Combined expression: ${combinedExpr.tree}")
514
}
515
}
516
517
// Run the workshop
518
ExpressionWorkshop.runAnalysis()
519
```