summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Macros.scala
blob: b9264aae558315c60a5a4375f0da6e5080bbbeb3 (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 macroMeth(mac: Symbol): Symbol = {
    var owner = mac.owner
    if (!owner.isModuleClass) owner = owner.companionModule.moduleClass
    owner.info.decl(nme.macroMethodName(mac.name))
  }

  /**
   * The definition of the method implementing a macro. Example:
   *  Say we have in a class C
   *
   *    def macro foo[T](xs: List[T]): T = expr
   *
   *  Then the following macro method is generated for `foo`:
   *
   *    def defmacro$foo(glob: scala.reflect.api.Universe)
   *           (_this: glob.Tree)
   *           (T: glob.Type)
   *           (xs: glob.Tree): glob.Tree = {
   *      implicit val $glob = glob
   *      expr
   *    }
   *
   *    If `foo` is declared in an object, the second parameter list is () instead of (_this: glob.Tree).
   */
  def macroMethDef(mdef: DefDef): Tree = {
    def paramDef(name: Name, tpt: Tree) = ValDef(Modifiers(PARAM), name, tpt, EmptyTree)
    val universeType = TypeTree(ReflectApiUniverse.tpe)
    val globParamSec = List(paramDef(nme.glob, universeType))
    def globSelect(name: Name) = Select(Ident(nme.glob), name)
    def globTree = globSelect(newTypeName("Tree"))
    def globType = globSelect(newTypeName("Type"))
    val thisParamSec = if (mdef.symbol.owner.isModuleClass) List() else List(paramDef(newTermName("_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), newTermName("$" + nme.glob), universeType, Ident(nme.glob))), tree)
    }

    atPos(mdef.pos) {
      new DefDef( // can't call DefDef here; need to find out why
        mods = mdef.mods &~ MACRO,
        name = nme.macroMethodName(mdef.name),
        tparams = List(),
        vparamss = globParamSec :: thisParamSec :: (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 = ???

}