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.Type;
008    import org.objectweb.asm.commons.GeneratorAdapter;
009    import org.objectweb.asm.commons.Method;
010    
011    import railo.transformer.bytecode.Body;
012    import railo.transformer.bytecode.BytecodeContext;
013    import railo.transformer.bytecode.BytecodeException;
014    import railo.transformer.bytecode.expression.Expression;
015    import railo.transformer.bytecode.util.Types;
016    
017    public final class Switch extends StatementBase implements FlowControl,HasBodies {
018        
019            private static final Type ARRAY_IMPL=Type.getType(railo.runtime.type.ArrayImpl.class);
020    
021            // Object append(Object o)
022            private static final Method APPEND = new Method(
023                                                                                            "append",
024                                                                                            Types.OBJECT,
025                                                                                            new Type[]{Types.OBJECT}
026            );
027    
028            private static final Method INIT = new Method(
029                            "<init>",
030                            Types.VOID,
031                            new Type[]{}
032                    );
033    
034            // int find(Array array, Object object)
035            private static final Method FIND = new Method(
036                            "find",
037                            Types.INT_VALUE,
038                            new Type[]{Types.ARRAY,Types.OBJECT}
039                    );      
040            
041            private ArrayList cases=new ArrayList();
042        private Body defaultCase;
043            private Expression expr;
044    
045            private NativeSwitch ns;
046    
047    
048        public Switch(Expression expr,int startline,int endline) {
049                    super(startline, endline);
050                    this.expr=expr;
051            }
052        
053        public void addCase(Expression expr, Body body) {
054            addCase(expr, body, -1, -1);
055        }
056        public void addCase(Expression expr, Body body,int startline,int endline) {
057            //if(cases==null) cases=new ArrayList();
058            cases.add(new Case(expr,body,startline,endline));
059            body.setParent(this);
060        }
061        public void setDefaultCase(Body body) {
062            defaultCase=body;
063            body.setParent(this);
064        }
065    
066        
067        public final class Case {
068            private Expression expression;
069            private Body body;
070                    private int startline;
071                    private int endline;
072    
073            public Case(Expression expression, Body body,int startline,int endline) {
074                this.expression=expression;
075                this.body=body;
076                this.startline=startline;
077                this.endline=endline;
078            }
079        }
080    
081            /**
082             * @see railo.transformer.bytecode.statement.StatementBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter)
083             */
084            public void _writeOut(BytecodeContext bc) throws BytecodeException {
085                    GeneratorAdapter adapter = bc.getAdapter();
086                    
087            // Array cases=new ArrayImpl();
088                    int array=adapter.newLocal(Types.ARRAY);
089                    adapter.newInstance(ARRAY_IMPL);
090                    adapter.dup();
091                    adapter.invokeConstructor(ARRAY_IMPL, INIT);
092                    
093                    adapter.storeLocal(array);
094                    
095            // cases.append(case.value);
096                    Iterator it = cases.iterator();
097                    Case c;
098                    while(it.hasNext()) {
099                            c=(Case) it.next();
100                            
101    
102                            adapter.loadLocal(array);
103                            c.expression.writeOut(bc, Expression.MODE_REF);
104                            adapter.invokeVirtual(ARRAY_IMPL, APPEND);
105                            adapter.pop();
106                    }
107                    
108                    // int result=ArrayUtil.find(array,expression);
109                    int result=adapter.newLocal(Types.INT_VALUE);
110                    adapter.loadLocal(array);
111                    expr.writeOut(bc, Expression.MODE_REF);
112                    adapter.invokeStatic(Types.ARRAY_UTIL, FIND);
113                    adapter.storeLocal(result);
114                    
115                    // switch(result)
116                    ns=new NativeSwitch(result,NativeSwitch.LOCAL_REF,getStartLine(),getEndLine());
117                    it = cases.iterator();
118                    int count=1;
119                    while(it.hasNext()) {
120                            c=(Case) it.next();
121                            ns.addCase(count++, c.body,c.startline,c.endline,false);
122                    }
123                    if(defaultCase!=null)ns.addDefaultCase(defaultCase);
124                    
125                    ns.writeOut(bc);
126    
127            }
128    
129            /**
130             *
131             * @see railo.transformer.bytecode.statement.FlowControl#getBreakLabel()
132             */
133            public Label getBreakLabel() {
134                    return ns.getBreakLabel();
135            }
136    
137            /**
138             *
139             * @see railo.transformer.bytecode.statement.FlowControl#getContinueLabel()
140             */
141            public Label getContinueLabel() {
142                    return ns.getContinueLabel();
143            }
144    
145    
146            /**
147             * @see railo.transformer.bytecode.statement.HasBodies#getBodies()
148             */
149            public Body[] getBodies() {
150                    if(cases==null) {
151                            if(defaultCase!=null) return new Body[]{defaultCase};
152                            return new Body[]{};
153                    }
154                    
155                    int len=cases.size(),count=0;
156                    if(defaultCase!=null)len++;
157                    Body[] bodies=new Body[len];
158                    Case c;
159                    Iterator it = cases.iterator();
160                    while(it.hasNext()) {
161                            c=(Case) it.next();
162                            bodies[count++]=c.body;
163                    }
164                    if(defaultCase!=null)bodies[count++]=defaultCase;
165                    
166                    return bodies;
167            }
168    
169    }