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.commons.GeneratorAdapter; 009 010 import railo.transformer.bytecode.Body; 011 import railo.transformer.bytecode.BytecodeContext; 012 import railo.transformer.bytecode.BytecodeException; 013 import railo.transformer.bytecode.Position; 014 import railo.transformer.bytecode.Statement; 015 import railo.transformer.bytecode.util.ExpressionUtil; 016 017 public final class NativeSwitch extends StatementBaseNoFinal implements FlowControlBreak,FlowControlContinue,HasBodies { 018 019 public static final short LOCAL_REF=0; 020 public static final short ARG_REF=1; 021 public static final short PRIMITIVE=1; 022 023 024 private int value; 025 private Label end; 026 private Statement defaultCase; 027 List<Case> cases=new ArrayList<Case>(); 028 private Label[] labels=new Label[0]; 029 private int[] values=new int[0]; 030 private short type; 031 032 public NativeSwitch(int value, short type, Position start, Position end) { 033 super(start, end); 034 this.value=value; 035 this.type=type; 036 } 037 038 public void _writeOut(BytecodeContext bc) throws BytecodeException { 039 end = new Label(); 040 GeneratorAdapter adapter = bc.getAdapter(); 041 042 if(type==LOCAL_REF) adapter.loadLocal(value); 043 else if(type==ARG_REF) adapter.loadArg(value); 044 else adapter.push(value); 045 046 Label beforeDefault = new Label(); 047 adapter.visitLookupSwitchInsn(beforeDefault, values, labels); 048 049 Iterator<Case> it = cases.iterator(); 050 Case c; 051 while(it.hasNext()) { 052 c= it.next(); 053 adapter.visitLabel(c.label); 054 ExpressionUtil.visitLine(bc, c.startPos); 055 c.body.writeOut(bc); 056 ExpressionUtil.visitLine(bc, c.endPos); 057 if(c.doBreak){ 058 adapter.goTo(end); 059 } 060 } 061 062 063 adapter.visitLabel(beforeDefault); 064 if(defaultCase!=null)defaultCase.writeOut(bc); 065 adapter.visitLabel(end); 066 067 } 068 069 public void addCase(int value, Statement body,Position start,Position end,boolean doBreak) { 070 071 Case nc = new Case(value,body,start,end,doBreak); 072 073 Label[] labelsTmp = new Label[cases.size()+1]; 074 int[] valuesTmp = new int[cases.size()+1]; 075 076 int count=0; 077 boolean hasAdd=false; 078 for(int i=0;i<labels.length;i++) { 079 if(!hasAdd && nc.value<values[i]) { 080 labelsTmp[count]=nc.label; 081 valuesTmp[count]=nc.value; 082 count++; 083 hasAdd=true; 084 } 085 labelsTmp[count]=labels[i]; 086 valuesTmp[count]=values[i]; 087 count++; 088 } 089 if(!hasAdd) { 090 labelsTmp[labels.length]=nc.label; 091 valuesTmp[values.length]=nc.value; 092 } 093 labels=labelsTmp; 094 values=valuesTmp; 095 096 097 cases.add(nc); 098 } 099 100 public void addDefaultCase(Statement defaultStatement) { 101 this.defaultCase=defaultStatement; 102 } 103 104 class Case { 105 106 public boolean doBreak; 107 private int value; 108 private Statement body; 109 private Label label=new Label(); 110 private Position startPos; 111 private Position endPos; 112 113 public Case(int value, Statement body,Position startline,Position endline, boolean doBreak) { 114 this.value=value; 115 this.body=body; 116 this.startPos=startline; 117 this.endPos=endline; 118 this.doBreak=doBreak; 119 } 120 121 } 122 123 /** 124 * 125 * @see railo.transformer.bytecode.statement.FlowControl#getBreakLabel() 126 */ 127 public Label getBreakLabel() { 128 return end; 129 } 130 131 /** 132 * 133 * @see railo.transformer.bytecode.statement.FlowControl#getContinueLabel() 134 */ 135 public Label getContinueLabel() { 136 return end; 137 } 138 139 /** 140 * @see railo.transformer.bytecode.statement.HasBodies#getBodies() 141 */ 142 public Body[] getBodies() { 143 if(cases==null) { 144 if(defaultCase!=null) return new Body[]{(Body) defaultCase}; 145 return new Body[]{}; 146 } 147 148 int len=cases.size(),count=0; 149 if(defaultCase!=null)len++; 150 Body[] bodies=new Body[len]; 151 Case c; 152 Iterator<Case> it = cases.iterator(); 153 while(it.hasNext()) { 154 c=it.next(); 155 bodies[count++]=(Body) c.body; 156 } 157 if(defaultCase!=null)bodies[count++]=(Body) defaultCase; 158 159 return bodies; 160 } 161 162 @Override 163 public String getLabel() { 164 return null; 165 } 166 }