KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jac > core > translators > VMStack


1 /*
2   Copyright (C) 2002-2003 Laurent Martelli <laurent@aopsys.com>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU Lesser General Public License as
6   published by the Free Software Foundation; either version 2 of the
7   License, or (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   Lesser General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public
15   License along with this program; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17   USA */

18
19 package org.objectweb.jac.core.translators;
20
21 import java.io.Serializable JavaDoc;
22 import java.util.Arrays JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.Set JavaDoc;
25 import java.util.Vector JavaDoc;
26 import org.apache.bcel.classfile.*;
27 import org.apache.bcel.generic.*;
28 import org.apache.log4j.Logger;
29 import org.objectweb.jac.util.Stack;
30
31 /**
32  * Represents the VM stack
33  */

34 public class VMStack extends Stack {
35     static Logger logger = Logger.getLogger("translator.bytecode");
36
37     public static final ThisPointer thisPointer = new ThisPointer();
38     public static final DontCare dontCare = new DontCare();
39
40     static final int UNPREDICTABLE = -1;
41     static final int UNDEFINED = -2;
42
43     Vector JavaDoc locals = new Vector JavaDoc(); // Local variables
44

45     ConstantPoolGen cp;
46     int[] exceptionHandlers;
47     int currentHandler = 0;
48     int nbArgs;
49     int localsOffest;
50     boolean isStatic;
51     public VMStack(ConstantPoolGen cp, Code code, int nbArgs, boolean isStatic) {
52         this.cp = cp;
53         this.nbArgs = nbArgs;
54         this.isStatic = isStatic;
55         this.localsOffest = nbArgs+(isStatic?1:0);
56         if (code!=null) {
57             CodeException[] exceptions = code.getExceptionTable();
58             exceptionHandlers = new int[exceptions.length];
59             for (int i=0; i<exceptions.length; i++) {
60                 exceptionHandlers[i] = exceptions[i].getHandlerPC();
61                 logger.debug("Exception handler at "+exceptionHandlers[i]);
62             }
63             Arrays.sort(exceptionHandlers);
64         }
65     }
66
67     public void preExecute(InstructionHandle ih) {
68         if (currentHandler<exceptionHandlers.length)
69             logger.debug("position="+ih.getPosition()+", nextHandler="+exceptionHandlers[currentHandler]);
70         if ( currentHandler<exceptionHandlers.length &&
71              ih.getPosition()==exceptionHandlers[currentHandler] ) {
72             logger.debug("entering exception handler");
73             currentHandler++;
74             push(dontCare);
75         }
76     }
77
78     static Set JavaDoc primitiveWrapperTypes = new HashSet JavaDoc();
79     static {
80         primitiveWrapperTypes.add("java.lang.Float");
81         primitiveWrapperTypes.add("java.lang.Double");
82         primitiveWrapperTypes.add("java.lang.Integer");
83         primitiveWrapperTypes.add("java.lang.Long");
84         primitiveWrapperTypes.add("java.lang.Boolean");
85         primitiveWrapperTypes.add("java.lang.Character");
86         primitiveWrapperTypes.add("java.lang.Byte");
87     }
88
89     public void execute(Instruction i, InstructionHandle ih) {
90         logger.debug("execute "+i.toString(cp.getConstantPool()));
91
92         if (i instanceof SWAP) {
93             swap();
94         } else if (i instanceof DUP || i instanceof DUP2) {
95             push(peek());
96         } else if (i instanceof DUP_X1 || i instanceof DUP2_X2 ||
97                    i instanceof DUP2_X1 || i instanceof DUP_X2) {
98             swap();
99             push(peek(1));
100         } else if (i instanceof ALOAD && ((ALOAD)i).getIndex() == 0
101                    && !isStatic) {
102             push(thisPointer);
103         } else if (i instanceof NEW) {
104             if (primitiveWrapperTypes.contains(
105                 ((NEW)i).getLoadClassType(cp).getClassName())) {
106                 push(new PrimitiveValue(((NEW)i).getLoadClassType(cp).getClassName()));
107             } else {
108                 push(new Instance(
109                     ((NEW)i).getLoadClassType(cp).getClassName(),ih));
110             }
111         } else if (i instanceof LoadInstruction) {
112             LoadInstruction load = (LoadInstruction)i;
113             if (load.getIndex()<=nbArgs) {
114                 push(new Argument(load.getIndex()));
115             } else {
116                 int index = load.getIndex()-nbArgs;
117                 // We must ensure the size of locals is correct
118
// because a LOAD may occur before a STORE in the
119
// bytecode (because of a JMP)
120
if (locals.size()<index+1)
121                     locals.setSize(index+1);
122                 push(locals.get(index));
123             }
124         } else if (i instanceof StoreInstruction) {
125             StoreInstruction store = (StoreInstruction)i;
126             if (store.getIndex()<=nbArgs) {
127             } else {
128                 int index = store.getIndex()-nbArgs;
129                 if (locals.size()<store.getIndex()+1)
130                     locals.setSize(store.getIndex()+1);
131                 locals.set(store.getIndex(),peek());
132             }
133             consume(i);
134         } else if (i instanceof GETFIELD) {
135             Object JavaDoc substance = peek();
136             consume(i);
137             push(new FieldValue(substance,
138                                 ((GETFIELD)i).getIndex(),
139                                 ((GETFIELD)i).getFieldName(cp)));
140         } else if (i instanceof GETSTATIC) {
141             consume(i);
142             push(new FieldValue(null,
143                                 ((GETSTATIC)i).getIndex(),
144                                 ((GETSTATIC)i).getFieldName(cp)));
145         } else if (i instanceof INVOKESPECIAL &&
146                    ((INVOKESPECIAL)i).getMethodName(cp).equals("<init>")) {
147             Object JavaDoc invoked = invokedObject((INVOKESPECIAL)i);
148             if (invoked instanceof PrimitiveValue)
149                 ((PrimitiveValue)invoked).wrappedValue = peek();
150             consume(i);
151             produce(i);
152             /*
153         } else if (i instanceof InvokeInstruction) {
154             InvokeInstruction invoke = (InvokeInstruction)i;
155             if (invoke.getMethodName(cp).equals("iterator")) {
156                 consume(i);
157                 push(new IteratorValue(peek()));
158             } else if (invoke.getMethodName(cp).equals("next") &&
159                        peek() instanceof IteratorValue) {
160                 consume(i);
161                 push(new CollectionValue(((IteratorValue)peek()).collection));
162             } else {
163                 consume(i);
164                 produce(i);
165             }
166             */

167         } else if (i instanceof CHECKCAST || i instanceof ATHROW) {
168             // nothing
169
} else if (i instanceof ANEWARRAY) {
170             // BCEL bug workaround (ANEWARRAY is a StackProducer but not
171
// a StackConsumer)
172
pop(1);
173             push(dontCare);
174         } else {
175             consume(i);
176             produce(i);
177         }
178         logger.debug("stack: "+this);
179     }
180
181     /**
182      * Returns the stack element corresponding to the object on which
183      * the InvokeInstruction is applied.
184      */

185     public Object JavaDoc invokedObject(InvokeInstruction i) {
186         return peek(i.getArgumentTypes(cp).length);
187     }
188
189     /**
190      * Consume values from the stack for the given instruction
191      */

192     public void consume(Instruction i) {
193         if (i instanceof StackConsumer)
194             pop(getConsumed(i,cp));
195     }
196     public void produce(Instruction i) {
197         if (i instanceof StackProducer) {
198             for(int j=0; j<getProduced(i,cp); j++)
199                 push(dontCare);
200         }
201     }
202     /**
203      * Returns the number of elements from the stack consumed by an
204      * instruction
205      */

206     public static int getConsumed(Instruction i, ConstantPoolGen cp) {
207         if (i instanceof INVOKESTATIC)
208             return ((InvokeInstruction)i).getArgumentTypes(cp).length;
209         else if (i instanceof InvokeInstruction)
210             return ((InvokeInstruction)i).getArgumentTypes(cp).length+1;
211         else if (i instanceof MULTIANEWARRAY)
212             return ((MULTIANEWARRAY)i).getDimensions();
213         else
214             return CONSUME_STACK[i.getOpcode()];
215     }
216
217     /**
218      * Returns the number of elements produced on the stack by an instruction
219      */

220     public static int getProduced(Instruction i, ConstantPoolGen cp) {
221         if (i instanceof InvokeInstruction) {
222             return ((InvokeInstruction)i).getReturnType(cp)==Type.VOID ? 0 : 1;
223         } else {
224             return PRODUCE_STACK[i.getOpcode()];
225         }
226     }
227
228     /**
229      * Gets the value on which a method is invoked
230      * @param invoke the invoke instruction
231      */

232     public Object JavaDoc getSubstance(InvokeInstruction invoke) {
233         return peek(invoke.getArgumentTypes(cp).length);
234     }
235
236     static final int[] CONSUME_STACK = {
237         0/*nop*/, 0/*aconst_null*/, 0/*iconst_m1*/, 0/*iconst_0*/, 0/*iconst_1*/,
238         0/*iconst_2*/, 0/*iconst_3*/, 0/*iconst_4*/, 0/*iconst_5*/, 0/*lconst_0*/,
239         0/*lconst_1*/, 0/*fconst_0*/, 0/*fconst_1*/, 0/*fconst_2*/, 0/*dconst_0*/,
240         0/*dconst_1*/, 0/*bipush*/, 0/*sipush*/, 0/*ldc*/, 0/*ldc_w*/, 0/*ldc2_w*/, 0/*iload*/,
241         0/*lload*/, 0/*fload*/, 0/*dload*/, 0/*aload*/, 0/*iload_0*/, 0/*iload_1*/, 0/*iload_2*/,
242         0/*iload_3*/, 0/*lload_0*/, 0/*lload_1*/, 0/*lload_2*/, 0/*lload_3*/, 0/*fload_0*/,
243         0/*fload_1*/, 0/*fload_2*/, 0/*fload_3*/, 0/*dload_0*/, 0/*dload_1*/, 0/*dload_2*/,
244         0/*dload_3*/, 0/*aload_0*/, 0/*aload_1*/, 0/*aload_2*/, 0/*aload_3*/, 2/*iaload*/,
245         2/*laload*/, 2/*faload*/, 2/*daload*/, 2/*aaload*/, 2/*baload*/, 2/*caload*/, 2/*saload*/,
246         1/*istore*/, 1/*lstore*/, 1/*fstore*/, 1/*dstore*/, 1/*astore*/, 1/*istore_0*/,
247         1/*istore_1*/, 1/*istore_2*/, 1/*istore_3*/, 1/*lstore_0*/, 1/*lstore_1*/,
248         1/*lstore_2*/, 1/*lstore_3*/, 1/*fstore_0*/, 1/*fstore_1*/, 1/*fstore_2*/,
249         1/*fstore_3*/, 1/*dstore_0*/, 1/*dstore_1*/, 1/*dstore_2*/, 1/*dstore_3*/,
250         1/*astore_0*/, 1/*astore_1*/, 1/*astore_2*/, 1/*astore_3*/, 3/*iastore*/, 3/*lastore*/,
251         3/*fastore*/, 3/*dastore*/, 3/*aastore*/, 3/*bastore*/, 3/*castore*/, 3/*sastore*/,
252         1/*pop*/, 1/*pop2*/, 1/*dup*/, 2/*dup_x1*/, 3/*dup_x2*/, 1/*dup2*/, 3/*dup2_x1*/,
253         4/*dup2_x2*/, 2/*swap*/, 2/*iadd*/, 2/*ladd*/, 2/*fadd*/, 2/*dadd*/, 2/*isub*/, 2/*lsub*/,
254         2/*fsub*/, 2/*dsub*/, 2/*imul*/, 2/*lmul*/, 2/*fmul*/, 2/*dmul*/, 2/*idiv*/, 2/*ldiv*/,
255         2/*fdiv*/, 2/*ddiv*/, 2/*irem*/, 2/*lrem*/, 2/*frem*/, 2/*drem*/, 1/*ineg*/, 1/*lneg*/,
256         1/*fneg*/, 1/*dneg*/, 2/*ishl*/, 2/*lshl*/, 2/*ishr*/, 2/*lshr*/, 2/*iushr*/, 2/*lushr*/,
257         2/*iand*/, 2/*land*/, 2/*ior*/, 2/*lor*/, 2/*ixor*/, 2/*lxor*/, 0/*iinc*/,
258         1/*i2l*/, 1/*i2f*/, 1/*i2d*/, 1/*l2i*/, 1/*l2f*/, 1/*l2d*/, 1/*f2i*/, 1/*f2l*/,
259         1/*f2d*/, 1/*d2i*/, 1/*d2l*/, 1/*d2f*/, 1/*i2b*/, 1/*i2c*/, 1/*i2s*/,
260         2/*lcmp*/, 2/*fcmpl*/, 2/*fcmpg*/, 2/*dcmpl*/, 2/*dcmpg*/, 1/*ifeq*/, 1/*ifne*/,
261         1/*iflt*/, 1/*ifge*/, 1/*ifgt*/, 1/*ifle*/, 2/*if_icmpeq*/, 2/*if_icmpne*/, 2/*if_icmplt*/,
262         2 /*if_icmpge*/, 2/*if_icmpgt*/, 2/*if_icmple*/, 2/*if_acmpeq*/, 2/*if_acmpne*/,
263         0/*goto*/, 0/*jsr*/, 0/*ret*/, 1/*tableswitch*/, 1/*lookupswitch*/, 1/*ireturn*/,
264         1/*lreturn*/, 1/*freturn*/, 1/*dreturn*/, 1/*areturn*/, 0/*return*/, 0/*getstatic*/,
265         1,/*putstatic*/ 1/*getfield*/, 2/*putfield*/,
266         UNPREDICTABLE/*invokevirtual*/, UNPREDICTABLE/*invokespecial*/,
267         UNPREDICTABLE/*invokestatic*/,
268         UNPREDICTABLE/*invokeinterface*/, UNDEFINED, 0/*new*/, 1/*newarray*/, 1/*anewarray*/,
269         1/*arraylength*/, 1/*athrow*/, 1/*checkcast*/, 1/*instanceof*/, 1/*monitorenter*/,
270         1/*monitorexit*/, 0/*wide*/, UNPREDICTABLE/*multianewarray*/, 1/*ifnull*/, 1/*ifnonnull*/,
271         0/*goto_w*/, 0/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED,
272         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
273         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
274         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
275         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
276         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
277         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
278         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
279         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
280         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
281         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
282         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
283         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
284         UNDEFINED, UNPREDICTABLE/*impdep1*/, UNPREDICTABLE/*impdep2*/
285     };
286
287     public static final int[] PRODUCE_STACK = {
288         0/*nop*/, 1/*aconst_null*/, 1/*iconst_m1*/, 1/*iconst_0*/, 1/*iconst_1*/,
289         1/*iconst_2*/, 1/*iconst_3*/, 1/*iconst_4*/, 1/*iconst_5*/, 1/*lconst_0*/,
290         1/*lconst_1*/, 1/*fconst_0*/, 1/*fconst_1*/, 1/*fconst_2*/, 1/*dconst_0*/,
291         1/*dconst_1*/, 1/*bipush*/, 1/*sipush*/, 1/*ldc*/, 1/*ldc_w*/, 1/*ldc2_w*/, 1/*iload*/,
292         1/*lload*/, 1/*fload*/, 1/*dload*/, 1/*aload*/, 1/*iload_0*/, 1/*iload_1*/, 1/*iload_2*/,
293         1/*iload_3*/, 1/*lload_0*/, 1/*lload_1*/, 1/*lload_2*/, 1/*lload_3*/, 1/*fload_0*/,
294         1/*fload_1*/, 1/*fload_2*/, 1/*fload_3*/, 1/*dload_0*/, 1/*dload_1*/, 1/*dload_2*/,
295         1/*dload_3*/, 1/*aload_0*/, 1/*aload_1*/, 1/*aload_2*/, 1/*aload_3*/, 1/*iaload*/,
296         1/*laload*/, 1/*faload*/, 1/*daload*/, 1/*aaload*/, 1/*baload*/, 1/*caload*/, 1/*saload*/,
297         0/*istore*/, 0/*lstore*/, 0/*fstore*/, 0/*dstore*/, 0/*astore*/, 0/*istore_0*/,
298         0/*istore_1*/, 0/*istore_2*/, 0/*istore_3*/, 0/*lstore_0*/, 0/*lstore_1*/,
299         0/*lstore_2*/, 0/*lstore_3*/, 0/*fstore_0*/, 0/*fstore_1*/, 0/*fstore_2*/,
300         0/*fstore_3*/, 0/*dstore_0*/, 0/*dstore_1*/, 0/*dstore_2*/, 0/*dstore_3*/,
301         0/*astore_0*/, 0/*astore_1*/, 0/*astore_2*/, 0/*astore_3*/, 0/*iastore*/, 0/*lastore*/,
302         0/*fastore*/, 0/*dastore*/, 0/*aastore*/, 0/*bastore*/, 0/*castore*/, 0/*sastore*/,
303         0/*pop*/, 0/*pop2*/, 2/*dup*/, 3/*dup_x1*/, 4/*dup_x2*/, 4/*dup2*/, 5/*dup2_x1*/,
304         6/*dup2_x2*/, 2/*swap*/, 1/*iadd*/, 1/*ladd*/, 1/*fadd*/, 1/*dadd*/, 1/*isub*/, 1/*lsub*/,
305         1/*fsub*/, 1/*dsub*/, 1/*imul*/, 1/*lmul*/, 1/*fmul*/, 1/*dmul*/, 1/*idiv*/, 1/*ldiv*/,
306         1/*fdiv*/, 1/*ddiv*/, 1/*irem*/, 1/*lrem*/, 1/*frem*/, 1/*drem*/, 1/*ineg*/, 1/*lneg*/,
307         1/*fneg*/, 1/*dneg*/, 1/*ishl*/, 1/*lshl*/, 1/*ishr*/, 1/*lshr*/, 1/*iushr*/, 1/*lushr*/,
308         1/*iand*/, 1/*land*/, 1/*ior*/, 1/*lor*/, 1/*ixor*/, 1/*lxor*/,
309         0/*iinc*/, 1/*i2l*/, 1/*i2f*/, 1/*i2d*/, 1/*l2i*/, 1/*l2f*/, 1/*l2d*/, 1/*f2i*/,
310         1/*f2l*/, 1/*f2d*/, 1/*d2i*/, 1/*d2l*/, 1/*d2f*/,
311         1/*i2b*/, 1/*i2c*/, 1/*i2s*/, 1/*lcmp*/, 1/*fcmpl*/, 1/*fcmpg*/,
312         1/*dcmpl*/, 1/*dcmpg*/, 0/*ifeq*/, 0/*ifne*/, 0/*iflt*/, 0/*ifge*/, 0/*ifgt*/, 0/*ifle*/,
313         0/*if_icmpeq*/, 0/*if_icmpne*/, 0/*if_icmplt*/, 0/*if_icmpge*/, 0/*if_icmpgt*/,
314         0/*if_icmple*/, 0/*if_acmpeq*/, 0/*if_acmpne*/, 0/*goto*/, 1/*jsr*/, 0/*ret*/,
315         0/*tableswitch*/, 0/*lookupswitch*/, 0/*ireturn*/, 0/*lreturn*/, 0/*freturn*/,
316         0/*dreturn*/, 0/*areturn*/, 0/*return*/, 1/*getstatic*/, 0/*putstatic*/,
317         1/*getfield*/, 0/*putfield*/, UNPREDICTABLE/*invokevirtual*/,
318         UNPREDICTABLE/*invokespecial*/, UNPREDICTABLE/*invokestatic*/,
319         UNPREDICTABLE/*invokeinterface*/, UNDEFINED, 1/*new*/, 1/*newarray*/, 1/*anewarray*/,
320         1/*arraylength*/, 1/*athrow*/, 1/*checkcast*/, 1/*instanceof*/, 0/*monitorenter*/,
321         0/*monitorexit*/, 0/*wide*/, 1/*multianewarray*/, 0/*ifnull*/, 0/*ifnonnull*/,
322         0/*goto_w*/, 1/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED,
323         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
324         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
325         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
326         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
327         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
328         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
329         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
330         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
331         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
332         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
333         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
334         UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED,
335         UNDEFINED, UNPREDICTABLE/*impdep1*/, UNPREDICTABLE/*impdep2*/
336     };
337
338     // various classes to represent values on the stack
339
public static class ThisPointer implements Serializable JavaDoc {
340         public String JavaDoc toString() { return "This"; }
341     }
342
343     /** Unknown value */
344     public static class DontCare implements Serializable JavaDoc {
345         public String JavaDoc toString() { return "???"; }
346     }
347
348     /** Instance of a class */
349     public static class Instance implements Serializable JavaDoc {
350         public String JavaDoc type;
351         /** the InstructionHandle who created this instance */
352         public transient InstructionHandle newHandle;
353         public transient InstructionHandle initHandle;
354         public Instance(String JavaDoc type, InstructionHandle newHandle) {
355             this.type = type;
356             this.newHandle = newHandle;
357         }
358         public String JavaDoc toString() { return type; }
359     }
360
361     /** An argument */
362     public static class Argument implements Serializable JavaDoc {
363         public int n;
364         public Argument(int n) { this.n = n; }
365         public String JavaDoc toString() { return "arg["+n+"]"; }
366     }
367
368     /** The value of a field */
369     public static class FieldValue implements Serializable JavaDoc {
370         int index; // const pool FieldRef index
371
String JavaDoc field; // name of field
372
Object JavaDoc substance; // owner of the field
373
public FieldValue(Object JavaDoc substance, int index, String JavaDoc field) {
374             this.field = field;
375             this.index = index;
376             this.substance = substance;
377         }
378         public String JavaDoc toString() { return substance+"."+field; }
379     }
380
381     /** A primitive value */
382     public static class PrimitiveValue implements Serializable JavaDoc {
383         public Object JavaDoc wrappedValue;
384         public String JavaDoc type;
385         public PrimitiveValue(String JavaDoc type) {
386             this.type = type;
387             this.wrappedValue = null;
388         }
389         public String JavaDoc toString() {
390             return type+"("+wrappedValue+")";
391         }
392     }
393
394     /** An iterator on a collection */
395     public static class IteratorValue {
396         public Object JavaDoc collection;
397         public IteratorValue(Object JavaDoc collection) {
398             this.collection = collection;
399         }
400         public String JavaDoc toString() {
401             return "iterator("+collection.toString()+")";
402         }
403     }
404
405     /** An item of a collection */
406     public static class CollectionValue {
407         public Object JavaDoc collection;
408         public CollectionValue(Object JavaDoc collection) {
409             this.collection = collection;
410         }
411         public String JavaDoc toString() {
412             return "iterator("+collection.toString()+")";
413         }
414     }
415 }
416
417
Popular Tags