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.transformer.bytecode.Body;
010    import railo.transformer.bytecode.BytecodeContext;
011    import railo.transformer.bytecode.BytecodeException;
012    import railo.transformer.bytecode.expression.Expression;
013    import railo.transformer.bytecode.expression.var.Variable;
014    import railo.transformer.bytecode.expression.var.VariableRef;
015    import railo.transformer.bytecode.util.ExpressionUtil;
016    import railo.transformer.bytecode.util.Types;
017    
018    public final class ForEach extends StatementBase implements FlowControl,HasBody {
019    
020            
021            private Body body;
022            private VariableRef key;
023            private Variable value;
024    
025            private final static Method TO_COLLECTION =     new Method("toCollection",Types.COLLECTION,new Type[]{Types.OBJECT});
026            //private final static Method TO_ITERATOR =     new Method("toIterator",Types.ITERATOR,new Type[]{Types.COLLECTION});
027            private final static Method ITERATOR =  new Method("iterator",Types.ITERATOR,new Type[]{});
028            //private final static Method KEY_ITERATORx =   new Method("keyIterator",Types.ITERATOR,new Type[]{});
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    
033        //private static final Type COLLECTION_UTIL = Type.getType(CollectionUtil.class);
034    
035            private Label begin = new Label();
036            private Label end = new Label();
037    
038            /**
039             * Constructor of the class
040             * @param key
041             * @param value
042             * @param body
043             * @param line
044             */
045            public ForEach(Variable key,Variable value,Body body,int startline,int endline) {
046                    super(startline,endline);
047                    this.key=new VariableRef(key);
048                    this.value=value;
049                    this.body=body;
050                    body.setParent(this);
051                    
052            }
053            
054            /**
055             *
056             * @see railo.transformer.bytecode.statement.StatementBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter)
057             */
058            public void _writeOut(BytecodeContext bc) throws BytecodeException {
059                    GeneratorAdapter adapter = bc.getAdapter();
060                    int it=adapter.newLocal(Types.ITERATOR);
061                    int item=adapter.newLocal(Types.REFERENCE);
062    
063                    //Value
064                            // Caster.toCollection(value)
065                            value.writeOut(bc, Expression.MODE_REF);
066                            adapter.invokeStatic(Types.CASTER, TO_COLLECTION);
067                            // ...iterator()
068                            adapter.invokeInterface(Types.COLLECTION, ITERATOR);
069                            //adapter.invokeStatic(COLLECTION_UTIL, TO_ITERATOR);
070                            // Iterator it=...
071                            adapter.storeLocal(it);
072                    // Key
073                            // new VariableReference(...)
074                            key.writeOut(bc, Expression.MODE_REF);
075                            // VariableReference item=...
076                            adapter.storeLocal(item);
077                    
078                    // while
079                            ExpressionUtil.visitLine(bc, getStartLine());
080                            adapter.visitLabel(begin);
081                            
082                            // hasNext
083                            adapter.loadLocal(it);
084                            adapter.invokeInterface(Types.ITERATOR, HAS_NEXT);
085                            adapter.ifZCmp(Opcodes.IFEQ, end);
086                            
087                            // item.set(pc,it.next());
088                            adapter.loadLocal(item);
089                            adapter.loadArg(0);
090                            adapter.loadLocal(it);
091                            adapter.invokeInterface(Types.ITERATOR, NEXT);
092                            adapter.invokeInterface(Types.REFERENCE, SET);
093                            adapter.pop();
094                            
095                            // Body
096                            body.writeOut(bc);
097                            adapter.visitJumpInsn(Opcodes.GOTO, begin);
098                            adapter.visitLabel(end);
099                    
100            }
101    /*
102            
103    <!--
104    for-each
105            Definiert eine for-each Schleife.
106            Dazu werden direkt Sprachkonstrukte von PHP genutzt.
107    -->
108    <xsl:template match="for-each">
109    <xsl:variable name="i">_<xsl:value-of select="generate-id(.)"/></xsl:variable>
110            railo.runtime.type.Collection coll<xsl:value-of select="$i"/>=Caster.toCollection(<xsl:apply-templates select="./value"/>);
111            java.util.Iterator it<xsl:value-of select="$i"/>=coll<xsl:value-of select="$i"/>.iterator();
112            railo.runtime.util.VariableReference item<xsl:value-of select="$i"/>=
113            <xsl:apply-templates select="./key"  mode="reference"/>;
114            
115            while(it<xsl:value-of select="$i"/>.hasNext()) {
116                    item<xsl:value-of select="$i"/>.set(pc,it<xsl:value-of select="$i"/>.next());
117                    <xsl:apply-templates select="./script-body"/>
118            }
119    </xsl:template>
120    
121    
122            */
123    
124            /**
125             *
126             * @see railo.transformer.bytecode.statement.FlowControl#getBreakLabel()
127             */
128            public Label getBreakLabel() {
129                    return end;
130            }
131    
132            /**
133             *
134             * @see railo.transformer.bytecode.statement.FlowControl#getContinueLabel()
135             */
136            public Label getContinueLabel() {
137                    return begin;
138            }
139    
140            /**
141             * @see railo.transformer.bytecode.statement.HasBody#getBody()
142             */
143            public Body getBody() {
144                    return body;
145            }
146    }