001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.transformer.bytecode.statement; 020 021import lucee.runtime.util.ForEachUtil; 022import lucee.transformer.bytecode.Body; 023import lucee.transformer.bytecode.BytecodeContext; 024import lucee.transformer.bytecode.BytecodeException; 025import lucee.transformer.bytecode.Position; 026import lucee.transformer.bytecode.expression.Expression; 027import lucee.transformer.bytecode.expression.var.Variable; 028import lucee.transformer.bytecode.expression.var.VariableRef; 029import lucee.transformer.bytecode.util.ExpressionUtil; 030import lucee.transformer.bytecode.util.Types; 031import lucee.transformer.bytecode.visitor.OnFinally; 032import lucee.transformer.bytecode.visitor.TryFinallyVisitor; 033 034import org.objectweb.asm.Label; 035import org.objectweb.asm.Opcodes; 036import org.objectweb.asm.Type; 037import org.objectweb.asm.commons.GeneratorAdapter; 038import org.objectweb.asm.commons.Method; 039 040public final class ForEach extends StatementBase implements FlowControlBreak,FlowControlContinue,HasBody { 041 042 043 private Body body; 044 private VariableRef key; 045 private Expression value; 046 047 private final static Method HAS_NEXT = new Method("hasNext",Types.BOOLEAN_VALUE,new Type[]{}); 048 private final static Method NEXT = new Method("next",Types.OBJECT,new Type[]{}); 049 private final static Method SET = new Method("set",Types.OBJECT,new Type[]{Types.PAGE_CONTEXT,Types.OBJECT}); 050 public static final Method TO_ITERATOR = new Method("toIterator",Types.ITERATOR,new Type[]{Types.OBJECT}); 051 private static final Type FOR_EACH_UTIL = Type.getType(ForEachUtil.class); 052 protected static final Method RESET = new Method("reset",Types.VOID,new Type[]{Types.ITERATOR}); 053 054 //private static final Type COLLECTION_UTIL = Type.getType(CollectionUtil.class); 055 056 private Label begin = new Label(); 057 private Label end = new Label(); 058 private FlowControlFinal fcf; 059 private String label; 060 061 /** 062 * Constructor of the class 063 * @param key 064 * @param value 065 * @param body 066 * @param line 067 */ 068 public ForEach(Variable key,Expression value,Body body,Position start, Position end,String label) { 069 super(start,end); 070 this.key=new VariableRef(key); 071 this.value=value; 072 this.body=body; 073 this.label=label; 074 body.setParent(this); 075 076 } 077 078 @Override 079 public void _writeOut(BytecodeContext bc) throws BytecodeException { 080 GeneratorAdapter adapter = bc.getAdapter(); 081 final int it=adapter.newLocal(Types.ITERATOR); 082 final int item=adapter.newLocal(Types.REFERENCE); 083 084 //Value 085 // ForEachUtil.toIterator(value) 086 value.writeOut(bc, Expression.MODE_REF); 087 adapter.invokeStatic(FOR_EACH_UTIL, TO_ITERATOR); 088 //adapter.invokeStatic(COLLECTION_UTIL, TO_ITERATOR); 089 // Iterator it=... 090 adapter.storeLocal(it); 091 TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() { 092 093 @Override 094 public void _writeOut(BytecodeContext bc) throws BytecodeException { 095 GeneratorAdapter a = bc.getAdapter(); 096 //if(fcf!=null && fcf.getAfterFinalGOTOLabel()!=null)ASMUtil.visitLabel(a,fcf.getFinalEntryLabel()); 097 a.loadLocal(it); 098 a.invokeStatic(FOR_EACH_UTIL, RESET); 099 /*if(fcf!=null){ 100 Label l=fcf.getAfterFinalGOTOLabel(); 101 if(l!=null)a.visitJumpInsn(Opcodes.GOTO, l); 102 }*/ 103 } 104 },getFlowControlFinal()); 105 tfv.visitTryBegin(bc); 106 // Key 107 // new VariableReference(...) 108 key.writeOut(bc, Expression.MODE_REF); 109 // VariableReference item=... 110 adapter.storeLocal(item); 111 112 // while 113 ExpressionUtil.visitLine(bc, getStart()); 114 adapter.visitLabel(begin); 115 116 // hasNext 117 adapter.loadLocal(it); 118 adapter.invokeInterface(Types.ITERATOR, HAS_NEXT); 119 adapter.ifZCmp(Opcodes.IFEQ, end); 120 121 // item.set(pc,it.next()); 122 adapter.loadLocal(item); 123 adapter.loadArg(0); 124 adapter.loadLocal(it); 125 adapter.invokeInterface(Types.ITERATOR, NEXT); 126 adapter.invokeInterface(Types.REFERENCE, SET); 127 adapter.pop(); 128 129 // Body 130 body.writeOut(bc); 131 adapter.visitJumpInsn(Opcodes.GOTO, begin); 132 adapter.visitLabel(end); 133 tfv.visitTryEnd(bc); 134 135 } 136 137 @Override 138 public Label getBreakLabel() { 139 return end; 140 } 141 142 @Override 143 public Label getContinueLabel() { 144 return begin; 145 } 146 147 @Override 148 public Body getBody() { 149 return body; 150 } 151 152 @Override 153 public FlowControlFinal getFlowControlFinal() { 154 if(fcf==null) fcf=new FlowControlFinalImpl(); 155 return fcf; 156 } 157 158 @Override 159 public String getLabel() { 160 return label; 161 } 162}