CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-scala-lang--scala-reflect

Reflection Library for the Scala Programming Language providing runtime reflection capabilities and metaprogramming support

Pending
Overview
Eval results
Files

macro-development.mddocs/

Macro Development

Compile-time reflection contexts for macro development including blackbox and whitebox macro support. Macros enable code generation and transformation at compile time, providing powerful metaprogramming capabilities.

Capabilities

Blackbox Context

Context for blackbox macros with restricted compile-time capabilities.

/**
 * Blackbox macro context providing compile-time reflection capabilities
 */
trait Context extends scala.reflect.macros.Aliases
               with scala.reflect.macros.Enclosures  
               with scala.reflect.macros.Names
               with scala.reflect.macros.Reifiers
               with scala.reflect.macros.Typers
               with scala.reflect.macros.Universe {
  
  /** The universe for this macro context */
  val universe: Universe
  
  /** Mirror for this macro context */
  val mirror: universe.Mirror
  
  /** The prefix expression (receiver) for this macro call */
  def prefix: Expr[_]
  
  /** Create expression wrapper */
  def Expr[T: WeakTypeTag](tree: universe.Tree): Expr[T]
  
  /** Issue compilation error */
  def error(pos: Position, msg: String): Unit
  
  /** Issue compilation warning */
  def warning(pos: Position, msg: String): Unit
  
  /** Issue compilation info message */
  def info(pos: Position, msg: String, force: Boolean): Unit
  
  /** Abort compilation with error */
  def abort(pos: Position, msg: String): Nothing
  
  /** Fresh name generation */
  def freshName(): String
  def freshName(name: String): String
  
  /** Enclosing position */
  def enclosingPosition: Position
  
  /** Macro application position */
  def macroApplication: Tree
}

Basic Blackbox Macro Example:

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros

// Macro implementation
def debugImpl(c: Context)(expr: c.Expr[Any]): c.Expr[Any] = {
  import c.universe._
  
  val exprCode = show(expr.tree)
  val debugTree = q"""
    {
      val result = $expr
      println(s"Debug: $exprCode = " + result)
      result
    }
  """
  
  c.Expr[Any](debugTree)
}

// Macro definition
def debug(expr: Any): Any = macro debugImpl

// Usage
debug(2 + 3)  // Prints: Debug: 2 + 3 = 5
debug("hello".toUpperCase)  // Prints: Debug: "hello".toUpperCase = HELLO

Whitebox Context

Context for whitebox macros with expanded compile-time capabilities.

/**
 * Whitebox macro context extending blackbox capabilities
 */
trait Context extends blackbox.Context {
  // Whitebox macros can refine their return type beyond what's declared
  // They have access to additional type information and can influence typing
}

Whitebox Macro Example:

import scala.reflect.macros.whitebox.Context
import scala.language.experimental.macros

// Whitebox macro that can refine return types
def selectDynamicImpl(c: Context)(name: c.Expr[String]): c.Expr[Any] = {
  import c.universe._
  
  name.tree match {
    case Literal(Constant(fieldName: String)) if fieldName == "length" =>
      // Return refined type - whitebox can specify exact return type
      c.Expr[Int](q"${c.prefix}.toString.length")
    case Literal(Constant(fieldName: String)) if fieldName == "upper" =>
      c.Expr[String](q"${c.prefix}.toString.toUpperCase")
    case _ =>
      c.abort(c.enclosingPosition, s"Unknown field: ${show(name.tree)}")
  }
}

class DynamicAccessor(value: Any) {
  def selectDynamic(name: String): Any = macro selectDynamicImpl
}

// Usage - whitebox can provide exact return types
val accessor = new DynamicAccessor("hello")
val len: Int = accessor.length      // Refined to Int
val upper: String = accessor.upper  // Refined to String

Macro Utilities and Context Operations

Common operations and utilities available in macro contexts.

/**
 * Macro context utilities and operations
 */
trait MacroUtils { this: Context =>
  /** Type checking */
  def typecheck(tree: Tree): Tree
  def typecheck(tree: Tree, mode: TypecheckMode): Tree
  def typecheck(tree: Tree, pt: Type): Tree
  
  /** Untypecheck tree (remove type information) */
  def untypecheck(tree: Tree): Tree
  
  /** Parse string as Scala code */
  def parse(code: String): Tree
  
  /** Show tree as code */
  def show(tree: Tree): String
  
  /** Show raw tree structure */
  def showRaw(tree: Tree): String
  
  /** Show type */
  def show(tpe: Type): String
  
  /** Fresh term name */
  def freshTermName(): TermName
  def freshTermName(prefix: String): TermName
  
  /** Fresh type name */
  def freshTypeName(): TypeName  
  def freshTypeName(prefix: String): TypeName
  
  /** Internal APIs */
  val internal: Internal
}

Macro Utilities Example:

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros

