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.commons.GeneratorAdapter;
import railo.transformer.bytecode.Body;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.Position;
import railo.transformer.bytecode.Statement;
import railo.transformer.bytecode.util.ExpressionUtil;
public final class NativeSwitch extends StatementBaseNoFinal implements FlowControlBreak,FlowControlContinue,HasBodies {
public static final short LOCAL_REF=0;
public static final short ARG_REF=1;
public static final short PRIMITIVE=1;
private int value;
private Label end;
private Statement defaultCase;
List<Case> cases=new ArrayList<Case>();
private Label[] labels=new Label[0];
private int[] values=new int[0];
private short type;
public NativeSwitch(int value, short type, Position start, Position end) {
super(start, end);
this.value=value;
this.type=type;
}
public void _writeOut(BytecodeContext bc) throws BytecodeException {
end = new Label();
GeneratorAdapter adapter = bc.getAdapter();
if(type==LOCAL_REF) adapter.loadLocal(value);
else if(type==ARG_REF) adapter.loadArg(value);
else adapter.push(value);
Label beforeDefault = new Label();
adapter.visitLookupSwitchInsn(beforeDefault, values, labels);
Iterator<Case> it = cases.iterator();
Case c;
while(it.hasNext()) {
c= it.next();
adapter.visitLabel(c.label);
ExpressionUtil.visitLine(bc, c.startPos);
c.body.writeOut(bc);
ExpressionUtil.visitLine(bc, c.endPos);
if(c.doBreak){
adapter.goTo(end);
}
}
adapter.visitLabel(beforeDefault);
if(defaultCase!=null)defaultCase.writeOut(bc);
adapter.visitLabel(end);
}
public void addCase(int value, Statement body,Position start,Position end,boolean doBreak) {
Case nc = new Case(value,body,start,end,doBreak);
Label[] labelsTmp = new Label[cases.size()+1];
int[] valuesTmp = new int[cases.size()+1];
int count=0;
boolean hasAdd=false;
for(int i=0;i<labels.length;i++) {
if(!hasAdd && nc.value<values[i]) {
labelsTmp[count]=nc.label;
valuesTmp[count]=nc.value;
count++;
hasAdd=true;
}
labelsTmp[count]=labels[i];
valuesTmp[count]=values[i];
count++;
}
if(!hasAdd) {
labelsTmp[labels.length]=nc.label;
valuesTmp[values.length]=nc.value;
}
labels=labelsTmp;
values=valuesTmp;
cases.add(nc);
}
public void addDefaultCase(Statement defaultStatement) {
this.defaultCase=defaultStatement;
}
class Case {
public boolean doBreak;
private int value;
private Statement body;
private Label label=new Label();
private Position startPos;
private Position endPos;
public Case(int value, Statement body,Position startline,Position endline, boolean doBreak) {
this.value=value;
this.body=body;
this.startPos=startline;
this.endPos=endline;
this.doBreak=doBreak;
}
}
/**
*
* @see railo.transformer.bytecode.statement.FlowControl#getBreakLabel()
*/
public Label getBreakLabel() {
return end;
}
/**
*
* @see railo.transformer.bytecode.statement.FlowControl#getContinueLabel()
*/
public Label getContinueLabel() {
return end;
}
/**
* @see railo.transformer.bytecode.statement.HasBodies#getBodies()
*/
public Body[] getBodies() {
if(cases==null) {
if(defaultCase!=null) return new Body[]{(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++]=(Body) c.body;
}
if(defaultCase!=null)bodies[count++]=(Body) defaultCase;
return bodies;
}
@Override
public String getLabel() {
return null;
}
}