001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.transformer.bytecode.statement.tag;
020
021import java.util.Iterator;
022import java.util.List;
023
024import lucee.transformer.bytecode.BodyBase;
025import lucee.transformer.bytecode.BytecodeContext;
026import lucee.transformer.bytecode.BytecodeException;
027import lucee.transformer.bytecode.Position;
028import lucee.transformer.bytecode.Statement;
029import lucee.transformer.bytecode.expression.Expression;
030import lucee.transformer.bytecode.util.Types;
031import lucee.transformer.bytecode.visitor.ConditionVisitor;
032import lucee.transformer.bytecode.visitor.DecisionIntVisitor;
033
034import org.objectweb.asm.Type;
035import org.objectweb.asm.commons.GeneratorAdapter;
036import org.objectweb.asm.commons.Method;
037
038public final class TagSwitch extends TagBaseNoFinal {
039
040        // int listFindNoCase(String list, String value, String delimiter)
041        private static final Method LIST_FIND_NO_CASE = new Method(
042                                                                                                                "listFindForSwitch",
043                                                                                                                Types.INT_VALUE,
044                                                                                                                new Type[]{Types.STRING,Types.STRING,Types.STRING});
045
046        /**
047         * Constructor of the class
048         * @param sl
049         * @param el
050         */
051        public TagSwitch(Position start,Position end) {
052                super(start,end);
053        }
054        
055        /**
056         *
057         * @see lucee.transformer.bytecode.statement.tag.TagBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter)
058         */
059        public void _writeOut(BytecodeContext bc) throws BytecodeException {
060                GeneratorAdapter adapter = bc.getAdapter();
061
062                // expression
063                int expression=adapter.newLocal(Types.STRING);
064                getAttribute("expression").getValue().writeOut(bc, Expression.MODE_REF);
065                adapter.storeLocal(expression);
066                
067                
068                List statements = getBody().getStatements();
069                Statement stat;
070                Tag tag;
071
072                ConditionVisitor cv=new ConditionVisitor();
073                cv.visitBefore();
074
075                // cases
076                Iterator it = statements.iterator();
077                Tag def=null;
078                while(it.hasNext()) {
079                        stat=(Statement) it.next();
080                        if(stat instanceof Tag) {
081                                tag=(Tag) stat;
082                                if(tag.getTagLibTag().getTagClassName().equals("lucee.runtime.tag.Case"))       {
083                                        addCase(bc,cv,tag,expression);
084                                        continue;
085                                }
086                                else if(tag.getTagLibTag().getTagClassName().equals("lucee.runtime.tag.Defaultcase"))   {
087                                        if(def!=null)
088                                                throw new BytecodeException("multiple defaultcases are not allowed",getStart());
089                                        def=tag;
090                                        //setDefaultCase(bc,cv,tag);
091                                        //break;
092                                }
093                        }
094                }
095
096                // default
097                if(def!=null)setDefaultCase(bc,cv,def);
098                
099                cv.visitAfter(bc);
100        }
101
102        private void setDefaultCase(BytecodeContext bc, ConditionVisitor cv, Tag tag) throws BytecodeException {
103                cv.visitOtherviseBeforeBody();
104                        BodyBase.writeOut(bc, tag.getBody());
105                        //tag.getBody().writeOut(bc);
106                cv.visitOtherviseAfterBody();
107        }
108
109        private void addCase(BytecodeContext bc, ConditionVisitor cv, Tag tag, int expression) throws BytecodeException {
110                GeneratorAdapter adapter = bc.getAdapter();
111                
112                cv.visitWhenBeforeExpr();
113                        DecisionIntVisitor div=new DecisionIntVisitor();
114                        div.visitBegin();
115                                // List.listFindNoCase(case.value,expression,del);
116                                tag.getAttribute("value").getValue().writeOut(bc,Expression.MODE_REF);
117                                adapter.loadLocal(expression);
118                                Attribute attr = tag.getAttribute("delimiters");
119                                if(attr!=null)attr.getValue().writeOut(bc,Expression.MODE_REF);
120                                else adapter.push(",");
121                                adapter.invokeStatic(Types.LIST_UTIL, LIST_FIND_NO_CASE);
122                        div.visitNEQ();
123                                adapter.push(-1);
124                        div.visitEnd(bc);
125                cv.visitWhenAfterExprBeforeBody(bc);
126                        BodyBase.writeOut(bc, tag.getBody());
127                        //tag.getBody().writeOut(bc);
128                cv.visitWhenAfterBody(bc);
129                
130                
131                
132                /*if(List.listFindNoCase(case.value,expression,delimiters)!=-1) {
133                <xsl:apply-templates select="./body/*"/>
134                }*/
135        }
136
137}