KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > polyglot > ext > jl > ast > Call_c


1 package polyglot.ext.jl.ast;
2
3 import polyglot.ast.*;
4 import polyglot.types.*;
5 import polyglot.util.*;
6 import polyglot.visit.*;
7 import java.util.*;
8
9 /**
10  * A <code>Call</code> is an immutable representation of a Java
11  * method call. It consists of a method name and a list of arguments.
12  * It may also have either a Type upon which the method is being
13  * called or an expression upon which the method is being called.
14  */

15 public class Call_c extends Expr_c implements Call
16 {
17   protected Receiver target;
18   protected String JavaDoc name;
19   protected List arguments;
20   protected MethodInstance mi;
21   protected boolean targetImplicit;
22
23   public Call_c(Position pos, Receiver target, String JavaDoc name,
24                 List arguments) {
25     super(pos);
26     this.target = target;
27     this.name = name;
28     this.arguments = TypedList.copyAndCheck(arguments, Expr.class, true);
29     this.targetImplicit = (target == null);
30   }
31
32   /** Get the precedence of the call. */
33   public Precedence precedence() {
34     return Precedence.LITERAL;
35   }
36
37   /** Get the target object or type of the call. */
38   public Receiver target() {
39     return this.target;
40   }
41
42   /** Set the target object or type of the call. */
43   public Call target(Receiver target) {
44     Call_c n = (Call_c) copy();
45     n.target = target;
46     return n;
47   }
48
49   /** Get the name of the call. */
50   public String JavaDoc name() {
51     return this.name;
52   }
53
54   /** Set the name of the call. */
55   public Call name(String JavaDoc name) {
56     Call_c n = (Call_c) copy();
57     n.name = name;
58     return n;
59   }
60
61   public ProcedureInstance procedureInstance() {
62       return methodInstance();
63   }
64
65   /** Get the method instance of the call. */
66   public MethodInstance methodInstance() {
67     return this.mi;
68   }
69
70   /** Set the method instance of the call. */
71   public Call methodInstance(MethodInstance mi) {
72     Call_c n = (Call_c) copy();
73     n.mi = mi;
74     return n;
75   }
76
77   public boolean isTargetImplicit() {
78       return this.targetImplicit;
79   }
80
81   public Call targetImplicit(boolean targetImplicit) {
82       if (targetImplicit == this.targetImplicit) {
83           return this;
84       }
85       
86       Call_c n = (Call_c) copy();
87       n.targetImplicit = targetImplicit;
88       return n;
89   }
90
91   /** Get the actual arguments of the call. */
92   public List arguments() {
93     return this.arguments;
94   }
95
96   /** Set the actual arguments of the call. */
97   public ProcedureCall arguments(List arguments) {
98     Call_c n = (Call_c) copy();
99     n.arguments = TypedList.copyAndCheck(arguments, Expr.class, true);
100     return n;
101   }
102
103   /** Reconstruct the call. */
104   protected Call_c reconstruct(Receiver target, List arguments) {
105     if (target != this.target || ! CollectionUtil.equals(arguments,
106                                                          this.arguments)) {
107       Call_c n = (Call_c) copy();
108       n.target = target;
109       n.arguments = TypedList.copyAndCheck(arguments, Expr.class, true);
110       return n;
111     }
112
113     return this;
114   }
115
116   /** Visit the children of the call. */
117   public Node visitChildren(NodeVisitor v) {
118     Receiver target = (Receiver) visitChild(this.target, v);
119     List arguments = visitList(this.arguments, v);
120     return reconstruct(target, arguments);
121   }
122
123   public Node buildTypes(TypeBuilder tb) throws SemanticException {
124     Call_c n = (Call_c) super.buildTypes(tb);
125
126     TypeSystem ts = tb.typeSystem();
127
128     List l = new ArrayList(arguments.size());
129     for (int i = 0; i < arguments.size(); i++) {
130       l.add(ts.unknownType(position()));
131     }
132
133     MethodInstance mi = ts.methodInstance(position(), ts.Object(),
134                                           Flags.NONE,
135                                           ts.unknownType(position()),
136                                           name, l,
137                                           Collections.EMPTY_LIST);
138     return n.methodInstance(mi);
139   }
140
141     /**
142      * Typecheck the Call when the target is null. This method finds
143      * an appropriate target, and then type checks accordingly.
144      *
145      * @param argTypes list of <code>Type</code>s of the arguments
146      */

147     protected Node typeCheckNullTarget(TypeChecker tc, List argTypes) throws SemanticException {
148         TypeSystem ts = tc.typeSystem();
149         NodeFactory nf = tc.nodeFactory();
150         Context c = tc.context();
151
152         // the target is null, and thus implicit
153
// let's find the target, using the context, and
154
// set the target appropriately, and then type check
155
// the result
156
MethodInstance mi = c.findMethod(this.name, argTypes);
157         
158         Receiver r;
159         if (mi.flags().isStatic()) {
160             r = nf.CanonicalTypeNode(position(), mi.container()).type(mi.container());
161         } else {
162             // The method is non-static, so we must prepend with "this", but we
163
// need to determine if the "this" should be qualified. Get the
164
// enclosing class which brought the method into scope. This is
165
// different from mi.container(). mi.container() returns a super type
166
// of the class we want.
167
ClassType scope = c.findMethodScope(name);
168
169             if (! ts.equals(scope, c.currentClass())) {
170                 r = nf.This(position(),
171                             nf.CanonicalTypeNode(position(), scope)).type(scope);
172             }
173             else {
174                 r = nf.This(position()).type(scope);
175             }
176         }
177
178         // we call typeCheck on the reciever too.
179
r = (Receiver)r.typeCheck(tc);
180         return this.targetImplicit(true).target(r).del().typeCheck(tc);
181     }
182
183     /** Type check the call. */
184     public Node typeCheck(TypeChecker tc) throws SemanticException {
185         TypeSystem ts = tc.typeSystem();
186         Context c = tc.context();
187
188         List argTypes = new ArrayList(this.arguments.size());
189
190         for (Iterator i = this.arguments.iterator(); i.hasNext(); ) {
191             Expr e = (Expr) i.next();
192             argTypes.add(e.type());
193         }
194
195         if (this.target == null) {
196             return this.typeCheckNullTarget(tc, argTypes);
197         }
198
199         ReferenceType targetType = this.findTargetType();
200         MethodInstance mi = ts.findMethod(targetType,
201                                           this.name,
202                                           argTypes,
203                                           c.currentClass());
204         
205         
206         /* This call is in a static context if and only if
207          * the target (possibly implicit) is a type node.
208          */

209         boolean staticContext = (this.target instanceof TypeNode);
210
211
212         if (staticContext && !mi.flags().isStatic()) {
213             throw new SemanticException("Cannot call non-static method " + this.name
214                                   + " of " + targetType + " in static "
215                                   + "context.", this.position());
216         }
217
218         // If the target is super, but the method is abstract, then complain.
219
if (this.target instanceof Special &&
220             ((Special)this.target).kind() == Special.SUPER &&
221             mi.flags().isAbstract()) {
222                 throw new SemanticException("Cannot call an abstract method " +
223                                "of the super class", this.position());
224         }
225         // If we found a method, the call must type check, so no need to check
226
// the arguments here.
227

228         Call_c call = (Call_c)this.methodInstance(mi).type(mi.returnType());
229         call.checkConsistency(c);
230         return call;
231     }
232     
233     protected ReferenceType findTargetType() throws SemanticException {
234         Type t = target.type();
235         if (t.isReference()) {
236             return t.toReference();
237         } else {
238             // trying to invoke a method on a non-reference type.
239
// let's pull out an appropriate error message.
240
if (target instanceof Expr) {
241                 throw new SemanticException("Cannot invoke method \"" + name + "\" on "
242                                     + "an expression of non-reference type "
243                                     + t + ".", target.position());
244             }
245             else if (target instanceof TypeNode) {
246                 throw new SemanticException("Cannot invoke static method \"" + name
247                                     + "\" on non-reference type " + t + ".",
248                                     target.position());
249             }
250             throw new SemanticException("Receiver of method invocation must be a "
251                                     + "reference type.",
252                                         target.position());
253         }
254     }
255
256   public Type childExpectedType(Expr child, AscriptionVisitor av)
257   {
258       if (child == target) {
259           return mi.container();
260       }
261
262       Iterator i = this.arguments.iterator();
263       Iterator j = mi.formalTypes().iterator();
264
265       while (i.hasNext() && j.hasNext()) {
266           Expr e = (Expr) i.next();
267           Type t = (Type) j.next();
268
269           if (e == child) {
270               return t;
271           }
272       }
273
274       return child.type();
275   }
276
277   public String JavaDoc toString() {
278     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
279     sb.append(targetImplicit ? "" : target.toString() + ".");
280     sb.append(name);
281     sb.append("(");
282
283     int count = 0;
284
285     for (Iterator i = arguments.iterator(); i.hasNext(); ) {
286         if (count++ > 2) {
287             sb.append("...");
288             break;
289         }
290
291         Expr n = (Expr) i.next();
292         sb.append(n.toString());
293
294         if (i.hasNext()) {
295             sb.append(", ");
296         }
297     }
298
299     sb.append(")");
300     return sb.toString();
301   }
302
303   /** Write the expression to an output file. */
304   public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
305     if (!targetImplicit) {
306         if (target instanceof Expr) {
307           printSubExpr((Expr) target, w, tr);
308           w.write(".");
309         }
310         else if (target != null) {
311           print(target, w, tr);
312           w.write(".");
313         }
314     }
315
316     w.write(name + "(");
317     w.begin(0);
318         
319     for(Iterator i = arguments.iterator(); i.hasNext();) {
320       Expr e = (Expr) i.next();
321       print(e, w, tr);
322
323       if (i.hasNext()) {
324         w.write(",");
325         w.allowBreak(0, " ");
326       }
327     }
328
329     w.end();
330     w.write(")");
331   }
332
333   /** Dumps the AST. */
334   public void dump(CodeWriter w) {
335     super.dump(w);
336
337     if ( mi != null ) {
338       w.allowBreak(4, " ");
339       w.begin(0);
340       w.write("(instance " + mi + ")");
341       w.end();
342     }
343
344     w.allowBreak(4, " ");
345     w.begin(0);
346     w.write("(name " + name + ")");
347     w.end();
348
349     w.allowBreak(4, " ");
350     w.begin(0);
351     w.write("(arguments " + arguments + ")");
352     w.end();
353   }
354
355   public Term entry() {
356       if (target instanceof Expr) {
357           return ((Expr) target).entry();
358       }
359       return listEntry(arguments, this);
360   }
361
362   public List acceptCFG(CFGBuilder v, List succs) {
363       if (target instanceof Expr) {
364           Expr t = (Expr) target;
365           v.visitCFG(t, listEntry(arguments, this));
366       }
367
368       v.visitCFGList(arguments, this);
369
370       return succs;
371   }
372
373   /** Check exceptions thrown by the call. */
374   public Node exceptionCheck(ExceptionChecker ec) throws SemanticException {
375     if (mi == null) {
376       throw new InternalCompilerError(position(),
377                                       "Null method instance after type "
378                                       + "check.");
379     }
380
381     return super.exceptionCheck(ec);
382   }
383
384
385   public List throwTypes(TypeSystem ts) {
386     List l = new LinkedList();
387
388     l.addAll(mi.throwTypes());
389     l.addAll(ts.uncheckedExceptions());
390
391     if (target instanceof Expr && ! (target instanceof Special)) {
392       l.add(ts.NullPointerException());
393     }
394
395     return l;
396   }
397   
398   // check that the implicit target setting is correct.
399
protected void checkConsistency(Context c) throws SemanticException {
400       if (targetImplicit) {
401           // the target is implicit. Check that the
402
// method found in the target type is the
403
// same as the method found in the context.
404

405           // as exception will be thrown if no appropriate method
406
// exists.
407
MethodInstance ctxtMI = c.findMethod(name, mi.formalTypes());
408           
409           // cannot perform this check due to the context's findMethod returning a
410
// different method instance than the typeSystem in some situations
411
// if (!c.typeSystem().equals(ctxtMI, mi)) {
412
// throw new InternalCompilerError("Method call " + this + " has an " +
413
// "implicit target, but the name " + name + " resolves to " +
414
// ctxtMI + " in " + ctxtMI.container() + " instead of " + mi+ " in " + mi.container(), position());
415
// }
416
}
417   }
418   
419 }
420
Popular Tags