001 package railo.transformer.bytecode.statement; 002 003 import java.util.ArrayList; 004 import java.util.Iterator; 005 import java.util.List; 006 007 import org.objectweb.asm.Label; 008 import org.objectweb.asm.Type; 009 import org.objectweb.asm.commons.GeneratorAdapter; 010 import org.objectweb.asm.commons.Method; 011 012 import railo.transformer.bytecode.Body; 013 import railo.transformer.bytecode.BytecodeContext; 014 import railo.transformer.bytecode.BytecodeException; 015 import railo.transformer.bytecode.Position; 016 import railo.transformer.bytecode.expression.Expression; 017 import railo.transformer.bytecode.util.Types; 018 019 public final class Switch extends StatementBaseNoFinal implements FlowControlBreak,HasBodies { 020 021 private static final Type ARRAY_IMPL=Type.getType(railo.runtime.type.ArrayImpl.class); 022 023 // Object append(Object o) 024 private static final Method APPEND = new Method( 025 "append", 026 Types.OBJECT, 027 new Type[]{Types.OBJECT} 028 ); 029 030 private static final Method INIT = new Method( 031 "<init>", 032 Types.VOID, 033 new Type[]{} 034 ); 035 036 // int find(Array array, Object object) 037 private static final Method FIND = new Method( 038 "find", 039 Types.INT_VALUE, 040 new Type[]{Types.ARRAY,Types.OBJECT} 041 ); 042 043 private List<Case> cases=new ArrayList<Case>(); 044 private Body defaultCase; 045 private Expression expr; 046 047 private NativeSwitch ns; 048 049 050 public Switch(Expression expr,Position start, Position end) { 051 super(start, end); 052 this.expr=expr; 053 } 054 055 public void addCase(Expression expr, Body body) { 056 addCase(expr, body, null, null); 057 } 058 public void addCase(Expression expr, Body body,Position start,Position end) { 059 //if(cases==null) cases=new ArrayList(); 060 cases.add(new Case(expr,body,start,end)); 061 body.setParent(this); 062 } 063 public void setDefaultCase(Body body) { 064 defaultCase=body; 065 body.setParent(this); 066 } 067 068 069 public final class Case { 070 private Expression expression; 071 private Body body; 072 private Position startPos; 073 private Position endPos; 074 075 public Case(Expression expression, Body body,Position start,Position end) { 076 this.expression=expression; 077 this.body=body; 078 this.startPos=start; 079 this.endPos=end; 080 } 081 } 082 083 /** 084 * @see railo.transformer.bytecode.statement.StatementBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter) 085 */ 086 public void _writeOut(BytecodeContext bc) throws BytecodeException { 087 GeneratorAdapter adapter = bc.getAdapter(); 088 089 // Array cases=new ArrayImpl(); 090 int array=adapter.newLocal(Types.ARRAY); 091 adapter.newInstance(ARRAY_IMPL); 092 adapter.dup(); 093 adapter.invokeConstructor(ARRAY_IMPL, INIT); 094 095 adapter.storeLocal(array); 096 097 // cases.append(case.value); 098 Iterator<Case> it = cases.iterator(); 099 Case c; 100 while(it.hasNext()) { 101 c=it.next(); 102 103 104 adapter.loadLocal(array); 105 c.expression.writeOut(bc, Expression.MODE_REF); 106 adapter.invokeVirtual(ARRAY_IMPL, APPEND); 107 adapter.pop(); 108 } 109 110 // int result=ArrayUtil.find(array,expression); 111 int result=adapter.newLocal(Types.INT_VALUE); 112 adapter.loadLocal(array); 113 expr.writeOut(bc, Expression.MODE_REF); 114 adapter.invokeStatic(Types.ARRAY_UTIL, FIND); 115 adapter.storeLocal(result); 116 117 // switch(result) 118 ns=new NativeSwitch(result,NativeSwitch.LOCAL_REF,getStart(),getEnd()); 119 it = cases.iterator(); 120 int count=1; 121 while(it.hasNext()) { 122 c=it.next(); 123 ns.addCase(count++, c.body,c.startPos,c.endPos,false); 124 } 125 if(defaultCase!=null)ns.addDefaultCase(defaultCase); 126 127 ns.writeOut(bc); 128 129 } 130 131 /** 132 * 133 * @see railo.transformer.bytecode.statement.FlowControl#getBreakLabel() 134 */ 135 public Label getBreakLabel() { 136 return ns.getBreakLabel(); 137 } 138 139 /** 140 * 141 * @see railo.transformer.bytecode.statement.FlowControl#getContinueLabel() 142 */ 143 public Label getContinueLabel() { 144 return ns.getContinueLabel(); 145 } 146 147 148 /** 149 * @see railo.transformer.bytecode.statement.HasBodies#getBodies() 150 */ 151 public Body[] getBodies() { 152 if(cases==null) { 153 if(defaultCase!=null) return new Body[]{defaultCase}; 154 return new Body[]{}; 155 } 156 157 int len=cases.size(),count=0; 158 if(defaultCase!=null)len++; 159 Body[] bodies=new Body[len]; 160 Case c; 161 Iterator<Case> it = cases.iterator(); 162 while(it.hasNext()) { 163 c=it.next(); 164 bodies[count++]=c.body; 165 } 166 if(defaultCase!=null)bodies[count++]=defaultCase; 167 168 return bodies; 169 } 170 171 @Override 172 public String getLabel() { 173 return null; 174 } 175 176 }