org.scalamacros.paradise.parser.TreeBuilder.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of paradise_2.10.7 Show documentation
Show all versions of paradise_2.10.7 Show documentation
Empowers production Scala compiler with latest macro developments
The newest version!
// NOTE: copy/pasted from scalac with minor patches applied for extensibility required in quasiquotes
// the alternative would be to inherit the existing parser and copy/paste half of it in a random fashion
package org.scalamacros.paradise
package parser
import scala.reflect.internal.Flags._
import scala.collection.mutable.ListBuffer
import scala.reflect.internal.util.{Position, SourceFile}
import scala.quasiquotes.FreshNameCreator
import scala.tools.nsc.Global
/** Methods for building trees, used in the parser. All the trees
* returned by this class must be untyped.
*/
abstract class TreeBuilder { self =>
val global: Global
import global.{gen => _, treeInfo => _, build => _, _}
lazy val compat = new { val global: self.global.type = self.global } with scala.quasiquotes.SymbolTableCompat
import compat.{gen, treeInfo, build}
import compat.symbolTable.{freshTermName, freshTypeName, RichPosition}
def unit: CompilationUnit
def source: SourceFile
implicit def fresh: FreshNameCreator = scala.quasiquotes.globalFreshNameCreator
def o2p(offset: Int): Position = Position.offset(source, offset)
def r2p(start: Int, mid: Int, end: Int): Position = rangePos(source, start, mid, end)
def rootScalaDot(name: Name) = gen.rootScalaDot(name)
def scalaDot(name: Name) = gen.scalaDot(name)
def scalaAnyRefConstr = scalaDot(tpnme.AnyRef)
def scalaUnitConstr = scalaDot(tpnme.Unit)
def convertToTypeName(t: Tree) = gen.convertToTypeName(t)
def byNameApplication(tpe: Tree): Tree =
AppliedTypeTree(rootScalaDot(tpnme.BYNAME_PARAM_CLASS_NAME), List(tpe))
def repeatedApplication(tpe: Tree): Tree =
AppliedTypeTree(rootScalaDot(tpnme.REPEATED_PARAM_CLASS_NAME), List(tpe))
def makeImportSelector(name: Name, nameOffset: Int): ImportSelector =
ImportSelector(name, nameOffset, name, nameOffset)
def makeTupleTerm(elems: List[Tree]) = gen.mkTuple(elems)
def makeTupleType(elems: List[Tree]) = gen.mkTupleType(elems)
def stripParens(t: Tree) = t match {
case Parens(ts) => atPos(t.pos) { makeTupleTerm(ts) }
case _ => t
}
def makeAnnotated(t: Tree, annot: Tree): Tree =
atPos(annot.pos union t.pos)(Annotated(annot, t))
def makeSelfDef(name: TermName, tpt: Tree): ValDef =
ValDef(Modifiers(PRIVATE), name, tpt, EmptyTree)
/** Create tree representing (unencoded) binary operation expression or pattern. */
def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = {
require(isExpr || targs.isEmpty || targs.exists(_.isErroneous), s"Incompatible args to makeBinop: !isExpr but targs=$targs")
def mkSelection(t: Tree) = {
def sel = atPos(opPos union t.pos)(Select(stripParens(t), op.encode))
if (targs.isEmpty) sel else atPos(left.pos)(TypeApply(sel, targs))
}
def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args
val arguments = right match {
case Parens(args) => mkNamed(args)
case _ => List(right)
}
if (isExpr) {
if (treeInfo.isLeftAssoc(op)) {
Apply(mkSelection(left), arguments)
} else {
val x = freshTermName()
Block(
List(ValDef(Modifiers(SYNTHETIC | ARTIFACT), x, TypeTree(), stripParens(left))),
Apply(mkSelection(right), List(Ident(x))))
}
} else {
Apply(Ident(op.encode), stripParens(left) :: arguments)
}
}
/** Tree for `od op`, start is start0 if od.pos is borked. */
def makePostfixSelect(start0: Int, end: Int, od: Tree, op: Name): Tree = {
val start = if (od.pos.isDefined) od.pos.startOrPoint else start0
atPos(r2p(start, end, end + op.length)) { new PostfixSelect(od, op.encode) }
}
/** Create tree representing a while loop */
def makeWhile(startPos: Int, cond: Tree, body: Tree): Tree = {
val lname = freshTermName(nme.WHILE_PREFIX)
def default = wrappingPos(List(cond, body)) match {
case p if p.isDefined => p.endOrPoint
case _ => startPos
}
val continu = atPos(o2p(body.pos pointOrElse default)) { Apply(Ident(lname), Nil) }
val rhs = If(cond, Block(List(body), continu), Literal(Constant(())))
LabelDef(lname, Nil, rhs)
}
/** Create tree representing a do-while loop */
def makeDoWhile(lname: TermName, body: Tree, cond: Tree): Tree = {
val continu = Apply(Ident(lname), Nil)
val rhs = Block(List(body), If(cond, continu, Literal(Constant(()))))
LabelDef(lname, Nil, rhs)
}
/** Create block of statements `stats` */
def makeBlock(stats: List[Tree]): Tree = gen.mkBlock(stats)
def makeParam(pname: TermName, tpe: Tree) =
ValDef(Modifiers(PARAM), pname, tpe, EmptyTree)
def makeSyntheticTypeParam(pname: TypeName, bounds: Tree) =
TypeDef(Modifiers(DEFERRED | SYNTHETIC), pname, Nil, bounds)
/** Create tree for a pattern alternative */
def makeAlternative(ts: List[Tree]): Tree = {
def alternatives(t: Tree): List[Tree] = t match {
case Alternative(ts) => ts
case _ => List(t)
}
Alternative(ts flatMap alternatives)
}
/** Create tree for case definition rhs> */
def makeCaseDef(pat: Tree, guard: Tree, rhs: Tree): CaseDef =
CaseDef(gen.patvarTransformer.transform(pat), guard, rhs)
/** Creates tree representing:
* { case x: Throwable =>
* val catchFn = catchExpr
* if (catchFn isDefinedAt x) catchFn(x) else throw x
* }
*/
def makeCatchFromExpr(catchExpr: Tree): CaseDef = {
val binder = freshTermName()
val pat = Bind(binder, Typed(Ident(nme.WILDCARD), Ident(tpnme.Throwable)))
val catchDef = ValDef(Modifiers(ARTIFACT), freshTermName("catchExpr"), TypeTree(), catchExpr)
val catchFn = Ident(catchDef.name)
val body = atPos(catchExpr.pos.makeTransparent)(Block(
List(catchDef),
If(
Apply(Select(catchFn, nme.isDefinedAt), List(Ident(binder))),
Apply(Select(catchFn, nme.apply), List(Ident(binder))),
Throw(Ident(binder))
)
))
makeCaseDef(pat, EmptyTree, body)
}
/** Create a tree representing the function type (argtpes) => restpe */
def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = gen.mkFunctionTypeTree(argtpes, restpe)
/** Append implicit parameter section if `contextBounds` nonempty */
def addEvidenceParams(owner: Name, vparamss: List[List[ValDef]], contextBounds: List[Tree]): List[List[ValDef]] = {
if (contextBounds.isEmpty) vparamss
else {
val mods = Modifiers(if (owner.isTypeName) PARAMACCESSOR | LOCAL | PRIVATE else PARAM)
def makeEvidenceParam(tpt: Tree) = ValDef(mods | IMPLICIT | SYNTHETIC, freshTermName(nme.EVIDENCE_PARAM_PREFIX), tpt, EmptyTree)
val evidenceParams = contextBounds map makeEvidenceParam
val vparamssLast = if(vparamss.nonEmpty) vparamss.last else Nil
if(vparamssLast.nonEmpty && vparamssLast.head.mods.hasFlag(IMPLICIT))
vparamss.init ::: List(evidenceParams ::: vparamssLast)
else
vparamss ::: List(evidenceParams)
}
}
def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree) = gen.mkPatDef(mods, pat, rhs)
}