/** * Copyright (c) 2014, the Railo Company Ltd. * Copyright (c) 2015, Lucee Assosication Switzerland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ package lucee.transformer.bytecode.statement; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import lucee.transformer.Position; import lucee.transformer.TransformerException; import lucee.transformer.bytecode.Body; import lucee.transformer.bytecode.BytecodeContext; import lucee.transformer.bytecode.util.Types; import lucee.transformer.expression.Expression; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; public final class Switch extends StatementBaseNoFinal implements FlowControlBreak,HasBodies { // Object append(Object o) private static final Method APPEND = new Method( "append", Types.OBJECT, new Type[]{Types.OBJECT} ); public static final Method INIT = new Method( "<init>", Types.VOID, new Type[]{} ); // int find(Array array, Object object) private static final Method FIND = new Method( "find", Types.INT_VALUE, new Type[]{Types.ARRAY,Types.OBJECT} ); private List<Case> cases=new ArrayList<Case>(); private Body defaultCase; private Expression expr; private NativeSwitch ns; public Switch(Expression expr,Position start, Position end) { super(expr.getFactory(),start, end); this.expr=expr; } public void addCase(Expression expr, Body body) { addCase(expr, body, null, null); } public void addCase(Expression expr, Body body,Position start,Position end) { //if(cases==null) cases=new ArrayList(); cases.add(new Case(expr,body,start,end)); body.setParent(this); } public void setDefaultCase(Body body) { defaultCase=body; body.setParent(this); } public final class Case { private Expression expression; private Body body; private Position startPos; private Position endPos; public Case(Expression expression, Body body,Position start,Position end) { this.expression=expression; this.body=body; this.startPos=start; this.endPos=end; } } @Override public void _writeOut(BytecodeContext bc) throws TransformerException { GeneratorAdapter adapter = bc.getAdapter(); // Array cases=new ArrayImpl(); int array=adapter.newLocal(Types.ARRAY); adapter.newInstance(Types.ARRAY_IMPL); adapter.dup(); adapter.invokeConstructor(Types.ARRAY_IMPL, INIT); adapter.storeLocal(array); // cases.append(case.value); Iterator<Case> it = cases.iterator(); Case c; while(it.hasNext()) { c=it.next(); adapter.loadLocal(array); c.expression.writeOut(bc, Expression.MODE_REF); adapter.invokeVirtual(Types.ARRAY_IMPL, APPEND); adapter.pop(); } // int result=ArrayUtil.find(array,expression); int result=adapter.newLocal(Types.INT_VALUE); adapter.loadLocal(array); expr.writeOut(bc, Expression.MODE_REF); adapter.invokeStatic(Types.ARRAY_UTIL, FIND); adapter.storeLocal(result); // switch(result) ns=new NativeSwitch(bc.getFactory(),result,NativeSwitch.LOCAL_REF,getStart(),getEnd()); it = cases.iterator(); int count=1; while(it.hasNext()) { c=it.next(); ns.addCase(count++, c.body,c.startPos,c.endPos,false); } if(defaultCase!=null)ns.addDefaultCase(defaultCase); ns.writeOut(bc); } /** * * @see lucee.transformer.bytecode.statement.FlowControl#getBreakLabel() */ @Override public Label getBreakLabel() { return ns.getBreakLabel(); } /** * * @see lucee.transformer.bytecode.statement.FlowControl#getContinueLabel() */ public Label getContinueLabel() { return ns.getContinueLabel(); } /** * @see lucee.transformer.bytecode.statement.HasBodies#getBodies() */ @Override public Body[] getBodies() { if(cases==null) { if(defaultCase!=null) return new Body[]{defaultCase}; return new Body[]{}; } int len=cases.size(),count=0; if(defaultCase!=null)len++; Body[] bodies=new Body[len]; Case c; Iterator<Case> it = cases.iterator(); while(it.hasNext()) { c=it.next(); bodies[count++]=c.body; } if(defaultCase!=null)bodies[count++]=defaultCase; return bodies; } @Override public String getLabel() { return null; } }