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

Scala example source code file (Placeholders.scala)

This example Scala source code file (Placeholders.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

collection, emptytree, holeplaceholder, ident, list, name, none, option, reflection, some, tree, valdef

The Placeholders.scala Scala example source code

package scala.tools.reflect
package quasiquotes

import java.util.UUID.randomUUID
import scala.collection.{immutable, mutable}

/** Emulates hole support (see Holes.scala) in the quasiquote parser (see Parsers.scala).
 *  A principled solution to splicing into Scala syntax would be a parser that natively supports holes.
 *  Unfortunately, that's outside of our reach in Scala 2.11, so we have to emulate.
 *  This trait stores knowledge of how to represent the holes as something understandable by the parser
 *  and how to recover holes from the results of parsing the produced representation.
 */
trait Placeholders { self: Quasiquotes =>
  import global._
  import Rank._
  import universeTypes._

  // Step 1: Transform Scala source with holes into vanilla Scala source

  lazy val posMap = mutable.LinkedHashMap[Position, (Int, Int)]()
  lazy val code = {
    val sb = new StringBuilder()
    val sessionSuffix = randomUUID().toString.replace("-", "").substring(0, 8) + "$"

    def appendPart(value: String, pos: Position) = {
      val start = sb.length
      sb.append(value)
      val end = sb.length
      posMap += pos -> ((start, end))
    }

    def appendHole(tree: Tree, rank: Rank) = {
      val placeholderName = c.freshName(TermName(nme.QUASIQUOTE_PREFIX + sessionSuffix))
      sb.append(placeholderName)
      val holeTree =
        if (method != nme.unapply) tree
        else Bind(placeholderName, tree)
      holeMap(placeholderName) = Hole(rank, holeTree)
    }

    val iargs = method match {
      case nme.apply   => args
      case nme.unapply => internal.subpatterns(args.head).get
      case _           => global.abort("unreachable")
    }

    foreach2(iargs, parts.init) { case (tree, (p, pos)) =>
      val (part, rank) = parseDots(p)
      appendPart(part, pos)
      appendHole(tree, rank)
    }
    val (p, pos) = parts.last
    appendPart(p, pos)

    sb.toString
  }

  object holeMap {
    private val underlying = mutable.LinkedHashMap.empty[String, Hole]
    private val accessed   = mutable.Set.empty[String]
    def unused: Set[Name] = (underlying.keys.toSet -- accessed).map(TermName(_))
    def contains(key: Name): Boolean = underlying.contains(key.toString)
    def apply(key: Name): Hole = {
      val skey = key.toString
      val value = underlying(skey)
      accessed += skey
      value
    }
    def update(key: Name, hole: Hole) =
      underlying += key.toString -> hole
    def get(key: Name): Option[Hole] = {
      val skey = key.toString
      underlying.get(skey).map { v =>
        accessed += skey
        v
      }
    }
    def keysIterator: Iterator[TermName] = underlying.keysIterator.map(TermName(_))
  }

  // Step 2: Transform vanilla Scala AST into an AST with holes

  trait HolePlaceholder {
    def matching: PartialFunction[Any, Name]
    def unapply(scrutinee: Any): Option[Hole] = {
      val name = matching.lift(scrutinee)
      name.flatMap { holeMap.get(_) }
    }
  }

  object Placeholder extends HolePlaceholder {
    def matching = {
      case name: Name => name
      case Ident(name) => name
      case Bind(name, Ident(nme.WILDCARD)) => name
      case TypeDef(_, name, List(), TypeBoundsTree(EmptyTree, EmptyTree)) => name
    }
  }

  object ModsPlaceholder extends HolePlaceholder {
    def apply(name: Name) =
      Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(name.toString))))
    def matching = {
      case Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(s: String)))) => TermName(s)
    }
  }

  object AnnotPlaceholder extends HolePlaceholder {
    def matching = {
      case Apply(Select(New(Ident(name)), nme.CONSTRUCTOR), Nil) => name
    }
  }

  object ParamPlaceholder extends HolePlaceholder {
    def apply(flags: FlagSet, name: Name) =
      ValDef(Modifiers(flags), nme.QUASIQUOTE_PARAM, Ident(name), EmptyTree)
    def matching = {
      case ValDef(_, nme.QUASIQUOTE_PARAM, Ident(name), EmptyTree) => name
    }
  }

  object TuplePlaceholder {
    def apply(args: List[Tree]) =
      Apply(Ident(nme.QUASIQUOTE_TUPLE), args)
    def unapply(tree: Tree): Option[List[Tree]] = tree match {
      case Apply(Ident(nme.QUASIQUOTE_TUPLE), args) => Some(args)
      case _ => None
    }
  }

  object TupleTypePlaceholder {
    def apply(args: List[Tree]) =
      AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), args)
    def unapply(tree: Tree): Option[List[Tree]] = tree match {
      case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), args) => Some(args)
      case _ => None
    }
  }

  object FunctionTypePlaceholder {
    def apply(args: List[Tree], res: Tree) =
      AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res)
    def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
      case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res) => Some((args, res))
      case _ => None
    }
  }

  object SymbolPlaceholder {
    def unapply(scrutinee: Any): Option[Hole] = scrutinee match {
      case Placeholder(hole: ApplyHole) if hole.tpe <:< symbolType => Some(hole)
      case _ => None
    }
  }

  object CasePlaceholder {
    def apply(name: Name) =
      CaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), Ident(name) :: Nil), EmptyTree, EmptyTree)
    def unapply(tree: Tree): Option[Hole] = tree match {
      case CaseDef(Apply(Ident(nme.QUASIQUOTE_CASE), List(Placeholder(hole))), EmptyTree, EmptyTree) => Some(hole)
      case _ => None
    }
  }

  object RefineStatPlaceholder {
    def apply(name: Name) =
      ValDef(NoMods, nme.QUASIQUOTE_REFINE_STAT, Ident(name), EmptyTree)
    def unapply(tree: Tree): Option[Hole] = tree match {
      case ValDef(_, nme.QUASIQUOTE_REFINE_STAT, Ident(Placeholder(hole)), _) => Some(hole)
      case _ => None
    }
  }

  object EarlyDefPlaceholder {
    def apply(name: Name) =
      ValDef(Modifiers(Flag.PRESUPER), nme.QUASIQUOTE_EARLY_DEF, Ident(name), EmptyTree)
    def unapply(tree: Tree): Option[Hole] = tree match {
      case ValDef(_, nme.QUASIQUOTE_EARLY_DEF, Ident(Placeholder(hole)), _) => Some(hole)
      case _ => None
    }
  }

  object PackageStatPlaceholder {
    def apply(name: Name) =
      ValDef(NoMods, nme.QUASIQUOTE_PACKAGE_STAT, Ident(name), EmptyTree)
    def unapply(tree: Tree): Option[Hole] = tree match {
      case ValDef(NoMods, nme.QUASIQUOTE_PACKAGE_STAT, Ident(Placeholder(hole)), EmptyTree) => Some(hole)
      case _ => None
    }
  }

  object ForEnumPlaceholder {
    def apply(name: Name) =
      build.SyntacticValFrom(Bind(name, Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM))
    def unapply(tree: Tree): Option[Hole] = tree match {
      case build.SyntacticValFrom(Bind(Placeholder(hole), Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM)) =>
        Some(hole)
      case _ => None
    }
  }
}

Other Scala source code examples

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

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

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 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.