logo

class

compiler::CallResolver

sys::Obj
  compiler::CompilerSupport
    compiler::CallResolver
   1  //
   2  // Copyright (c) 2006, Brian Frank and Andy Frank
   3  // Licensed under the Academic Free License version 3.0
   4  //
   5  // History:
   6  //   15 Sep 05  Brian Frank  Creation
   7  //    5 Sep 06  Brian Frank  Ported from Java to Fan
   8  //
   9  
  10  **
  11  ** CallResolver handles the process of resolving a CallExpr or
  12  ** UnknownVarExpr to a method call or a field access.
  13  **
  14  class CallResolver : CompilerSupport
  15  {
  16  
  17  //////////////////////////////////////////////////////////////////////////
  18  // Construction
  19  //////////////////////////////////////////////////////////////////////////
  20  
  21    **
  22    ** Construct with NameExpr (base class of CallExpr and UnknownVarExpr)
  23    **
  24    new make(Compiler compiler, TypeDef curType, MethodDef curMethod, NameExpr expr)
  25      : super(compiler)
  26    {
  27      this.curType   = curType
  28      this.curMethod = curMethod
  29      this.expr      = expr
  30      this.location  = expr.location
  31      this.target    = expr.target
  32      this.name      = expr.name
  33  
  34      call := expr as CallExpr
  35      if (call != null)
  36      {
  37        this.isVar = false
  38        this.args  = call.args
  39        this.found = call.method
  40      }
  41      else
  42      {
  43        this.isVar = true
  44        this.args  = Expr[,]
  45      }
  46    }
  47  
  48  //////////////////////////////////////////////////////////////////////////
  49  // Resolve
  50  //////////////////////////////////////////////////////////////////////////
  51  
  52    **
  53    ** Resolve into a method call or field access
  54    **
  55    Expr resolve()
  56    {
  57      try
  58      {
  59        resolveBase
  60        find
  61        insertImplicitThis
  62        resolveToExpr
  63        constantFolding
  64        return result
  65      }
  66      catch (CompilerErr err)
  67      {
  68        expr.ctype = ns.error
  69        return expr
  70      }
  71    }
  72  
  73  //////////////////////////////////////////////////////////////////////////
  74  // Resolve Base
  75  //////////////////////////////////////////////////////////////////////////
  76  
  77    **
  78    ** Resolve the base type which defines the slot we are calling.
  79    **
  80    Void resolveBase()
  81    {
  82      // if target unspecified, then assume a slot on the current
  83      // class otherwise the slot must be on the target type
  84      if (target == null)
  85      {
  86        // if we are in a closure - then base is the enclosing class
  87        if (curType.isClosure)
  88        {
  89          base = curType.closure.enclosingType
  90        }
  91        else
  92        {
  93          base = curType
  94        }
  95      }
  96      else
  97      {
  98        base = target.ctype
  99      }
 100  
 101      // if base is the error type, then we already logged an error
 102      // trying to resolve the target and it's pointless to continue
 103      if (base == ns.error) throw CompilerErr.make("ignore", location, null)
 104  
 105      // sanity check
 106      if (base == null) throw err("Internal error", location)
 107    }
 108  
 109  //////////////////////////////////////////////////////////////////////////
 110  // Find
 111  //////////////////////////////////////////////////////////////////////////
 112  
 113    **
 114    ** Find the method or field with the specified name.
 115    **
 116    Void find()
 117    {
 118      // if already "found", then skip this step
 119      if (found != null) return
 120  
 121      // look it up in base type
 122      found = base.slot(name)
 123  
 124      // if still not found, then error
 125      if (found == null)
 126      {
 127        if (isVar)
 128        {
 129          if (target == null)
 130            throw err("Unknown variable '$name'", location)
 131          else
 132            throw err("Unknown slot '$errSig'", location)
 133        }
 134        else
 135        {
 136          throw err("Unknown method '$errSig'", location)
 137        }
 138      }
 139  
 140      // if slot is a field and we are using method call
 141      // syntax on a field and need to map to getter/setter
 142      field := found as CField
 143      if (field != null && !isVar)
 144        throw err("Expected method, not field '$errSig'", location)
 145    }
 146  
 147    private Str errSig() { return "${base.qname}.${name}" }
 148  
 149  //////////////////////////////////////////////////////////////////////////
 150  // Implicit This
 151  //////////////////////////////////////////////////////////////////////////
 152  
 153    **
 154    ** If the call has no explicit target, and is a instance field
 155    ** or method, then we need to insert an implicit this.
 156    **
 157    private Void insertImplicitThis()
 158    {
 159      if (target != null) return
 160      if (found.isStatic || found.isCtor) return
 161      if (curMethod.isStatic) return
 162  
 163      if (curType.isClosure)
 164      {
 165        closure := curType.closure
 166        if (!closure.enclosingMethod.isStatic)
 167          target = FieldExpr.make(location, ThisExpr.make(location, closure.enclosingType), closure.outerThisField)
 168      }
 169      else
 170      {
 171        target = ThisExpr.make(location, curType)
 172      }
 173    }
 174  
 175  //////////////////////////////////////////////////////////////////////////
 176  // Resolve Expr Type
 177  //////////////////////////////////////////////////////////////////////////
 178  
 179    **
 180    ** Compute the expression type the call itself (what gets left on the stack).
 181    **
 182    private Void resolveToExpr()
 183    {
 184      if (found is CField)
 185      {
 186        result = resolveToFieldExpr
 187      }
 188      else
 189      {
 190        result = resolveToCallExpr
 191      }
 192    }
 193  
 194    private CallExpr resolveToCallExpr()
 195    {
 196      method := (CMethod)found
 197  
 198      call := expr as CallExpr
 199      if (call == null)
 200      {
 201        call = CallExpr.make(location)
 202        call.name   = name
 203        call.args   = args
 204      }
 205      call.target = target
 206  
 207      call.method = method
 208      if (method.isCtor)
 209        call.ctype = method.parent
 210      else
 211        call.ctype = method.returnType
 212  
 213      return call
 214    }
 215  
 216    private FieldExpr resolveToFieldExpr()
 217    {
 218      f := (CField)found
 219  
 220      field := FieldExpr.make(location)
 221      field.target = target
 222      field.name   = name
 223      field.field  = f
 224      field.ctype  = f.fieldType
 225      return field
 226    }
 227  
 228  //////////////////////////////////////////////////////////////////////////
 229  // Constant Folding
 230  //////////////////////////////////////////////////////////////////////////
 231  
 232    **
 233    ** If the epxression is a call, check for constant folding.
 234    **
 235    private Void constantFolding()
 236    {
 237      call := result as CallExpr
 238      if (call != null)
 239        result = ConstantFolder.make(compiler).fold(call)
 240    }
 241  
 242  //////////////////////////////////////////////////////////////////////////
 243  // Fields
 244  //////////////////////////////////////////////////////////////////////////
 245  
 246    TypeDef curType      // current type of scope
 247    MethodDef curMethod  // current method of scope
 248    NameExpr expr        // original expression being resolved
 249    Location location    // location of original expression
 250    Expr target          // target base or null
 251    Str name             // slot name to resolve
 252    Bool isVar           // are we resolving simple variable
 253    Expr[] args          // arguments or null if simple variable
 254    CType base           // resolveBase()
 255    CSlot found          // find()
 256    Expr result          // resolveToExpr()
 257  
 258  }