package railo.transformer.bytecode.statement; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.objectweb.asm.Label; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import railo.transformer.bytecode.Body; import railo.transformer.bytecode.BytecodeContext; import railo.transformer.bytecode.BytecodeException; import railo.transformer.bytecode.Position; import railo.transformer.bytecode.expression.Expression; import railo.transformer.bytecode.util.Types; public final class Switch extends StatementBaseNoFinal implements FlowControlBreak,HasBodies { private static final Type ARRAY_IMPL=Type.getType(railo.runtime.type.ArrayImpl.class); // Object append(Object o) private static final Method APPEND = new Method( "append", Types.OBJECT, new Type[]{Types.OBJECT} ); private 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(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; } } /** * @see railo.transformer.bytecode.statement.StatementBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter) */ public void _writeOut(BytecodeContext bc) throws BytecodeException { GeneratorAdapter adapter = bc.getAdapter(); // Array cases=new ArrayImpl(); int array=adapter.newLocal(Types.ARRAY); adapter.newInstance(ARRAY_IMPL); adapter.dup(); adapter.invokeConstructor(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(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(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 railo.transformer.bytecode.statement.FlowControl#getBreakLabel() */ public Label getBreakLabel() { return ns.getBreakLabel(); } /** * * @see railo.transformer.bytecode.statement.FlowControl#getContinueLabel() */ public Label getContinueLabel() { return ns.getContinueLabel(); } /** * @see railo.transformer.bytecode.statement.HasBodies#getBodies() */ 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; } }