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    }