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 }