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;
}
}