
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 }