def printTypeInfoImpl(c: Context)(expr: c.Expr[Any]): c.Expr[Unit] = {
  import c.universe._
  
  // Get type information
  val exprType = expr.actualType
  val exprTree = expr.tree
  
  // Type checking
  val typecheckedTree = c.typecheck(exprTree)
  
  // Fresh names
  val tempVar = c.freshTermName("temp")
  
  // Generate debug info
  val debugInfo = show(exprTree)
  val typeInfo = show(exprType)
  val rawInfo = showRaw(exprTree)
  
  val result = q"""
    {
      val $tempVar = $expr
      println("Expression: " + $debugInfo)
      println("Type: " + $typeInfo)  
      println("Raw: " + $rawInfo)
      println("Value: " + $tempVar)
    }
  """
  
  c.Expr[Unit](result)
}

def printTypeInfo(expr: Any): Unit = macro printTypeInfoImpl

// Usage
printTypeInfo(List(1, 2, 3))
printTypeInfo("hello".length)
printTypeInfo(Map("a" -> 1, "b" -> 2))

Quasiquotes

String interpolation syntax for constructing and deconstructing ASTs.

/**
 * Quasiquote string interpolators for AST construction
 */
object Quasiquotes {
  /** Expression quasiquote */
  implicit class QuasiquoteExpr(val sc: StringContext) {
    def q(args: Any*): Tree = macro ???
  }
  
  /** Type quasiquote */  
  implicit class QuasiquoteType(val sc: StringContext) {
    def tq(args: Any*): Tree = macro ???
  }
  
  /** Pattern quasiquote */
  implicit class QuasiquotePattern(val sc: StringContext) {
    def pq(args: Any*): Tree = macro ???
  }
  
  /** Case definition quasiquote */
  implicit class QuasiquoteCaseDef(val sc: StringContext) {
    def cq(args: Any*): Tree = macro ???
  }
}

Quasiquotes Example:

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros

def loggerImpl(c: Context)(message: c.Expr[String]): c.Expr[Unit] = {
  import c.universe._
  
  // Using quasiquotes for AST construction
  val loggerTree = q"""
    {
      val timestamp = java.time.LocalDateTime.now()
      val logMessage = s"[$timestamp] ${$message}"
      println(logMessage)
    }
  """
  
  c.Expr[Unit](loggerTree)
}

def measureTimeImpl(c: Context)(expr: c.Expr[Any]): c.Expr[Any] = {
  import c.universe._
  
  val resultName = TermName(c.freshName("result"))
  val startName = TermName(c.freshName("start"))
  val endName = TermName(c.freshName("end"))
  
  // Quasiquote with variable substitution
  val timerTree = q"""
    {
      val $startName = System.nanoTime()
      val $resultName = $expr
      val $endName = System.nanoTime()
      val duration = ($endName - $startName) / 1000000.0
      println(s"Execution time: $duration ms")
      $resultName
    }
  """
  
  c.Expr[Any](timerTree)
}

def logger(message: String): Unit = macro loggerImpl  
def measureTime[T](expr: T): T = macro measureTimeImpl

// Usage
logger("Application started")
val result = measureTime {
  Thread.sleep(100)
  "Hello World"
}

Annotation Macros

Macros triggered by annotations for code transformation.

/**
 * Annotation macro support
 */
class MacroAnnotation extends scala.annotation.StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro MacroAnnotation.impl
}

object MacroAnnotation {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    
    // Transform annotated code
    val result = annottees.map(_.tree).toList match {
      case (classDecl @ q"$mods class $className(..$params) extends ..$parents { ..$body }") :: Nil =>
        // Transform class
        q"""
          $mods class $className(..$params) extends ..$parents {
            ..$body
            def generatedMethod: String = "Generated by macro annotation"
          }
        """
      case _ => c.abort(c.enclosingPosition, "Annotation can only be applied to classes")
    }
    
    c.Expr[Any](result)
  }
}

Annotation Macro Example:

import scala.reflect.macros.whitebox.Context
import scala.language.experimental.macros
import scala.annotation.{StaticAnnotation, compileTimeOnly}

@compileTimeOnly("enable macro paradise to expand macro annotations")
class toString extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro toString.impl
}

object toString {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    
    def generateToString(className: TypeName, params: List[ValDef]): DefDef = {
      val fieldAccess = params.map { param =>
        val name = param.name.toString
        q"$name + '=' + ${param.name}"
      }
      
      val toStringBody = if (fieldAccess.nonEmpty) {
        fieldAccess.reduce((acc, field) => q"$acc + ', ' + $field")
      } else {
        q"''"
      }
      
      q"override def toString: String = ${className.toString} + '(' + $toStringBody + ')'"
    }
    
