logo

class

compiler::InitClosures

sys::Obj
  compiler::CompilerSupport
    compiler::CompilerStep
      compiler::InitClosures
   1  //
   2  // Copyright (c) 2006, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //   16 Jan 06  Brian Frank  Creation
   7  //    2 Oct 06  Brian Frank  Ported from Java to Fan
   8  //
   9  
  10  **
  11  ** During the Parse step we created a list of all the closures.
  12  ** In InitClosures we map each ClosureExpr into a TypeDef as
  13  ** an anonymous class, then we map ClosureExpr.substitute to
  14  ** call the constructor anonymous class.
  15  **
  16  class InitClosures : CompilerStep
  17  {
  18  
  19  //////////////////////////////////////////////////////////////////////////
  20  // Constructor
  21  //////////////////////////////////////////////////////////////////////////
  22  
  23    new make(Compiler compiler)
  24      : super(compiler)
  25    {
  26    }
  27  
  28  //////////////////////////////////////////////////////////////////////////
  29  // Run
  30  //////////////////////////////////////////////////////////////////////////
  31  
  32    override Void run()
  33    {
  34      log.debug("Closures")
  35      compiler.closures.each |ClosureExpr c| { process(c) }
  36    }
  37  
  38  //////////////////////////////////////////////////////////////////////////
  39  // Process
  40  //////////////////////////////////////////////////////////////////////////
  41  
  42    private Void process(ClosureExpr c)
  43    {
  44      // class Class$Method$Num : |A,B..->R|
  45      // {
  46      //    new $make() {}
  47      //    Bool isImmutable() { return true }
  48      //    Obj call(Obj a, Obj b, ...) { doCall((A)a, ...) }
  49      //    R doCall(A a, B b, ...) { closure.code }
  50      // }
  51  
  52      setup(c)       // setup our fields to process this closure
  53      genClass       // generate anonymous implementation class
  54      genCtor        // generate $make()
  55      genIsImmutable // generate isImmutable()
  56      genDoCall      // generate doCall(...)
  57      genCall       // generate call(...) { doCall(...) }
  58      substitute    // substitute closure code with anonymous class ctor
  59    }
  60  
  61  //////////////////////////////////////////////////////////////////////////
  62  // Setup
  63  //////////////////////////////////////////////////////////////////////////
  64  
  65    private Void setup(ClosureExpr c)
  66    {
  67      this.closure         = c
  68      this.loc             = c.location
  69      this.signature       = c.signature
  70      this.enclosingType   = c.enclosingType
  71      this.enclosingMethod = c.enclosingMethod
  72    }
  73  
  74  //////////////////////////////////////////////////////////////////////////
  75  // Generate Class
  76  //////////////////////////////////////////////////////////////////////////
  77  
  78    private Void genClass()
  79    {
  80      cls = TypeDef.make(ns, loc, closure.enclosingType.unit, closure.name)
  81      cls.flags   = FConst.Internal | FConst.Final | FConst.Synthetic
  82      cls.base    = closure.signature
  83      cls.closure = closure
  84      closure.cls = cls
  85      addTypeDef(cls)
  86    }
  87  
  88  //////////////////////////////////////////////////////////////////////////
  89  // Generate Constructor
  90  //////////////////////////////////////////////////////////////////////////
  91  
  92    private Void genCtor()
  93    {
  94      code := Block.make(loc)
  95      code.stmts.add(ReturnStmt.make(loc))
  96  
  97      ctor = MethodDef.make(loc, cls)
  98      ctor.flags = FConst.Internal | FConst.Ctor | FConst.Synthetic
  99      ctor.name = "make"
 100      ctor.ret  = ns.voidType
 101      ctor.code = code
 102      cls.addSlot(ctor)
 103    }
 104  
 105  //////////////////////////////////////////////////////////////////////////
 106  // Generate IsConst Override
 107  //////////////////////////////////////////////////////////////////////////
 108  
 109    private Void genIsImmutable()
 110    {
 111      // we assume immutable until proved otherwise in ClosureVars step
 112      genIsImmutableMethod(compiler, loc, cls, true)
 113    }
 114  
 115    static internal Void genIsImmutableMethod(Compiler compiler, Location loc, TypeDef parent, Bool literalVal)
 116    {
 117      Expr literal
 118      if (literalVal)
 119        literal = LiteralExpr.make(loc, ExprId.trueLiteral, compiler.ns.boolType, true)
 120      else
 121        literal = LiteralExpr.make(loc, ExprId.falseLiteral, compiler.ns.boolType, false)
 122  
 123      code := Block.make(loc)
 124      code.stmts.add(ReturnStmt.make(loc, literal))
 125  
 126      m := MethodDef.make(loc, parent)
 127      m.flags = FConst.Public | FConst.Synthetic | FConst.Override
 128      m.name = "isImmutable"
 129      m.ret  = compiler.ns.boolType
 130      m.code = code
 131      parent.addSlot(m)
 132    }
 133  
 134  //////////////////////////////////////////////////////////////////////////
 135  // Generate doCall()
 136  //////////////////////////////////////////////////////////////////////////
 137  
 138    private Void genDoCall()
 139    {
 140      doCall = MethodDef.make(loc, cls)
 141      doCall.name  = "doCall"
 142      doCall.flags = FConst.Private | FConst.Synthetic
 143      doCall.code  = closure.code
 144      doCall.ret = signature.ret
 145      doCall.paramDefs = signature.toParamDefs(loc)
 146      closure.doCall = doCall
 147      cls.addSlot(doCall)
 148    }
 149  
 150  //////////////////////////////////////////////////////////////////////////
 151  // Generate call()
 152  //////////////////////////////////////////////////////////////////////////
 153  
 154    private Void genCall()
 155    {
 156      c := CallExpr.makeWithMethod(loc, ThisExpr.make(loc), doCall)
 157      genMethodCall(compiler, loc, cls, signature, c, false)
 158    }
 159  
 160    **
 161    ** This method overrides either call(List) or callx(A...) to push the
 162    ** args onto the stack, then redirect to the specified CallExpr c.
 163    ** We share this code for both closures and curries.
 164    **
 165    static MethodDef genMethodCall(Compiler compiler, Location loc, TypeDef parent,
 166                                   FuncType signature, CallExpr c, Bool firstAsTarget)
 167    {
 168      ns := compiler.ns
 169  
 170      // method def
 171      m := MethodDef.make(loc, parent)
 172      m.name  = "call"
 173      m.flags = FConst.Override | FConst.Synthetic
 174      m.ret   = ns.objType
 175      m.code  = Block.make(loc)
 176  
 177      // signature:
 178      //   call(List)                 // if > MaxIndirectParams
 179      //   call(Obj p0, Obj p1, ...)  // if <= MaxIndirectParams
 180      paramCount := signature.params.size
 181      useListArgs := paramCount > 8
 182      if (useListArgs)
 183      {
 184        p := ParamDef.make(loc, ns.objType.toListOf, "list")
 185        m.params.add(p)
 186      }
 187      else
 188      {
 189        m.name += paramCount.toStr
 190        paramCount.times |Int i|
 191        {
 192          p := ParamDef.make(loc, ns.objType, "p$i")
 193          m.paramDefs.add(p)
 194        }
 195      }
 196  
 197      // init the doCall() expr with arguments
 198      paramCount.times |Int i|
 199      {
 200        Expr arg
 201  
 202        // list.get(<i>)
 203        if (useListArgs)
 204        {
 205          listGet := CallExpr.makeWithMethod(loc, UnknownVarExpr.make(loc, null, "list"), ns.objType.toListOf.method("get"))
 206          listGet.args.add(LiteralExpr.make(loc, ExprId.intLiteral, ns.intType, i))
 207          arg = listGet
 208        }
 209  
 210        // p<i>
 211        else
 212        {
 213          arg = UnknownVarExpr.make(loc, null, "p$i")
 214        }
 215  
 216        // cast to closure param type
 217        arg = TypeCheckExpr.make(loc, ExprId.cast, arg, signature.params[i])
 218  
 219        // add to doCall() argument list
 220        if (firstAsTarget && i === 0)
 221          c.target = arg
 222        else
 223          c.args.add(arg)
 224      }
 225  
 226      // return:
 227      //   doCall; return null;  // if doCall() is void
 228      //   return doCall         // if doCall() non-void
 229      if (signature.ret.isVoid)
 230      {
 231        m.code.add(c.toStmt)
 232        m.code.add(ReturnStmt.make(loc, LiteralExpr.make(loc, ExprId.nullLiteral, ns.objType, null)))
 233      }
 234      else
 235      {
 236        m.code.add(ReturnStmt.make(loc, c))
 237      }
 238  
 239      // add to our synthetic parent class
 240      parent.addSlot(m)
 241      return m
 242    }
 243  
 244  //////////////////////////////////////////////////////////////////////////
 245  // Substitute
 246  //////////////////////////////////////////////////////////////////////////
 247  
 248    private Void substitute()
 249    {
 250      closure.code = null
 251      closure.substitute = CallExpr.makeWithMethod(loc, null, ctor)
 252    }
 253  
 254  //////////////////////////////////////////////////////////////////////////
 255  // Fields
 256  //////////////////////////////////////////////////////////////////////////
 257  
 258    ClosureExpr closure        // current closure
 259    Location loc               // closure.location
 260    FuncType signature         // closure.sig
 261    TypeDef enclosingType      // closure.enclosingType
 262    MethodDef enclosingMethod  // closure.enclosingMethod
 263    TypeDef cls                // current anonymous class implementing closure
 264    MethodDef ctor             // anonymous class make ctor
 265    MethodDef doCall           // R doCall(A a, ...) { closure.code }
 266  
 267  }