logo
class

compiler::Normalize

sys::Obj
  compiler::CompilerSupport
    compiler::CompilerStep
      compiler::Normalize
   1  //
   2  // Copyright (c) 2006, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //    2 Dec 05  Brian Frank  Creation
   7  //   30 Sep 06  Brian Frank  Ported from Java to Fan
   8  //
   9  
  10  **
  11  ** Normalize the abstract syntax tree:
  12  **   - Collapse multiple static new blocks
  13  **   - Init static fields in static new block
  14  **   - Init instance fields in instance new block
  15  **   - Add implicit return in methods
  16  **   - Add implicit super constructor call
  17  **   - Rewrite synthetic getter/setter for override of concrete field
  18  **
  19  class Normalize : CompilerStep
  20  {
  21  
  22  //////////////////////////////////////////////////////////////////////////
  23  // Constructor
  24  //////////////////////////////////////////////////////////////////////////
  25  
  26    new make(Compiler compiler)
  27      : super(compiler)
  28    {
  29    }
  30  
  31  //////////////////////////////////////////////////////////////////////////
  32  // Run
  33  //////////////////////////////////////////////////////////////////////////
  34  
  35    override Void run()
  36    {
  37      log.verbose("Normalize")
  38      walk(types, VisitDepth.typeDef)
  39      bombIfErr
  40    }
  41  
  42  //////////////////////////////////////////////////////////////////////////
  43  // Type Normalization
  44  //////////////////////////////////////////////////////////////////////////
  45  
  46    override Void visitTypeDef(TypeDef t)
  47    {
  48      location := t.location
  49      iInit := Block.make(location)  // instance init
  50      sInit := Block.make(location)  // static init
  51  
  52      // walk thru all the slots
  53      t.slotDefs.each |SlotDef s|
  54      {
  55        if (is FieldDef)
  56        {
  57          f := (FieldDef)s
  58          normalizeField(f)
  59          if (f.init != null && !f.isAbstract)
  60          {
  61            if (f.isStatic)
  62              sInit.add(fieldInitStmt(f))
  63            else
  64              iInit.add(fieldInitStmt(f))
  65            f.init = null // don't walk the init expr anymore
  66          }
  67        }
  68        else
  69        {
  70          // if a static initializer, append it
  71          m := (MethodDef)s
  72          if (m.isStaticInit)
  73            appendStaticInit(sInit, m)
  74          else
  75            normalizeMethod(m)
  76        }
  77      }
  78  
  79      // add instance$init if needed
  80      if (!iInit.isEmpty)
  81      {
  82        iInit.add(ReturnStmt.make(location))
  83        t.addSlot(MethodDef.makeInstanceInit(iInit.location, t, iInit))
  84      }
  85  
  86      // add static$init if needed
  87      if (!sInit.isEmpty)
  88      {
  89        sInit.add(ReturnStmt.make(location))
  90        t.normalizeStaticInits(MethodDef.makeStaticInit(sInit.location, t, sInit))
  91      }
  92    }
  93  
  94    private Void appendStaticInit(Block sInit, MethodDef m)
  95    {
  96      // append inside an "if (true) {}" block so that each static
  97      // initializer is given its own scope in the unified static initializer;
  98      // the "if (true)" gets optimized away in CoodeAsm
  99      loc := m.location
 100      ifStmt := IfStmt.make(loc)
 101      ifStmt.condition = LiteralExpr.make(loc, ExprId.trueLiteral, ns.boolType, true)
 102      ifStmt.trueBlock = m.code
 103      sInit.add(ifStmt)
 104      m.code = null
 105    }
 106  
 107  //////////////////////////////////////////////////////////////////////////
 108  // Method Normalization
 109  //////////////////////////////////////////////////////////////////////////
 110  
 111    private Void normalizeMethod(MethodDef m)
 112    {
 113      code := m.code
 114      if (code == null) return
 115  
 116      // add implicit return
 117      if (!code.isExit) code.add(ReturnStmt.make(code.location))
 118  
 119      // insert super constructor call
 120      if (m.isCtor) insertSuperCtor(m)
 121    }
 122  
 123    private Void insertSuperCtor(MethodDef m)
 124    {
 125      // never insert super call for synthetic types, mixins, or Obj.make
 126      parent := m.parent
 127      base := parent.base
 128      if (parent.isSynthetic) return
 129      if (parent.isMixin) return
 130      if (base.isObj) return
 131  
 132      // check if the base class has exactly one available
 133      // constructor with no parameters
 134      superCtors := base.ctors
 135      if (superCtors.size != 1) return
 136      superCtor := superCtors.first
 137      if (superCtor.isPrivate) return
 138      if (superCtor.isInternal && base.pod != parent.pod) return
 139      if (!superCtor.params.isEmpty) return
 140  
 141      // if we find a ctor to use, then create an implicit super call
 142      m.ctorChain = CallExpr.makeWithMethod(m.location, SuperExpr.make(m.location), superCtor)
 143      m.ctorChain.isCtorChain = true
 144    }
 145  
 146  //////////////////////////////////////////////////////////////////////////
 147  // Field Normalization
 148  //////////////////////////////////////////////////////////////////////////
 149  
 150    private Void normalizeField(FieldDef f)
 151    {
 152      // if this field overrides a concrete field, that means we already have
 153      // a concrete getter/setter for this field - if either of this field's
 154      // accessors is synthetic, then rewrite the one generated by Parser with
 155      // one that calls the "super" version of the accessor
 156      if (f.concreteBase != null)
 157      {
 158        if (!f.hasGet) genSyntheticOverrideGet(f)
 159        if (!f.hasSet) genSyntheticOverrideSet(f)
 160      }
 161  
 162      // ensure that getter is using inherited return
 163      // in case we have a covariant override
 164      if (f.get != null)
 165        f.get.inheritedRet = f.inheritedRet
 166    }
 167  
 168    private Void genSyntheticOverrideGet(FieldDef f)
 169    {
 170      loc := f.location
 171      f.get.code.stmts.clear
 172      f.get.code.add(ReturnStmt.make(loc, FieldExpr.make(loc, SuperExpr.make(loc), f.concreteBase)))
 173    }
 174  
 175    private Void genSyntheticOverrideSet(FieldDef f)
 176    {
 177      loc := f.location
 178      lhs := FieldExpr.make(loc, SuperExpr.make(loc), f.concreteBase)
 179      rhs := UnknownVarExpr.make(loc, null"val")
 180      code := f.get.code
 181      f.set.code.stmts.clear
 182      f.set.code.add(BinaryExpr.makeAssign(lhs, rhs).toStmt)
 183      f.set.code.add(ReturnStmt.make(loc))
 184    }
 185  
 186    private static ExprStmt fieldInitStmt(FieldDef f)
 187    {
 188      useAccessor := f.concreteBase != null
 189      lhs := f.makeAccessorExpr(f.location, useAccessor)
 190      rhs := f.init
 191      return BinaryExpr.makeAssign(lhs, rhs).toStmt
 192    }
 193  
 194  }