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.cfml.evaluator.impl; 020 021 022import java.util.Iterator; 023import java.util.List; 024import java.util.Map; 025 026import lucee.commons.lang.StringUtil; 027import lucee.runtime.PageSource; 028import lucee.runtime.functions.system.CFFunction; 029import lucee.runtime.listener.AppListenerUtil; 030import lucee.transformer.bytecode.Body; 031import lucee.transformer.bytecode.BytecodeException; 032import lucee.transformer.bytecode.Literal; 033import lucee.transformer.bytecode.Page; 034import lucee.transformer.bytecode.Statement; 035import lucee.transformer.bytecode.cast.CastBoolean; 036import lucee.transformer.bytecode.cast.CastString; 037import lucee.transformer.bytecode.expression.ExprString; 038import lucee.transformer.bytecode.expression.Expression; 039import lucee.transformer.bytecode.literal.LitBoolean; 040import lucee.transformer.bytecode.literal.LitString; 041import lucee.transformer.bytecode.statement.tag.Attribute; 042import lucee.transformer.bytecode.statement.tag.Tag; 043import lucee.transformer.bytecode.util.ASMUtil; 044import lucee.transformer.cfml.evaluator.EvaluatorException; 045import lucee.transformer.cfml.evaluator.EvaluatorSupport; 046import lucee.transformer.library.function.FunctionLib; 047import lucee.transformer.library.function.FunctionLibFunction; 048import lucee.transformer.library.tag.TagLibTag; 049 050/** 051 * Prueft den Kontext des Tag function. 052 * Das Attribute <code>argument</code> darf nur direkt innerhalb des Tag <code>function</code> liegen. 053 * Dem Tag <code>argument</code> muss als erstes im tag function vorkommen 054 */ 055public final class Function extends EvaluatorSupport { 056 057 /** 058 * @see lucee.transformer.cfml.evaluator.EvaluatorSupport#evaluate(org.w3c.dom.Element, lucee.transformer.library.tag.TagLibTag) 059 */ 060 public void evaluate(Tag tag, TagLibTag libTag, FunctionLib[] flibs) throws EvaluatorException { 061 //Body p=(Body) tag.getParent(); 062 //Statement pp = p.getParent(); 063 064 boolean isCI=true; 065 try { 066 isCI = ASMUtil.getAncestorPage(tag).isComponent() || ASMUtil.getAncestorPage(tag).isInterface(); 067 } catch (BytecodeException e) {} 068 069 Attribute attrName = tag.getAttribute("name"); 070 if(attrName!=null) { 071 Expression expr = attrName.getValue(); 072 if(expr instanceof LitString && !isCI){ 073 Page p = ASMUtil.getAncestorPage(tag,null); 074 checkFunctionName(((LitString)expr).getString(),flibs,p!=null?p.getPageSource():null); 075 } 076 077 } 078 // attribute modifier 079 Attribute attrModifier = tag.getAttribute("modifier"); 080 if(attrModifier!=null) { 081 ExprString expr = CastString.toExprString(attrModifier.getValue()); 082 if(!(expr instanceof Literal)) 083 throw new EvaluatorException("Attribute modifier of the Tag Function, must be one of the following literal string values: [abstract] or [final]"); 084 String modifier=StringUtil.emptyIfNull(((Literal)expr).getString()).trim(); 085 if(!StringUtil.isEmpty(modifier) && !"abstract".equalsIgnoreCase(modifier) && !"final".equalsIgnoreCase(modifier)) 086 throw new EvaluatorException("Attribute modifier of the Tag Function, must be one of the following literal string values: [abstract] or [final]"); 087 088 089 boolean abstr = "abstract".equalsIgnoreCase(modifier); 090 if(abstr)throwIfNotEmpty(tag); 091 } 092 093 // cachedWithin 094 Attribute attrCachedWithin = tag.getAttribute("cachedwithin"); 095 if(attrCachedWithin!=null) { 096 Expression val = attrCachedWithin.getValue(); 097 tag.addAttribute(new Attribute( 098 attrCachedWithin.isDynamicType(), 099 attrCachedWithin.getName(), 100 ASMUtil.cachedWithinValue(val), 101 attrCachedWithin.getType())); 102 } 103 104 // Attribute localMode 105 Attribute attrLocalMode = tag.getAttribute("localmode"); 106 if(attrLocalMode!=null) { 107 Expression expr = attrLocalMode.getValue(); 108 String str = ASMUtil.toString(expr,null); 109 if(!StringUtil.isEmpty(str) && AppListenerUtil.toLocalMode(str, -1)==-1) 110 throw new EvaluatorException("Attribute localMode of the Tag Function, must be a literal value (modern, classic, true or false)"); 111 //boolean output = ((LitBoolean)expr).getBooleanValue(); 112 //if(!output) ASMUtil.removeLiterlChildren(tag, true); 113 } 114 115 116 // Attribute Output 117 // "output=true" wird in "lucee.transformer.cfml.attributes.impl.Function" gehaendelt 118 Attribute attrOutput = tag.getAttribute("output"); 119 if(attrOutput!=null) { 120 Expression expr = CastBoolean.toExprBoolean(attrOutput.getValue()); 121 if(!(expr instanceof LitBoolean)) 122 throw new EvaluatorException("Attribute output of the Tag Function, must be a literal boolean value (true or false, yes or no)"); 123 //boolean output = ((LitBoolean)expr).getBooleanValue(); 124 //if(!output) ASMUtil.removeLiterlChildren(tag, true); 125 } 126 127 Attribute attrBufferOutput = tag.getAttribute("bufferoutput"); 128 if(attrBufferOutput!=null) { 129 Expression expr = CastBoolean.toExprBoolean(attrBufferOutput.getValue()); 130 if(!(expr instanceof LitBoolean)) 131 throw new EvaluatorException("Attribute bufferOutput of the Tag Function, must be a literal boolean value (true or false, yes or no)"); 132 //boolean output = ((LitBoolean)expr).getBooleanValue(); 133 //if(!output) ASMUtil.removeLiterlChildren(tag, true); 134 } 135 136 137 //if(ASMUtil.isRoot(pp)) { 138 Map attrs = tag.getAttributes(); 139 Iterator it = attrs.keySet().iterator(); 140 Attribute attr; 141 while(it.hasNext()) { 142 attr=(Attribute) attrs.get(it.next()); 143 checkAttributeValue(tag,attr); 144 } 145 //} 146 147 } 148 149 private static void checkFunctionName(String name, FunctionLib[] flibs,PageSource ps) throws EvaluatorException { 150 FunctionLibFunction flf; 151 for (int i = 0; i < flibs.length; i++) { 152 flf = flibs[i].getFunction(name); 153 if(flf!=null && flf.getClazz(null)!=CFFunction.class) { 154 155 String path=null; 156 if(ps!=null) { 157 path = ps.getDisplayPath(); 158 path=path.replace('\\', '/'); 159 } 160 if(path==null || path.indexOf("/library/function/")==-1)// TODO make better 161 throw new EvaluatorException("The name ["+name+"] is already used by a built in Function"); 162 } 163 } 164 } 165 166 public static void throwIfNotEmpty(Tag tag) throws EvaluatorException { 167 Body body = tag.getBody(); 168 List<Statement> statments = body.getStatements(); 169 Statement stat; 170 Iterator<Statement> it = statments.iterator(); 171 TagLibTag tlt; 172 173 while(it.hasNext()) { 174 stat=it.next(); 175 if(stat instanceof Tag) { 176 tlt = ((Tag)stat).getTagLibTag(); 177 if(!tlt.getTagClassName().equals("lucee.runtime.tag.Argument")) 178 throw new EvaluatorException("tag "+tlt.getFullName()+" is not allowed inside a function declaration"); 179 } 180 /*else if(stat instanceof PrintOut) { 181 //body.remove(stat); 182 }*/ 183 } 184 } 185 186 private void checkAttributeValue(Tag tag, Attribute attr) throws EvaluatorException { 187 if(!(attr.getValue() instanceof Literal)) 188 throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] must be a literal/constant value"); 189 190 } 191}