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 }
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 }