    val result = annottees.map(_.tree).toList match {
      case (classDecl @ q"$mods class $className(..$params) extends ..$parents { ..$body }") :: Nil =>
        val toStringMethod = generateToString(className, params)
        q"""
          $mods class $className(..$params) extends ..$parents {
            ..$body
            $toStringMethod
          }
        """
      case _ => c.abort(c.enclosingPosition, "Can only annotate classes")
    }
    
    c.Expr[Any](result)
  }
}

// Usage
@toString
class Person(name: String, age: Int)

val person = new Person("Alice", 25)
println(person)  // Person(name=Alice, age=25)

Advanced Macro Patterns

Complex macro patterns for advanced metaprogramming.

/**
 * Advanced macro development patterns
 */
object AdvancedMacroPatterns {
  /** Type-level computation macro */
  def typeComputation[T](implicit c: Context, tag: c.WeakTypeTag[T]): c.Expr[String]
  
  /** Compile-time reflection macro */
  def reflectiveAccess(obj: Any, methodName: String): Any
  
  /** Code generation macro */
  def generateClass(className: String, fields: (String, String)*): Any
  
  /** Validation macro */
  def validate[T](expr: T): T
  
  /** Serialization macro */
  def serialize[T: Context#WeakTypeTag](obj: T): String
}

Complete Macro Development Example:

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros

// Comprehensive macro example with multiple features
object ComprehensiveMacros {
  
  // 1. Debug macro with type information
  def debugWithTypeImpl(c: Context)(expr: c.Expr[Any]): c.Expr[Any] = {
    import c.universe._
    
    val exprType = expr.actualType
    val exprString = show(expr.tree)
    val typeString = show(exprType)
    val pos = expr.tree.pos
    
    q"""
      {
        val result = $expr
        println(s"[${${pos.toString}}] $exprString: $typeString = " + result)
        result
      }
    """
  }
  
  // 2. Assertion macro with custom messages
  def assertImpl(c: Context)(condition: c.Expr[Boolean], message: c.Expr[String]): c.Expr[Unit] = {
    import c.universe._
    
    val conditionString = show(condition.tree)
    
    q"""
      if (!$condition) {
        throw new AssertionError(s"Assertion failed: $conditionString - " + $message)
      }
    """
  }
  
  // 3. Performance measurement macro
  def benchmarkImpl(c: Context)(name: c.Expr[String])(expr: c.Expr[Any]): c.Expr[Any] = {
    import c.universe._
    
    val resultVar = TermName(c.freshName("result"))
    val startVar = TermName(c.freshName("start"))
    val endVar = TermName(c.freshName("end"))
    
    q"""
      {
        println(s"Starting benchmark: " + $name)
        val $startVar = System.nanoTime()
        val $resultVar = $expr
        val $endVar = System.nanoTime()
        val duration = ($endVar - $startVar) / 1000000.0
        println(s"Completed benchmark: " + $name + s" in $duration ms")
        $resultVar
      }
    """
  }
  
  // 4. Compile-time string processing  
  def processStringImpl(c: Context)(str: c.Expr[String]): c.Expr[String] = {
    import c.universe._
    
    str.tree match {
      case Literal(Constant(s: String)) =>
        // Process string at compile time
        val processed = s.toUpperCase.reverse
        c.Expr[String](Literal(Constant(processed)))
      case _ =>
        c.abort(c.enclosingPosition, "String must be a literal")
    }
  }
  
  // Macro definitions
  def debugWithType(expr: Any): Any = macro debugWithTypeImpl
  def assert(condition: Boolean, message: String): Unit = macro assertImpl
  def benchmark[T](name: String)(expr: T): T = macro benchmarkImpl
  def processString(str: String): String = macro processStringImpl
}

// Usage examples
import ComprehensiveMacros._

// Debug with type information
val list = debugWithType(List(1, 2, 3).map(_ * 2))

// Custom assertions
assert(list.length == 3, "List should have 3 elements")

// Performance measurement
val result = benchmark("List processing") {
  (1 to 1000000).toList.filter(_ % 2 == 0).sum
}

// Compile-time string processing
val processed = processString("hello")  // Becomes "OLLEH" at compile time
println(processed)

// Error handling in macros
def safeDebugImpl(c: Context)(expr: c.Expr[Any]): c.Expr[Any] = {
  import c.universe._
  
  try {
    val result = q"""
      {
        val value = $expr
        println(s"Value: " + value)
        value
      }
    """
    c.Expr[Any](result)
  } catch {
    case ex: Exception =>
      c.error(c.enclosingPosition, s"Macro expansion failed: ${ex.getMessage}")
      expr
  }
}

def safeDebug(expr: Any): Any = macro safeDebugImpl

Install with Tessl CLI

npx tessl i tessl/maven-org-scala-lang--scala-reflect

docs

abstract-syntax-trees.md

expressions-reification.md

index.md

macro-development.md

mirrors-reflective-operations.md

runtime-reflection.md

symbol-system.md

type-system.md

type-tags-type-information.md

tile.json