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