001 package railo.transformer.bytecode.statement.tag; 002 003 import java.util.HashMap; 004 import java.util.Iterator; 005 import java.util.List; 006 import java.util.Map; 007 008 import railo.commons.lang.StringUtil; 009 import railo.runtime.type.util.ComponentUtil; 010 import railo.transformer.bytecode.Body; 011 import railo.transformer.bytecode.BodyBase; 012 import railo.transformer.bytecode.BytecodeContext; 013 import railo.transformer.bytecode.BytecodeException; 014 import railo.transformer.bytecode.Literal; 015 import railo.transformer.bytecode.Page; 016 import railo.transformer.bytecode.Position; 017 import railo.transformer.bytecode.Statement; 018 import railo.transformer.bytecode.expression.ExprString; 019 import railo.transformer.bytecode.expression.Expression; 020 import railo.transformer.bytecode.literal.LitBoolean; 021 import railo.transformer.bytecode.literal.LitLong; 022 import railo.transformer.bytecode.literal.LitString; 023 import railo.transformer.bytecode.statement.FlowControlFinal; 024 import railo.transformer.bytecode.statement.IFunction; 025 import railo.transformer.bytecode.statement.PrintOut; 026 import railo.transformer.bytecode.statement.udf.Function; 027 import railo.transformer.bytecode.statement.udf.FunctionImpl; 028 029 public final class TagFunction extends TagBase implements IFunction { 030 031 private static final ExprString ANY = LitString.toExprString("any"); 032 033 private static final Expression PUBLIC = LitString.toExprString("public"); 034 035 private static final Expression EMPTY = LitString.toExprString(""); 036 037 public TagFunction(Position start,Position end) { 038 super(start,end); 039 040 } 041 042 /** 043 * @see railo.transformer.bytecode.statement.IFunction#writeOut(railo.transformer.bytecode.BytecodeContext, int) 044 */ 045 public void writeOut(BytecodeContext bc, int type) throws BytecodeException { 046 //ExpressionUtil.visitLine(bc, getStartLine()); 047 _writeOut(bc,type); 048 //ExpressionUtil.visitLine(bc, getEndLine()); 049 } 050 051 /** 052 * @see railo.transformer.bytecode.statement.tag.TagBase#_writeOut(railo.transformer.bytecode.BytecodeContext) 053 */ 054 public void _writeOut(BytecodeContext bc) throws BytecodeException { 055 _writeOut(bc,Function.PAGE_TYPE_REGULAR); 056 } 057 058 public void _writeOut(BytecodeContext bc, int type) throws BytecodeException { 059 Body functionBody = new BodyBase(); 060 Function func = createFunction(bc.getPage(),functionBody); 061 func.setParent(getParent()); 062 063 List<Statement> statements = getBody().getStatements(); 064 Statement stat; 065 Tag tag; 066 067 // supress WS between cffunction and the last cfargument 068 Tag last=null; 069 if(bc.getSupressWSbeforeArg()){ 070 // check if there is a cfargument at all 071 Iterator<Statement> it = statements.iterator(); 072 while (it.hasNext()) { 073 stat = it.next(); 074 if (stat instanceof Tag) { 075 tag = (Tag) stat; 076 if (tag.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Argument")) { 077 last=tag; 078 } 079 } 080 } 081 082 // check if there are only literal WS printouts 083 if(last!=null) { 084 it = statements.iterator(); 085 while (it.hasNext()) { 086 stat = it.next(); 087 if(stat==last) break; 088 089 if(stat instanceof PrintOut){ 090 PrintOut po=(PrintOut) stat; 091 Expression expr = po.getExpr(); 092 if(!(expr instanceof LitString) || !StringUtil.isWhiteSpace(((LitString)expr).getString())) { 093 last=null; 094 break; 095 } 096 } 097 } 098 } 099 } 100 101 102 103 Iterator<Statement> it = statements.iterator(); 104 boolean beforeLastArgument=last!=null; 105 while (it.hasNext()) { 106 stat = it.next(); 107 if(beforeLastArgument) { 108 if(stat==last) { 109 beforeLastArgument=false; 110 } 111 else if(stat instanceof PrintOut){ 112 PrintOut po=(PrintOut) stat; 113 Expression expr = po.getExpr(); 114 if(expr instanceof LitString) { 115 LitString ls=(LitString) expr; 116 if(StringUtil.isWhiteSpace(ls.getString())) continue; 117 } 118 } 119 120 } 121 if (stat instanceof Tag) { 122 tag = (Tag) stat; 123 if (tag.getTagLibTag().getTagClassName().equals( 124 "railo.runtime.tag.Argument")) { 125 addArgument(func, tag); 126 continue; 127 } 128 } 129 functionBody.addStatement(stat); 130 } 131 func._writeOut(bc,type); 132 133 } 134 135 private void addArgument(Function func, Tag tag) { 136 Attribute attr; 137 // name 138 Expression name = tag.removeAttribute("name").getValue(); 139 140 // type 141 attr = tag.removeAttribute("type"); 142 Expression type = (attr == null) ? ANY : attr.getValue(); 143 144 // required 145 attr = tag.removeAttribute("required"); 146 Expression required = (attr == null) ? LitBoolean.FALSE : attr 147 .getValue(); 148 149 // default 150 attr = tag.removeAttribute("default"); 151 Expression defaultValue = (attr == null) ? null : attr.getValue(); 152 153 // passby 154 attr = tag.removeAttribute("passby"); 155 LitBoolean passByReference = LitBoolean.TRUE; 156 if(attr!=null) { 157 // i can cast irt to LitString because he evulator check this before 158 String str = ((LitString)attr.getValue()).getString(); 159 if(str.trim().equalsIgnoreCase("value")) 160 passByReference=LitBoolean.FALSE; 161 } 162 163 164 // displayname 165 attr = tag.removeAttribute("displayname"); 166 Expression displayName = (attr == null) ? EMPTY : attr.getValue(); 167 168 // hint 169 attr = tag.removeAttribute("hint"); 170 if (attr == null) 171 attr = tag.removeAttribute("description"); 172 173 Expression hint; 174 if(attr == null)hint=EMPTY; 175 else hint=attr.getValue(); 176 177 func.addArgument(name, type, required, defaultValue, passByReference,displayName, hint,tag.getAttributes()); 178 179 } 180 181 private Function createFunction(Page page, Body body) throws BytecodeException { 182 Attribute attr; 183 184 // name 185 Expression name = removeAttribute("name").getValue(); 186 /*if(name instanceof LitString) { 187 ((LitString)name).upperCase(); 188 }*/ 189 // return 190 attr = removeAttribute("returntype"); 191 // if(attr==null) attr = getAttribute("return"); 192 // if(attr==null) attr = getAttribute("type"); 193 Expression returnType = (attr == null) ? ANY : attr.getValue(); 194 195 // output 196 attr = removeAttribute("output"); 197 Expression output = (attr == null) ? LitBoolean.TRUE : attr.getValue(); 198 199 // bufferOutput 200 attr = removeAttribute("bufferoutput"); 201 Expression bufferOutput = (attr == null) ? null : attr.getValue(); 202 203 // modifier 204 boolean _abstract=false,_final=false; 205 attr = removeAttribute("modifier"); 206 if(attr!=null) { 207 Expression val = attr.getValue(); 208 if(val instanceof Literal) { 209 Literal l=(Literal) val; 210 String str = StringUtil.emptyIfNull(l.getString()).trim(); 211 if("abstract".equalsIgnoreCase(str))_abstract=true; 212 else if("final".equalsIgnoreCase(str))_final=true; 213 } 214 } 215 216 // access 217 attr = removeAttribute("access"); 218 Expression access = (attr == null) ? PUBLIC : attr.getValue(); 219 220 // dspLabel 221 attr = removeAttribute("displayname"); 222 Expression displayname = (attr == null) ? EMPTY : attr.getValue(); 223 224 // hint 225 attr = removeAttribute("hint"); 226 Expression hint = (attr == null) ? EMPTY : attr.getValue(); 227 228 // description 229 attr = removeAttribute("description"); 230 Expression description = (attr == null) ? EMPTY : attr.getValue(); 231 232 // returnformat 233 attr = removeAttribute("returnformat"); 234 Expression returnFormat = (attr == null) ? null : attr.getValue(); 235 236 // secureJson 237 attr = removeAttribute("securejson"); 238 Expression secureJson = (attr == null) ? null : attr.getValue(); 239 240 // verifyClient 241 attr = removeAttribute("verifyclient"); 242 Expression verifyClient = (attr == null) ? null : attr.getValue(); 243 244 // localMode 245 attr = removeAttribute("localmode"); 246 Expression localMode = (attr == null) ? null : attr.getValue(); 247 248 249 250 // cachedWithin 251 long cachedWithin=0; 252 attr = removeAttribute("cachedwithin"); 253 if(attr!=null) { 254 Expression val = attr.getValue(); 255 if(val instanceof LitLong) 256 cachedWithin=((LitLong)val).getLongValue(); 257 } 258 259 String strAccess = ((LitString)access).getString(); 260 int acc = ComponentUtil.toIntAccess(strAccess,-1); 261 if(acc==-1) 262 throw new BytecodeException("invalid access type ["+strAccess+"], access types are remote, public, package, private",getStart()); 263 264 Function func = new FunctionImpl(page,name, returnType,returnFormat, output, bufferOutput, acc, displayname,description, 265 hint,secureJson,verifyClient,localMode,cachedWithin,_abstract,_final, body, getStart(),getEnd()); 266 267 268 269 270 // %**% 271 Map attrs = getAttributes(); 272 Iterator it = attrs.entrySet().iterator(); 273 HashMap<String,Attribute> metadatas=new HashMap<String,Attribute>(); 274 while(it.hasNext()){ 275 attr=(Attribute) ((Map.Entry)it.next()).getValue(); 276 metadatas.put(attr.getName(),attr); 277 } 278 func.setMetaData(metadatas); 279 return func; 280 } 281 282 @Override 283 public FlowControlFinal getFlowControlFinal() { 284 return null; 285 } 286 287 }