Reflection Library for the Scala Programming Language providing runtime reflection capabilities and metaprogramming support
—
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.
Typed wrapper around AST trees providing type-safe access to code representations.
/**
* Typed expression wrapper providing access to AST and type information
*/
trait ExprApi[+T] { this: Expr[T] =>
/** Underlying abstract syntax tree */
def tree: Tree
/** Static type as determined at compile time */
def staticType: Type
/** Actual type considering runtime type refinements */
def actualType: Type
/** Splice the expression back into code context */
def splice: T
/** Convert to different universe */
def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U#Expr[T]
}
/**
* Create expression wrapper from tree
*/
def Expr[T: WeakTypeTag](tree: Tree): Expr[T]Basic Expression Usage:
import scala.reflect.runtime.universe._
// Create expressions from values
val intExpr = Expr[Int](Literal(Constant(42)))
val stringExpr = Expr[String](Literal(Constant("hello")))
println(s"Int expression tree: ${intExpr.tree}")
println(s"Int expression type: ${intExpr.staticType}")
println(s"String expression tree: ${stringExpr.tree}")
println(s"String expression type: ${stringExpr.staticType}")
// Access expression properties
def analyzeExpression[T](expr: Expr[T]): Unit = {
println(s"Tree: ${expr.tree}")
println(s"Static type: ${expr.staticType}")
println(s"Actual type: ${expr.actualType}")
println(s"Tree class: ${expr.tree.getClass.getSimpleName}")
println()
}
analyzeExpression(intExpr)
analyzeExpression(stringExpr)Converting runtime expressions and values into compile-time AST representations.
/**
* Reify runtime expressions into AST form
*/
def reify[T](expr: T): Expr[T]
/**
* Reification with explicit type
*/
def reifyType[T: TypeTag](expr: T): Expr[T]
/**
* Reify expressions with free variables
*/
def reifyEnclosingRuntimeClass[T](expr: T): Expr[T]Reification Examples:
import scala.reflect.runtime.universe._
// Simple value reification
val numReified = reify(42)
val stringReified = reify("Hello World")
val boolReified = reify(true)
println(s"Number: ${numReified.tree}")
println(s"String: ${stringReified.tree}")
println(s"Boolean: ${boolReified.tree}")
// Expression reification
val mathReified = reify(2 + 3 * 4)
val comparisonReified = reify(10 > 5)
println(s"Math: ${mathReified.tree}")
println(s"Comparison: ${comparisonReified.tree}")
// Complex expression reification
val complexReified = reify {
val x = 10
val y = 20
if (x < y) x + y else x - y
}
println(s"Complex: ${complexReified.tree}")
// Method call reification
def greet(name: String): String = s"Hello $name"
val methodCallReified = reify(greet("Alice"))
println(s"Method call: ${methodCallReified.tree}")Converting AST representations back into runtime values and expressions.
/**
* Splice expressions back into code context
*/
trait Splicing {
/** Splice expression into surrounding code */
def splice[T](expr: Expr[T]): T
/** Splice with explicit evaluation context */
def eval[T](expr: Expr[T]): T
/** Splice tree directly */
def spliceTree[T](tree: Tree): T
}Splicing Examples:
import scala.reflect.runtime.universe._
// Create expressions
val addExpr = reify(5 + 3)
val stringExpr = reify("Hello".toUpperCase)
// Splice back to values (conceptual - actual splicing happens at compile time)
// In practice, splicing is primarily used within macro contexts
println(s"Add expression: ${addExpr.tree}")
println(s"String expression: ${stringExpr.tree}")
// Splicing in macro context example (conceptual)
def macroWithSplicing(c: scala.reflect.macros.blackbox.Context)(expr: c.Expr[Int]): c.Expr[String] = {
import c.universe._
// Create new expression using spliced value
val newExpr = reify {
val value = expr.splice // Splice the expression
s"The value is: $value"
}
newExpr
}Transforming expressions while preserving type information.
/**
* Expression transformation operations
*/
trait ExpressionTransformation[T] { this: Expr[T] =>
/** Transform underlying tree */
def transform(transformer: Tree => Tree): Expr[T]
/** Map over expression value */
def map[U: WeakTypeTag](f: T => U): Expr[U]
/** FlatMap over expression */
def flatMap[U: WeakTypeTag](f: T => Expr[U]): Expr[U]
/** Filter expression */
def filter(p: T => Boolean): Expr[Option[T]]
/** Combine with another expression */
def zip[U](other: Expr[U]): Expr[(T, U)]
}Expression Transformation Examples:
import scala.reflect.runtime.universe._
// Create base expressions
val numExpr = reify(10)
val listExpr = reify(List(1, 2, 3, 4, 5))
// Transform expressions (conceptual API)
def transformExpression[T, U: WeakTypeTag](expr: Expr[T])(f: Tree => Tree): Expr[U] = {
val transformedTree = f(expr.tree)
Expr[U](transformedTree)
}
// Example transformation: double all numbers
val doubledExpr = transformExpression[Int, Int](numExpr) { tree =>
Apply(Select(tree, TermName("$times")), List(Literal(Constant(2))))
}
println(s"Original: ${numExpr.tree}")
println(s"Doubled: ${doubledExpr.tree}")Composing multiple expressions into larger expressions.
/**
* Expression composition utilities
*/
object ExprComposition {
/** Combine two expressions with binary operation */
def combine[A, B, C: WeakTypeTag](
exprA: Expr[A],
exprB: Expr[B]
)(op: (A, B) => C): Expr[C]
/** Sequence multiple expressions */
def sequence[T: WeakTypeTag](exprs: List[Expr[T]]): Expr[List[T]]
/** Conditional expression composition */
def conditional[T: WeakTypeTag](
condition: Expr[Boolean],
thenExpr: Expr[T],
elseExpr: Expr[T]
): Expr[T]
/** Block expression from statements and result */
def block[T: WeakTypeTag](
statements: List[Expr[Any]],
result: Expr[T]
): Expr[T]
}Expression Composition Examples:
import scala.reflect.runtime.universe._
// Create component expressions
val aExpr = reify(10)
val bExpr = reify(20)
val condExpr = reify(true)
// Combine expressions
val addExpr = reify(aExpr.splice + bExpr.splice)
val multExpr = reify(aExpr.splice * bExpr.splice)
println(s"Add: ${addExpr.tree}")
println(s"Multiply: ${multExpr.tree}")
// Conditional expression
val conditionalExpr = reify {
if (condExpr.splice) aExpr.splice else bExpr.splice
}
println(s"Conditional: ${conditionalExpr.tree}")
// Block expression
val blockExpr = reify {
val temp1 = aExpr.splice
val temp2 = bExpr.splice
temp1 + temp2
}
println(s"Block: ${blockExpr.tree}")Analyzing expressions for various properties and patterns.
/**
* Expression analysis utilities
*/
object ExpressionAnalysis {
/** Check if expression is pure (no side effects) */
def isPure[T](expr: Expr[T]): Boolean
/** Extract free variables from expression */
def freeVariables[T](expr: Expr[T]): Set[String]
/** Get expression complexity score */
def complexity[T](expr: Expr[T]): Int
/** Check if expression contains specific patterns */
def containsPattern[T](expr: Expr[T], pattern: Tree => Boolean): Boolean
/** Extract all method calls from expression */
def extractMethodCalls[T](expr: Expr[T]): List[(String, List[Tree])]
/** Get all referenced types */
def referencedTypes[T](expr: Expr[T]): Set[Type]
}Expression Analysis Examples:
import scala.reflect.runtime.universe._
def analyzeExpression[T](expr: Expr[T]): Unit = {
println(s"=== Analyzing Expression ===")
println(s"Tree: ${expr.tree}")
println(s"Type: ${expr.staticType}")
// Manual analysis functions (conceptual implementations)
def countNodes(tree: Tree): Int = {
1 + tree.children.map(countNodes).sum
}
def findLiterals(tree: Tree): List[Any] = {
tree.collect {
case Literal(Constant(value)) => value
}
}
def findIdentifiers(tree: Tree): List[String] = {
tree.collect {
case Ident(name) => name.toString
}
}
def findMethodCalls(tree: Tree): List[String] = {
tree.collect {
case Apply(Select(_, name), _) => name.toString
case Apply(Ident(name), _) => name.toString
}
}
println(s"Node count: ${countNodes(expr.tree)}")
println(s"Literals: ${findLiterals(expr.tree)}")
println(s"Identifiers: ${findIdentifiers(expr.tree)}")
println(s"Method calls: ${findMethodCalls(expr.tree)}")
println()
}
// Analyze various expressions
analyzeExpression(reify(42))
analyzeExpression(reify("hello".toUpperCase))
analyzeExpression(reify(List(1, 2, 3).map(_ * 2).sum))
analyzeExpression(reify {
val x = 10
val y = 20
if (x < y) x + y else x * y
})Advanced patterns for working with expressions in complex scenarios.
/**
* Advanced expression patterns and utilities
*/
object AdvancedExpressionPatterns {
/** Partial evaluation of expressions */
def partialEval[T](expr: Expr[T]): Expr[T]
/** Expression memoization */
def memoize[T](expr: Expr[T]): Expr[T]
/** Expression optimization */
def optimize[T](expr: Expr[T]): Expr[T]
/** Dead code elimination */
def eliminateDeadCode[T](expr: Expr[T]): Expr[T]
/** Constant folding */
def foldConstants[T](expr: Expr[T]): Expr[T]
/** Expression serialization */
def serialize[T](expr: Expr[T]): String
/** Expression deserialization */
def deserialize[T: WeakTypeTag](serialized: String): Expr[T]
}Complete Expression and Reification Example:
import scala.reflect.runtime.universe._
// Comprehensive expression manipulation example
object ExpressionWorkshop {
// Create various types of expressions
val simpleExpr = reify(42)
val stringExpr = reify("Hello World")
val mathExpr = reify(2 + 3 * 4)
val listExpr = reify(List(1, 2, 3, 4, 5))
val complexExpr = reify {
val numbers = List(1, 2, 3, 4, 5)
val doubled = numbers.map(_ * 2)
val filtered = doubled.filter(_ > 5)
filtered.sum
}
// Expression introspection
def inspectExpression[T](name: String, expr: Expr[T]): Unit = {
println(s"=== $name ===")
println(s"Tree: ${expr.tree}")
println(s"Static type: ${expr.staticType}")
println(s"Actual type: ${expr.actualType}")
println(s"Tree structure:")
printTreeStructure(expr.tree, 0)
println()
}
def printTreeStructure(tree: Tree, indent: Int): Unit = {
val spaces = " " * indent
println(s"$spaces${tree.getClass.getSimpleName}: $tree")
tree.children.foreach(printTreeStructure(_, indent + 1))
}
// Pattern matching on expressions
def analyzeExpressionPattern[T](expr: Expr[T]): String = {
expr.tree match {
case Literal(Constant(value)) =>
s"Literal value: $value (${value.getClass.getSimpleName})"
case Ident(name) =>
s"Identifier: $name"
case Apply(Select(obj, method), args) =>
s"Method call: $obj.$method(${args.mkString(", ")})"
case Apply(fun, args) =>
s"Function call: $fun(${args.mkString(", ")})"
case Block(statements, expr) =>
s"Block with ${statements.length} statements, result: $expr"
case If(condition, thenp, elsep) =>
s"Conditional: if ($condition) $thenp else $elsep"
case ValDef(mods, name, tpt, rhs) =>
s"Value definition: $name = $rhs"
case _ =>
s"Other: ${tree.getClass.getSimpleName}"
}
}
// Expression transformation
def transformExpression[T](expr: Expr[T]): Expr[T] = {
val transformer = new Transformer {
override def transform(tree: Tree): Tree = tree match {
// Double all integer literals
case Literal(Constant(n: Int)) =>
Literal(Constant(n * 2))
// Convert string literals to uppercase
case Literal(Constant(s: String)) =>
Literal(Constant(s.toUpperCase))
case _ =>
super.transform(tree)
}
}
Expr[T](transformer.transform(expr.tree))
}
// Run analysis
def runAnalysis(): Unit = {
// Inspect all expressions
inspectExpression("Simple", simpleExpr)
inspectExpression("String", stringExpr)
inspectExpression("Math", mathExpr)
inspectExpression("List", listExpr)
inspectExpression("Complex", complexExpr)
// Pattern analysis
println("=== Pattern Analysis ===")
println(s"Simple: ${analyzeExpressionPattern(simpleExpr)}")
println(s"String: ${analyzeExpressionPattern(stringExpr)}")
println(s"Math: ${analyzeExpressionPattern(mathExpr)}")
println(s"List: ${analyzeExpressionPattern(listExpr)}")
println()
// Transformation
println("=== Transformation ===")
val transformedSimple = transformExpression(simpleExpr)
val transformedString = transformExpression(stringExpr)
println(s"Original simple: ${simpleExpr.tree}")
println(s"Transformed simple: ${transformedSimple.tree}")
println(s"Original string: ${stringExpr.tree}")
println(s"Transformed string: ${transformedString.tree}")
// Expression composition
println("=== Composition ===")
val combinedExpr = reify {
val a = simpleExpr.splice
val b = transformedSimple.splice
a + b
}
println(s"Combined expression: ${combinedExpr.tree}")
}
}
// Run the workshop
ExpressionWorkshop.runAnalysis()Install with Tessl CLI
npx tessl i tessl/maven-org-scala-lang--scala-reflect