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