001    package railo.transformer.bytecode.statement;
002    
003    import org.objectweb.asm.Label;
004    import org.objectweb.asm.Opcodes;
005    import org.objectweb.asm.Type;
006    import org.objectweb.asm.commons.GeneratorAdapter;
007    import org.objectweb.asm.commons.Method;
008    
009    import railo.runtime.util.ForEachUtil;
010    import railo.transformer.bytecode.Body;
011    import railo.transformer.bytecode.BytecodeContext;
012    import railo.transformer.bytecode.BytecodeException;
013    import railo.transformer.bytecode.Position;
014    import railo.transformer.bytecode.expression.Expression;
015    import railo.transformer.bytecode.expression.var.Variable;
016    import railo.transformer.bytecode.expression.var.VariableRef;
017    import railo.transformer.bytecode.util.ExpressionUtil;
018    import railo.transformer.bytecode.util.Types;
019    import railo.transformer.bytecode.visitor.OnFinally;
020    import railo.transformer.bytecode.visitor.TryFinallyVisitor;
021    
022    public final class ForEach extends StatementBase implements FlowControlBreak,FlowControlContinue,HasBody {
023    
024            
025            private Body body;
026            private VariableRef key;
027            private Variable value;
028    
029            private final static Method HAS_NEXT =          new Method("hasNext",Types.BOOLEAN_VALUE,new Type[]{});
030            private final static Method NEXT =                      new Method("next",Types.OBJECT,new Type[]{});
031            private final static Method SET =                       new Method("set",Types.OBJECT,new Type[]{Types.PAGE_CONTEXT,Types.OBJECT});
032            public static final Method TO_ITERATOR = new Method("toIterator",Types.ITERATOR,new Type[]{Types.OBJECT});
033            private static final Type FOR_EACH_UTIL = Type.getType(ForEachUtil.class);
034            protected static final Method RESET = new Method("reset",Types.VOID,new Type[]{Types.ITERATOR});
035    
036        //private static final Type COLLECTION_UTIL = Type.getType(CollectionUtil.class);
037    
038            private Label begin = new Label();
039            private Label end = new Label();
040            private FlowControlFinal fcf;
041            private String label;
042    
043            /**
044             * Constructor of the class
045             * @param key
046             * @param value
047             * @param body
048             * @param line
049             */
050            public ForEach(Variable key,Variable value,Body body,Position start, Position end,String label) {
051                    super(start,end);
052                    this.key=new VariableRef(key);
053                    this.value=value;
054                    this.body=body;
055                    this.label=label;
056                    body.setParent(this);
057                    
058            }
059            
060            @Override
061            public void _writeOut(BytecodeContext bc) throws BytecodeException {
062                    GeneratorAdapter adapter = bc.getAdapter();
063                    final int it=adapter.newLocal(Types.ITERATOR);
064                    final int item=adapter.newLocal(Types.REFERENCE);
065                    
066                    //Value
067                            // ForEachUtil.toIterator(value)
068                            value.writeOut(bc, Expression.MODE_REF);
069                            adapter.invokeStatic(FOR_EACH_UTIL, TO_ITERATOR);
070                            //adapter.invokeStatic(COLLECTION_UTIL, TO_ITERATOR);
071                            // Iterator it=...
072                            adapter.storeLocal(it);
073                            TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() {
074                                    
075                                    @Override
076                                    public void writeOut(BytecodeContext bc) throws BytecodeException {
077                                            GeneratorAdapter a = bc.getAdapter();
078                                            //if(fcf!=null && fcf.getAfterFinalGOTOLabel()!=null)ASMUtil.visitLabel(a,fcf.getFinalEntryLabel());
079                                            a.loadLocal(it);
080                                            a.invokeStatic(FOR_EACH_UTIL, RESET);
081                                            /*if(fcf!=null){
082                                                    Label l=fcf.getAfterFinalGOTOLabel();
083                                                    if(l!=null)a.visitJumpInsn(Opcodes.GOTO, l);
084                                            }*/
085                                    }
086                            },getFlowControlFinal());
087                            tfv.visitTryBegin(bc);
088                            // Key
089                                    // new VariableReference(...)
090                                    key.writeOut(bc, Expression.MODE_REF);
091                                    // VariableReference item=...
092                                    adapter.storeLocal(item);
093                            
094                            // while
095                                    ExpressionUtil.visitLine(bc, getStart());
096                                    adapter.visitLabel(begin);
097                                    
098                                    // hasNext
099                                    adapter.loadLocal(it);
100                                    adapter.invokeInterface(Types.ITERATOR, HAS_NEXT);
101                                    adapter.ifZCmp(Opcodes.IFEQ, end);
102                                    
103                                    // item.set(pc,it.next());
104                                    adapter.loadLocal(item);
105                                    adapter.loadArg(0);
106                                    adapter.loadLocal(it);
107                                    adapter.invokeInterface(Types.ITERATOR, NEXT);
108                                    adapter.invokeInterface(Types.REFERENCE, SET);
109                                    adapter.pop();
110                                    
111                                    // Body
112                                    body.writeOut(bc);
113                                    adapter.visitJumpInsn(Opcodes.GOTO, begin);
114                                    adapter.visitLabel(end);
115                            tfv.visitTryEnd(bc);
116                    
117            }
118    
119            @Override
120            public Label getBreakLabel() {
121                    return end;
122            }
123    
124            @Override
125            public Label getContinueLabel() {
126                    return begin;
127            }
128    
129            @Override
130            public Body getBody() {
131                    return body;
132            }
133    
134            @Override
135            public FlowControlFinal getFlowControlFinal() {
136                    if(fcf==null) fcf=new FlowControlFinalImpl();
137                    return fcf;
138            }
139    
140            @Override
141            public String getLabel() {
142                    return label;
143            }
144    }