All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.tools.nsc.ast.parser.TreeBuilder.scala Maven / Gradle / Ivy

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

package scala.tools.nsc
package ast.parser

import symtab.Flags._
import scala.collection.mutable.ListBuffer
import scala.reflect.internal.util.{Position, SourceFile, FreshNameCreator}

/** Methods for building trees, used in the parser.  All the trees
 *  returned by this class must be untyped.
 */
abstract class TreeBuilder {
  val global: Global
  import global._

  def unit: CompilationUnit
  def source: SourceFile

  implicit def fresh: FreshNameCreator              = unit.fresh
  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)) {
        makeApply(atPos(opPos union left.pos) { Select(stripParens(left), op.encode) }, 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.start else start0
    atPos(r2p(start, end, end + op.length)) { new PostfixSelect(od, op.encode) }
  }

//VIRT was deleted
/*
  /** Create positioned tree representing an object creation  p.end
      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)
  }

  /** Captures the difference in tree building between virtualized and non-virtualized scala */
  // private commented out since it cause "error: private class TreeBuilderStrategy escapes its defining scope as part of type TreeBuilder.this.TreeBuilderStrategy"
  /*private <-- BUG*/ abstract class TreeBuilderStrategy {
    /** Create a tree representing an assignment  */
    def makeAssign(lhs: Tree, rhs: Tree): Tree

    /** Create tree representing a while loop */
    def makeWhileDo(startPos: Int, cond: Tree, body: Tree): Tree

    /** Create tree representing a do-while loop */
    def makeDoWhile(lname: TermName, body: Tree, cond: Tree): Tree

    /** Create tree representing a do-while loop */
    def makeIfThenElse(cond: Tree, thenp: Tree, elsep: Tree): Tree

    /** Create tree representing a variable initializer */
    def makeNewVar(expr: Tree): Tree

    /** Create tree representing a return statement */
    def makeReturn(expr: Tree): Tree

    /** Create a tree making an application node */
    def makeApply(sel: Tree, exprs: List[Tree]): Tree
  }

  // the factory methods below delegate to methods on builder
  private lazy val builder: TreeBuilderStrategy =
    // help out the JIT by only ever instantiating one of the two subclasses (of the *private* TreeBuilderStrategy class, so it's effectively sealed)
    if (!settings.Yvirtualize) new DirectTreeBuilder else new VirtualizingTreeBuilder

  /** Create a tree representing an assignment  */
  @inline final def makeAssign(lhs: Tree, rhs: Tree): Tree = builder.makeAssign(lhs, rhs)

  /** Create tree representing a while loop */
  @inline final def makeWhileDo(startPos: Int, cond: Tree, body: Tree): Tree = builder.makeWhileDo(startPos, cond, body)

  /** Create tree representing a do-while loop */
  @inline final def makeDoWhile(lname: TermName, body: Tree, cond: Tree): Tree = builder.makeDoWhile(lname, body, cond)

  /** Create tree representing a do-while loop */
  @inline final def makeIfThenElse(cond: Tree, thenp: Tree, elsep: Tree): Tree = builder.makeIfThenElse(cond, thenp, elsep)

  /** Create tree representing a variable initializer */
  @inline final def makeNewVar(expr: Tree): Tree = builder.makeNewVar(expr)

  /** Create tree representing a return statement */
  @inline final def makeReturn(expr: Tree): Tree = builder.makeReturn(expr)

  /** Create a tree making an application node */
  @inline final def makeApply(sel: Tree, exprs: List[Tree]): Tree = builder.makeApply(sel, exprs)

  // build trees for plain vanilla scala
  /*private <-- BUG*/ class DirectTreeBuilder extends TreeBuilderStrategy {
    /** Create a tree representing an assignment  */
    def makeAssign(lhs: Tree, rhs: Tree): Tree = lhs match {
      case Apply(fn, args) =>
        Apply(atPos(fn.pos) { Select(fn, nme.update) }, args ::: List(rhs))
      case _ =>
        Assign(lhs, rhs)
    }

    /** Create tree representing a while loop */
    def makeWhileDo(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 lname: Name = freshTermName(nme.DO_WHILE_PREFIX)
      val continu = Apply(Ident(lname), Nil)
      val rhs = Block(List(body), If(cond, continu, Literal(Constant())))
      LabelDef(lname, Nil, rhs)
    }

    /** Create tree representing a do-while loop */
    def makeIfThenElse(cond: Tree, thenp: Tree, elsep: Tree): Tree =
      If(cond, thenp, elsep)

    /** Create tree representing a variable initializer */
    def makeNewVar(expr: Tree): Tree =
      expr

    /** Create tree representing a return statement */
    def makeReturn(expr: Tree): Tree =
      Return(expr)

    /** Create a tree making an application node */
    def makeApply(sel: Tree, exprs: List[Tree]) =
      Apply(sel, exprs)
  }

  // build trees for virtualized scala
  /*private <-- BUG*/ class VirtualizingTreeBuilder extends TreeBuilderStrategy {
    /** Create a tree representing an assignment  */
    def makeAssign(lhs: Tree, rhs: Tree): Tree = lhs match {
      case Apply(fn, args) =>
        Apply(atPos(fn.pos) { Select(fn, nme.update) }, args ::: List(rhs))
      case _ =>
        Apply(Ident(nme._assign), List(lhs, rhs))
    }

    /** Create tree representing a while loop */
    def makeWhileDo(startPos: Int, cond: Tree, body: Tree): Tree =
      Apply(Ident(nme._whileDo), List(cond, body))

    /** Create tree representing a do-while loop */
    def makeDoWhile(lname: TermName, body: Tree, cond: Tree): Tree =
      Apply(Ident(nme._doWhile), List(body, cond))

    /** Create tree representing a do-while loop */
    def makeIfThenElse(cond: Tree, thenp: Tree, elsep: Tree): Tree =
      Apply(Ident(nme._ifThenElse), List(cond, thenp, elsep))

    /** Create tree representing a variable initializer */
    def makeNewVar(expr: Tree): Tree =
      Apply(Ident(nme._newVar) setPos expr.pos.makeTransparent, List(expr)) setPos expr.pos

    /** Create tree representing a return statement */
    def makeReturn(expr: Tree): Tree =
      Apply(Ident(nme._return), List(expr))

    /** Create a tree making an application node; treating == specially
     */
    def makeApply(sel: Tree, exprs: List[Tree]) = sel match {
      case Select(qual, nme.EQ) => // reroute == to __equal
        // don't tuple exprs, as we can't (easily) undo it when it turns out
        // there was a regular == method that takes this number of args (see t3736 in pos/ and neg/)
        Apply(Ident(nme._equal) setPos sel.pos, qual :: exprs)
      case _ =>
        Apply(sel, exprs)
    }
  }


  /** 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)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy