summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Macros.scala
blob: d0640e76af2cc3eacb372f6fccb840af5e942f1e (plain) (tree)
1
2
3
4
5
6
7
8
9








                                


                                                                             



                                                                       
                                       































                                                                                          









                                                                                            



                                                                                  

                                                                                      





                                         
package scala.tools.nsc
package typechecker

import symtab.Flags._

trait Macros { self: Analyzer =>
  import global._
  import definitions._

  def macroMethName(sym: Symbol) =
    newTermName((if (sym.name.isTypeName) "type" else "def") + "macro$" +
                (if (sym.owner.isModuleClass) "obj$" else "cls$") + sym.name)

  def macroMeth(mac: Symbol): Symbol = {
    var owner = mac.owner
    if (!owner.isModuleClass) owner = owner.companionModule.moduleClass
    owner.info.decl(macroMethName(mac))
  }

  /**
   * The definition of the method implementing a macro. Example:
   *  Say we have
   *
   *    def macro foo[T](xs: List[T]): T = expr
   *
   *  Then the following macro method is generated for `foo`:
   *
   *    def foo(glob: scala.reflect.api.Universe)
   *           (_this: glob.Tree)
   *           (T: glob.Type)
   *           (xs: glob.Tree): glob.Tree = {
   *      implicit val $glob = glob
   *      expr
   *    }
   */
  def macroMethDef(mdef: DefDef): Tree = {
    def paramDef(name: Name, tpt: Tree) = ValDef(Modifiers(PARAM), name, tpt, EmptyTree)
    val universeType = TypeTree(ReflectApiUniverse.tpe)
    val globParam = paramDef("glob", universeType)
    def globSelect(name: Name) = Select(Ident("glob"), name)
    def globTree = globSelect(newTypeName("Tree"))
    def globType = globSelect(newTypeName("Type"))
    val thisParam = paramDef("_this", globTree)
    def tparamInMacro(tdef: TypeDef) = paramDef(tdef.name.toTermName, globType)
    def vparamInMacro(vdef: ValDef): ValDef = paramDef(vdef.name, globTree)
    def wrapImplicit(tree: Tree) = atPos(tree.pos) {
      Block(List(ValDef(Modifiers(IMPLICIT), "$glob", universeType, Ident("glob"))), tree)
    }

    atPos(mdef.pos) {
      new DefDef( // can't call DefDef here; need to find out why
        mods = mdef.mods &~ MACRO,
        name = macroMethName(mdef.symbol),
        tparams = List(),
        vparamss = List(globParam) :: List(thisParam) :: (mdef.tparams map tparamInMacro) ::
          (mdef.vparamss map (_ map vparamInMacro)),
        tpt = globTree,
        wrapImplicit(mdef.rhs))
    }
  }

  def addMacroMethods(templ: Template, namer: Namer): Unit = {
    for (ddef @ DefDef(mods, _, _, _, _, _) <- templ.body if mods hasFlag MACRO) {
      val sym = namer.enterSyntheticSym(util.trace("macro def: ")(macroMethDef(ddef)))
      println("added to "+namer.context.owner.enclClass+": "+sym)
    }
  }

  def macroExpand(tree: Tree): Tree = ???

}