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