/** * Copyright (c) 2014, the Railo Company Ltd. * Copyright (c) 2015, Lucee Assosication Switzerland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ package lucee.transformer.bytecode.statement.tag; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import lucee.commons.lang.StringUtil; import lucee.commons.lang.types.RefBoolean; import lucee.commons.lang.types.RefBooleanImpl; import lucee.runtime.Component; import lucee.runtime.type.util.ComponentUtil; import lucee.transformer.Factory; import lucee.transformer.Position; import lucee.transformer.TransformerException; import lucee.transformer.bytecode.Body; import lucee.transformer.bytecode.BodyBase; import lucee.transformer.bytecode.BytecodeContext; import lucee.transformer.bytecode.Page; import lucee.transformer.bytecode.Statement; import lucee.transformer.bytecode.statement.FlowControlFinal; import lucee.transformer.bytecode.statement.IFunction; import lucee.transformer.bytecode.statement.PrintOut; import lucee.transformer.bytecode.statement.udf.Function; import lucee.transformer.bytecode.statement.udf.FunctionImpl; import lucee.transformer.expression.Expression; import lucee.transformer.expression.literal.LitBoolean; import lucee.transformer.expression.literal.LitString; import lucee.transformer.expression.literal.Literal; public final class TagFunction extends TagBase implements IFunction { @Override public int getType() { return TYPE_UDF; } public TagFunction(Factory f,Position start,Position end) { super(f,start,end); } @Override public void writeOut(BytecodeContext bc, int type) throws TransformerException { //ExpressionUtil.visitLine(bc, getStartLine()); _writeOut(bc,type); //ExpressionUtil.visitLine(bc, getEndLine()); } @Override public void _writeOut(BytecodeContext bc) throws TransformerException { _writeOut(bc,IFunction.PAGE_TYPE_REGULAR); } public void _writeOut(BytecodeContext bc, int type) throws TransformerException { //private static final Expression EMPTY = LitString.toExprString(""); Body functionBody = new BodyBase(bc.getFactory()); RefBoolean isStatic=new RefBooleanImpl(); Function func = createFunction(bc.getPage(),functionBody,isStatic,bc.getOutput()); //ScriptBody sb=new ScriptBody(bc.getFactory()); func.setParent(getParent()); List<Statement> statements = getBody().getStatements(); Statement stat; Tag tag; // suppress WS between cffunction and the last cfargument Tag last=null; if(bc.getSupressWSbeforeArg()){ // check if there is a cfargument at all Iterator<Statement> it = statements.iterator(); while (it.hasNext()) { stat = it.next(); if (stat instanceof Tag) { tag = (Tag) stat; if (tag.getTagLibTag().getTagClassDefinition().isClassNameEqualTo("lucee.runtime.tag.Argument")) { last=tag; } } } // check if there are only literal WS printouts if(last!=null) { it = statements.iterator(); while (it.hasNext()) { stat = it.next(); if(stat==last) break; if(stat instanceof PrintOut){ PrintOut po=(PrintOut) stat; Expression expr = po.getExpr(); if(!(expr instanceof LitString) || !StringUtil.isWhiteSpace(((LitString)expr).getString())) { last=null; break; } } } } } Iterator<Statement> it = statements.iterator(); boolean beforeLastArgument=last!=null; while (it.hasNext()) { stat = it.next(); if(beforeLastArgument) { if(stat==last) { beforeLastArgument=false; } else if(stat instanceof PrintOut){ PrintOut po=(PrintOut) stat; Expression expr = po.getExpr(); if(expr instanceof LitString) { LitString ls=(LitString) expr; if(StringUtil.isWhiteSpace(ls.getString())) continue; } } } if (stat instanceof Tag) { tag = (Tag) stat; if (tag.getTagLibTag().getTagClassDefinition().isClassNameEqualTo("lucee.runtime.tag.Argument")) { addArgument(func, tag); continue; } } functionBody.addStatement(stat); } func._writeOut(bc,type); } private void addArgument(Function func, Tag tag) { Attribute attr; // name Expression name = tag.removeAttribute("name").getValue(); // type attr = tag.removeAttribute("type"); Expression type = (attr == null) ? tag.getFactory().createLitString("any") : attr.getValue(); // required attr = tag.removeAttribute("required"); Expression required = (attr == null) ? tag.getFactory().FALSE() : attr .getValue(); // default attr = tag.removeAttribute("default"); Expression defaultValue = (attr == null) ? null : attr.getValue(); // passby attr = tag.removeAttribute("passby"); LitBoolean passByReference = tag.getFactory().TRUE(); if(attr!=null) { // i can cast irt to LitString because he evulator check this before String str = ((LitString)attr.getValue()).getString(); if(str.trim().equalsIgnoreCase("value")) passByReference=tag.getFactory().FALSE(); } // displayname attr = tag.removeAttribute("displayname"); Expression displayName = (attr == null) ? tag.getFactory().EMPTY() : attr.getValue(); // hint attr = tag.removeAttribute("hint"); if (attr == null) attr = tag.removeAttribute("description"); Expression hint; if(attr == null)hint=tag.getFactory().EMPTY(); else hint=attr.getValue(); func.addArgument(name, type, required, defaultValue, passByReference,displayName, hint,tag.getAttributes()); } private Function createFunction(Page page, Body body, RefBoolean isStatic, boolean defaultOutput) throws TransformerException { Attribute attr; LitString ANY = page.getFactory().createLitString("any"); LitString PUBLIC = page.getFactory().createLitString("public"); // name Expression name = removeAttribute("name").getValue(); /*if(name instanceof LitString) { ((LitString)name).upperCase(); }*/ // return attr = removeAttribute("returntype"); // if(attr==null) attr = getAttribute("return"); // if(attr==null) attr = getAttribute("type"); Expression returnType = (attr == null) ? ANY : attr.getValue(); // output attr = removeAttribute("output"); Expression output = (attr == null) ? (defaultOutput?page.getFactory().TRUE():page.getFactory().TRUE()) : attr.getValue(); // bufferOutput attr = removeAttribute("bufferoutput"); Expression bufferOutput = (attr == null) ? null : attr.getValue(); // modifier isStatic.setValue(false); int modifier=Component.MODIFIER_NONE; attr = removeAttribute("modifier"); if(attr!=null) { Expression val = attr.getValue(); if(val instanceof Literal) { Literal l=(Literal) val; String str = StringUtil.emptyIfNull(l.getString()).trim(); if("abstract".equalsIgnoreCase(str))modifier=Component.MODIFIER_ABSTRACT; else if("final".equalsIgnoreCase(str))modifier=Component.MODIFIER_FINAL; else if("static".equalsIgnoreCase(str)) isStatic.setValue(true); } } // access attr = removeAttribute("access"); Expression access = (attr == null) ? PUBLIC : attr.getValue(); // dspLabel attr = removeAttribute("displayname"); Expression displayname = (attr == null) ? page.getFactory().EMPTY() : attr.getValue(); // hint attr = removeAttribute("hint"); Expression hint = (attr == null) ? page.getFactory().EMPTY() : attr.getValue(); // description attr = removeAttribute("description"); Expression description = (attr == null) ? page.getFactory().EMPTY() : attr.getValue(); // returnformat attr = removeAttribute("returnformat"); Expression returnFormat = (attr == null) ? null : attr.getValue(); // secureJson attr = removeAttribute("securejson"); Expression secureJson = (attr == null) ? null : attr.getValue(); // verifyClient attr = removeAttribute("verifyclient"); Expression verifyClient = (attr == null) ? null : attr.getValue(); // localMode attr = removeAttribute("localmode"); Expression localMode = (attr == null) ? null : attr.getValue(); // cachedWithin Literal cachedWithin=null; attr = removeAttribute("cachedwithin"); if(attr!=null) { Expression val = attr.getValue(); if(val instanceof Literal) cachedWithin=((Literal)val); } String strAccess = ((LitString)access).getString(); int acc = ComponentUtil.toIntAccess(strAccess,-1); if(acc==-1) throw new TransformerException("invalid access type ["+strAccess+"], access types are remote, public, package, private",getStart()); Function func = new FunctionImpl(page,name, returnType,returnFormat, output, bufferOutput, acc, displayname,description, hint,secureJson,verifyClient,localMode,cachedWithin,modifier, body, getStart(),getEnd()); // %**% Map attrs = getAttributes(); Iterator it = attrs.entrySet().iterator(); HashMap<String,Attribute> metadatas=new HashMap<String,Attribute>(); while(it.hasNext()){ attr=(Attribute) ((Map.Entry)it.next()).getValue(); metadatas.put(attr.getName(),attr); } func.setMetaData(metadatas); return func; } @Override public FlowControlFinal getFlowControlFinal() { return null; } }