alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (Exprs.scala)

This example Scala source code file (Exprs.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Scala source code examples by using tags.

All credit for the original source code belongs to scala-lang.org; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Scala tags/keywords

annotation, anyref, expr, mirror, reflection, runtime, serializable, singleton, t, tree, treecreator, type, universe

The Exprs.scala Scala example source code

/* NSC -- new Scala compiler
 * Copyright 2005-2013 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala
package reflect
package api

import scala.reflect.runtime.{universe => ru}
import scala.annotation.compileTimeOnly

/**
 * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
 *
 * A trait that defines strongly-typed tree wrappers and operations on them for use in Scala Reflection.
 *
 *  `Expr` wraps an abstract syntax tree ([[scala.reflect.api.Trees#Tree]]) and tags it with its type ([[scala.reflect.api.Types#Type]]).
 *
 *  Usually `Expr`s are created via [[scala.reflect.api.Universe#reify]], in which case a compiler
 *  produces a [[scala.reflect.api.TreeCreator]] for the provided expression and also
 *  creates a complementary [[scala.reflect.api.TypeTags#WeakTypeTag]] that corresponds to the type of that expression.
 *
 * `Expr`s can also be created manually via the `Expr` companion object, but then the burden of providing a `TreeCreator` lies on the programmer.
 *  Compile-time reflection via macros, as described in [[scala.reflect.macros.Aliases]], provides an easier way to instantiate exprs manually.
 *  Manual creation, however, is very rarely needed when working with runtime reflection.
 *
 *  `Expr` can be migrated from one mirror to another by using the `in` method. Migration means that all symbolic references
 *  to classes/objects/packages in the expression are re-resolved within the new mirror
 *  (typically using that mirror's classloader). The default universe of an `Expr` is typically
 *  [[scala.reflect.runtime#universe]], the default mirror is typically [[scala.reflect.runtime#currentMirror]].
 *
 * @group ReflectionAPI
 */
trait Exprs { self: Universe =>

  /** Expr wraps an abstract syntax tree and tags it with its type.
   *  The main source of information about exprs is the [[scala.reflect.api.Exprs]] page.
   *  @group Expressions
   */
  trait Expr[+T] extends Equals with Serializable {
    /**
     * Underlying mirror of this expr.
     */
    val mirror: Mirror

    /**
     * Migrates the expression into another mirror, jumping into a different universe if necessary.
     */
    def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # Expr[T]

    /**
     * The Scala abstract syntax tree representing the wrapped expression.
     */
    def tree: Tree

    /**
     * Type of the wrapped expression tree as provided during creation.
     *
     * When exprs are created by the compiler, `staticType` represents
     * a statically known type of the tree as calculated at that point by the compiler.
     */
    def staticType: Type

    /**
     * Type of the wrapped expression tree as found in the underlying tree.
     */
    def actualType: Type

    /**
     * A dummy method to mark expression splicing in reification.
     *
     * It should only be used within a `reify` call, which eliminates the `splice` call and embeds
     * the wrapped tree into the reified surrounding expression.
     * If used alone `splice` throws an exception when called at runtime.
     *
     * If you want to use an Expr in reification of some Scala code, you need to splice it in.
     * For an expr of type `Expr[T]`, where `T` has a method `foo`, the following code
     * {{{
     *   reify{ expr.splice.foo }
     * }}}
     * uses splice to turn an expr of type Expr[T] into a value of type T in the context of `reify`.
     *
     * It is equivalent to
     * {{{
     *   Select( expr.tree, newTermName("foo") )
     * }}}
     *
     * The following example code however does not compile
     * {{{
     *   reify{ expr.foo }
     * }}}
     * because expr of type Expr[T] itself does not have a method foo.
     */
    @compileTimeOnly("splice must be enclosed within a reify {} block")
    def splice: T

    /**
     * A dummy value to denote cross-stage path-dependent type dependencies.
     *
     * For example for the following macro definition:
     * {{{
     * class X { type T }
     * object Macros { def foo(x: X): x.T = macro Impls.foo_impl }
     * }}}
     *
     * The corresponding macro implementation should have the following signature (note how the return type denotes path-dependency on x):
     * {{{
     * object Impls { def foo_impl(c: Context)(x: c.Expr[X]): c.Expr[x.value.T] = ... }
     * }}}
     */
    @compileTimeOnly("cannot use value except for signatures of macro implementations")
    val value: T

    override def canEqual(x: Any) = x.isInstanceOf[Expr[_]]

    override def equals(x: Any) = x.isInstanceOf[Expr[_]] && this.mirror == x.asInstanceOf[Expr[_]].mirror && this.tree == x.asInstanceOf[Expr[_]].tree

    override def hashCode = mirror.hashCode * 31 + tree.hashCode

    override def toString = "Expr["+staticType+"]("+tree+")"
  }

  /**
   * Constructor/Extractor for Expr.
   *
   * Can be useful, when having a tree and wanting to splice it in reify call,
   * in which case the tree first needs to be wrapped in an expr.

   * The main source of information about exprs is the [[scala.reflect.api.Exprs]] page.
   *  @group Expressions
   */
  object Expr {
    def apply[T: WeakTypeTag](mirror: scala.reflect.api.Mirror[self.type], treec: TreeCreator): Expr[T] = new ExprImpl[T](mirror.asInstanceOf[Mirror], treec)
    def unapply[T](expr: Expr[T]): Option[Tree] = Some(expr.tree)
  }

  private class ExprImpl[+T: WeakTypeTag](val mirror: Mirror, val treec: TreeCreator) extends Expr[T] {
    def in[U <: Universe with Singleton](otherMirror: scala.reflect.api.Mirror[U]): U # Expr[T] = {
      val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]]
      val tag1 = (implicitly[WeakTypeTag[T]] in otherMirror).asInstanceOf[otherMirror.universe.WeakTypeTag[T]]
      otherMirror.universe.Expr[T](otherMirror1, treec)(tag1)
    }

    lazy val tree: Tree = treec(mirror)
    lazy val staticType: Type = implicitly[WeakTypeTag[T]].tpe
    def actualType: Type = tree.tpe

    def splice: T = throw new UnsupportedOperationException("""
      |the function you're calling has not been spliced by the compiler.
      |this means there is a cross-stage evaluation involved, and it needs to be invoked explicitly.
      |if you're sure this is not an oversight, add scala-compiler.jar to the classpath,
      |import `scala.tools.reflect.Eval` and call `<your expr>.eval` instead.""".trim.stripMargin)
    lazy val value: T = throw new UnsupportedOperationException("""
      |the value you're calling is only meant to be used in cross-stage path-dependent types.
      |if you want to splice the underlying expression, use `<your expr>.splice`.
      |if you want to get a value of the underlying expression, add scala-compiler.jar to the classpath,
      |import `scala.tools.reflect.Eval` and call `<your expr>.eval` instead.""".trim.stripMargin)

    private def writeReplace(): AnyRef = new SerializedExpr(treec, implicitly[WeakTypeTag[T]].in(ru.rootMirror))
  }
}

private[scala] class SerializedExpr(var treec: TreeCreator, var tag: ru.WeakTypeTag[_]) extends Serializable {
  private def writeObject(out: java.io.ObjectOutputStream): Unit = {
    out.writeObject(treec)
    out.writeObject(tag)
  }

  private def readObject(in: java.io.ObjectInputStream): Unit = {
    treec = in.readObject().asInstanceOf[TreeCreator]
    tag = in.readObject().asInstanceOf[ru.WeakTypeTag[_]]
  }

  private def readResolve(): AnyRef = {
    import ru._
    Expr(rootMirror, treec)(tag)
  }
}

Other Scala source code examples

Here is a short list of links related to this Scala Exprs.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.