package railo.transformer.cfml.script; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import railo.commons.lang.StringUtil; import railo.commons.lang.types.RefBoolean; import railo.commons.lang.types.RefBooleanImpl; import railo.runtime.Component; import railo.runtime.exp.TemplateException; import railo.runtime.functions.system.CFFunction; import railo.runtime.type.util.ArrayUtil; import railo.runtime.type.util.ComponentUtil; import railo.transformer.bytecode.Body; import railo.transformer.bytecode.BodyBase; import railo.transformer.bytecode.BytecodeException; import railo.transformer.bytecode.FunctionBody; import railo.transformer.bytecode.Position; import railo.transformer.bytecode.ScriptBody; import railo.transformer.bytecode.Statement; import railo.transformer.bytecode.cast.CastBoolean; import railo.transformer.bytecode.cast.CastOther; import railo.transformer.bytecode.cast.CastString; import railo.transformer.bytecode.expression.ClosureAsExpression; import railo.transformer.bytecode.expression.ExprBoolean; import railo.transformer.bytecode.expression.Expression; import railo.transformer.bytecode.expression.var.Variable; import railo.transformer.bytecode.literal.LitBoolean; import railo.transformer.bytecode.literal.LitString; import railo.transformer.bytecode.statement.Condition; import railo.transformer.bytecode.statement.Condition.Pair; import railo.transformer.bytecode.statement.DoWhile; import railo.transformer.bytecode.statement.ExpressionAsStatement; import railo.transformer.bytecode.statement.For; import railo.transformer.bytecode.statement.ForEach; import railo.transformer.bytecode.statement.Return; import railo.transformer.bytecode.statement.Switch; import railo.transformer.bytecode.statement.TryCatchFinally; import railo.transformer.bytecode.statement.While; import railo.transformer.bytecode.statement.tag.Attribute; import railo.transformer.bytecode.statement.tag.Tag; import railo.transformer.bytecode.statement.tag.TagOther; import railo.transformer.bytecode.statement.tag.TagParam; import railo.transformer.bytecode.statement.udf.Closure; import railo.transformer.bytecode.statement.udf.Function; import railo.transformer.bytecode.statement.udf.FunctionImpl; import railo.transformer.cfml.evaluator.EvaluatorException; import railo.transformer.cfml.evaluator.impl.ProcessingDirectiveException; import railo.transformer.cfml.expression.AbstrCFMLExprTransformer; import railo.transformer.cfml.tag.CFMLTransformer; import railo.transformer.library.function.FunctionLibFunction; import railo.transformer.library.tag.TagLibException; import railo.transformer.library.tag.TagLibTag; import railo.transformer.library.tag.TagLibTagAttr; import railo.transformer.library.tag.TagLibTagScript; import railo.transformer.util.CFMLString; /** * Innerhalb des Tag script kann in CFML eine eigene Scriptsprache verwendet werden, * welche sich an Javascript orientiert. * Da der data.cfml Transformer keine Spezialfaelle zulaesst, * also Tags einfach anhand der eingegeben TLD einliest und transformiert, * aus diesem Grund wird der Inhalt des Tag script einfach als Zeichenkette eingelesen. * Erst durch den Evaluator (siehe 3.3), der fuer das Tag script definiert ist, * wird der Inhalt des Tag script uebersetzt. * */ public abstract class AbstrCFMLScriptTransformer extends AbstrCFMLExprTransformer { private static final String[] IGNORE_LIST_COMPONENT = new String[]{ "output","synchronized","extends","implements","displayname","style","persistent","accessors"}; private static final String[] IGNORE_LIST_INTERFACE = new String[]{ "output","extends","displayname","style","persistent","accessors"}; private static final String[] IGNORE_LIST_PROPERTY = new String[]{ "default","fieldtype","name","type","persistent","remotingFetch","column","generator","length", "ormtype","params","unSavedValue","dbdefault","formula","generated","insert","optimisticlock", "update","notnull","precision","scale","unique","uniquekey","source" }; private static EndCondition SEMI_BLOCK=new EndCondition() { public boolean isEnd(ExprData data) { return data.cfml.isCurrent('{') || data.cfml.isCurrent(';'); } }; private static EndCondition SEMI=new EndCondition() { public boolean isEnd(ExprData data) { return data.cfml.isCurrent(';'); } }; private static EndCondition COMMA_ENDBRACKED=new EndCondition() { public boolean isEnd(ExprData data) { return data.cfml.isCurrent(',') || data.cfml.isCurrent(')'); } }; private short ATTR_TYPE_NONE=TagLibTagAttr.SCRIPT_SUPPORT_NONE; private short ATTR_TYPE_OPTIONAL=TagLibTagAttr.SCRIPT_SUPPORT_OPTIONAL; private short ATTR_TYPE_REQUIRED=TagLibTagAttr.SCRIPT_SUPPORT_REQUIRED; public static class ComponentTemplateException extends TemplateException { private static final long serialVersionUID = -8103635220891288231L; private TemplateException te; public ComponentTemplateException(TemplateException te){ super(te.getPageSource(),te.getLine(),0,te.getMessage()); this.te=te; } /** * @return the te */ public TemplateException getTemplateException() { return te; } } private static final Expression NULL = LitString.toExprString("NULL"); private static final Attribute ANY = new Attribute(false,"type",LitString.toExprString("any"),"string"); /** * Liest saemtliche Statements des CFScriptString ein. * <br /> * EBNF:<br /> * <code>{statement spaces};</code> * @return a statement * @throws TemplateException */ protected final Body statements(ExprData data) throws TemplateException { ScriptBody body=new ScriptBody(); statements(data,body,true); return body; } /** * Liest saemtliche Statements des CFScriptString ein. * <br /> * EBNF:<br /> * <code>{statement spaces};</code> * @param parent �bergeornetes Element dem das Statement zugewiesen wird. * @param isRoot befindet sich der Parser im root des data.cfml Docs * @throws TemplateException */ private final void statements(ExprData data,Body body, boolean isRoot) throws TemplateException { do { if(isRoot && isFinish(data))return; statement(data,body); comments(data); } while(data.cfml.isValidIndex() && !data.cfml.isCurrent('}')); } /** * Liest ein einzelnes Statement ein (if,for,while usw.). * <br /> * EBNF:<br /> * <code>";" | "if" spaces "(" ifStatement | "function " funcStatement | "while" spaces "(" whileStatement | "do" spaces "{" doStatement | "for" spaces "(" forStatement | "return" returnStatement | "break" breakStatement | "continue" continueStatement | "/*" comment | expressionStatement;</code> * @param parent �bergeornetes Element dem das Statement zugewiesen wird. * @throws TemplateException */ private final void statement(ExprData data,Body parent) throws TemplateException { statement(data, parent, data.context); } private boolean statement(ExprData data,Body parent,short context) throws TemplateException { short prior=data.context; data.context=context; comments(data); Statement child=null; if(data.cfml.forwardIfCurrent(';')){return true;} else if((child=ifStatement(data))!=null) parent.addStatement(child); else if((child=propertyStatement(data,parent))!=null) parent.addStatement(child); else if((child=paramStatement(data,parent))!=null) parent.addStatement(child); else if((child=funcStatement(data,parent))!=null) parent.addStatement(child); else if((child=whileStatement(data))!=null) parent.addStatement(child); else if((child=doStatement(data))!=null) parent.addStatement(child); else if((child=forStatement(data))!=null) parent.addStatement(child); else if((child=returnStatement(data))!=null) parent.addStatement(child); else if((child=switchStatement(data))!=null) parent.addStatement(child); else if((child=tryStatement(data))!=null) parent.addStatement(child); else if((child=tagStatement(data,parent))!=null) parent.addStatement(child); else if(block(data,parent)){} else parent.addStatement(expressionStatement(data,parent)); data.docComment=null; data.context=prior; return false; } /** * Liest ein if Statement ein. * <br /> * EBNF:<br /> * <code>spaces condition spaces ")" spaces block {"else if" spaces "(" elseifStatement spaces } [("else" spaces "(" | "else ") elseStatement spaces];</code> * @return if Statement * @throws TemplateException */ private final Statement ifStatement(ExprData data) throws TemplateException { if(!data.cfml.forwardIfCurrent("if",'(')) return null; Position line = data.cfml.getPosition(); Body body=new BodyBase(); Condition cont=new Condition(condition(data),body,line,null); if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"if statement must end with a [)]"); // ex block statement(data,body,CTX_IF); // else if comments(data); while(elseifStatement(data,cont)) { comments(data); } // else if(elseStatement(data,cont)) { comments(data); } cont.setEnd(data.cfml.getPosition()); return cont; } /** * Liest ein else if Statement ein. * <br /> * EBNF:<br /> * <code>spaces condition spaces ")" spaces block;</code> * @return else if Statement * @throws TemplateException */ private final boolean elseifStatement(ExprData data,Condition cont) throws TemplateException { int pos=data.cfml.getPos(); if(!data.cfml.forwardIfCurrent("else")) return false; comments(data); if(!data.cfml.forwardIfCurrent("if",'(')) { data.cfml.setPos(pos); return false; } Position line = data.cfml.getPosition(); Body body=new BodyBase(); Pair pair = cont.addElseIf(condition(data), body, line,null); if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"else if statement must end with a [)]"); // ex block statement(data,body,CTX_ELSE_IF); pair.end=data.cfml.getPosition(); return true; } /** * Liest ein else Statement ein. * <br /> * EBNF:<br /> * <code>block;</code> * @return else Statement * @throws TemplateException * */ private final boolean elseStatement(ExprData data,Condition cont) throws TemplateException { if(!data.cfml.forwardIfCurrent("else",'{') && !data.cfml.forwardIfCurrent("else ") && !data.cfml.forwardIfCurrent("else",'/')) return false; // start ( data.cfml.previous(); // ex block Body body=new BodyBase(); Pair p = cont.setElse(body, data.cfml.getPosition(),null); statement(data,body,CTX_ELSE); p.end=data.cfml.getPosition(); return true; } private final boolean finallyStatement(ExprData data,TryCatchFinally tcf) throws TemplateException { if(!data.cfml.forwardIfCurrent("finally",'{') && !data.cfml.forwardIfCurrent("finally ") && !data.cfml.forwardIfCurrent("finally",'/')) return false; // start ( data.cfml.previous(); // ex block Body body=new BodyBase(); tcf.setFinally(body, data.cfml.getPosition()); statement(data,body,CTX_FINALLY); return true; } /** * Liest ein while Statement ein. * <br /> * EBNF:<br /> * <code>spaces condition spaces ")" spaces block;</code> * @return while Statement * @throws TemplateException */ private final While whileStatement(ExprData data) throws TemplateException { int pos=data.cfml.getPos(); // id String id=variableDec(data, false); if(id==null) { data.cfml.setPos(pos); return null; } if(id.equalsIgnoreCase("while")){ id=null; data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent('(')){ data.cfml.setPos(pos); return null; } } else { data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent(':')){ data.cfml.setPos(pos); return null; } data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent("while",'(')){ data.cfml.setPos(pos); return null; } } Position line = data.cfml.getPosition(); Body body=new BodyBase(); While whil=new While(condition(data),body,line,null,id); if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"while statement must end with a [)]"); statement(data,body,CTX_WHILE); whil.setEnd(data.cfml.getPosition()); return whil; } /** * Liest ein switch Statment ein * @return switch Statement * @throws TemplateException */ private final Switch switchStatement(ExprData data) throws TemplateException { if(!data.cfml.forwardIfCurrent("switch",'(')) return null; Position line = data.cfml.getPosition(); comments(data); Expression expr = super.expression(data); comments(data); // end ) if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"switch statement must end with a [)]"); comments(data); if(!data.cfml.forwardIfCurrent('{')) throw new TemplateException(data.cfml,"switch statement must have a starting [{]"); Switch swit=new Switch(expr,line,null); // cases //Node child=null; comments(data); while(caseStatement(data,swit)) { comments(data); } // default if(defaultStatement(data,swit)) { comments(data); } while(caseStatement(data,swit)) { comments(data); } // } if(!data.cfml.forwardIfCurrent('}')) throw new TemplateException(data.cfml,"invalid construct in switch statement"); swit.setEnd(data.cfml.getPosition()); return swit; } /** * Liest ein Case Statement ein * @return case Statement * @throws TemplateException */ private final boolean caseStatement(ExprData data,Switch swit) throws TemplateException { if(!data.cfml.forwardIfCurrentAndNoWordAfter("case")) return false; //int line=data.cfml.getLine(); comments(data); Expression expr = super.expression(data); comments(data); if(!data.cfml.forwardIfCurrent(':')) throw new TemplateException(data.cfml,"case body must start with [:]"); Body body=new BodyBase(); switchBlock(data,body); swit.addCase(expr, body); return true; } /** * Liest ein default Statement ein * @return default Statement * @throws TemplateException */ private final boolean defaultStatement(ExprData data,Switch swit) throws TemplateException { if(!data.cfml.forwardIfCurrent("default",':')) return false; //int line=data.cfml.getLine(); Body body=new BodyBase(); swit.setDefaultCase(body); switchBlock(data,body); return true; } /** * Liest ein Switch Block ein * @param block * @throws TemplateException */ private final void switchBlock(ExprData data,Body body) throws TemplateException { while(data.cfml.isValidIndex()) { comments(data); if(data.cfml.isCurrent("case ") || data.cfml.isCurrent("default",':') || data.cfml.isCurrent('}')) return; statement(data,body,CTX_SWITCH); } } /** * Liest ein do Statement ein. * <br /> * EBNF:<br /> * <code>block spaces "while" spaces "(" spaces condition spaces ")";</code> * @return do Statement * @throws TemplateException */ private final DoWhile doStatement(ExprData data) throws TemplateException { int pos=data.cfml.getPos(); // id String id=variableDec(data, false); if(id==null) { data.cfml.setPos(pos); return null; } if(id.equalsIgnoreCase("do")){ id=null; if(!data.cfml.isCurrent('{') && !data.cfml.isCurrent(' ') && !data.cfml.isCurrent('/')) { data.cfml.setPos(pos); return null; } } else { data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent(':')){ data.cfml.setPos(pos); return null; } data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent("do",'{') && !data.cfml.forwardIfCurrent("do ") && !data.cfml.forwardIfCurrent("do",'/')) { data.cfml.setPos(pos); return null; } data.cfml.previous(); } //if(!data.cfml.forwardIfCurrent("do",'{') && !data.cfml.forwardIfCurrent("do ") && !data.cfml.forwardIfCurrent("do",'/')) // return null; Position line = data.cfml.getPosition(); Body body=new BodyBase(); //data.cfml.previous(); statement(data,body,CTX_DO_WHILE); comments(data); if(!data.cfml.forwardIfCurrent("while",'(')) throw new TemplateException(data.cfml,"do statement must have a while at the end"); DoWhile doWhile=new DoWhile(condition(data),body,line,data.cfml.getPosition(),id); if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"do statement must end with a [)]"); return doWhile; } /** * Liest ein for Statement ein. * <br /> * EBNF:<br /> * <code>expression spaces ";" spaces condition spaces ";" spaces expression spaces ")" spaces block;</code> * @return for Statement * @throws TemplateException */ private final Statement forStatement(ExprData data) throws TemplateException { int pos=data.cfml.getPos(); // id String id=variableDec(data, false); if(id==null) { data.cfml.setPos(pos); return null; } if(id.equalsIgnoreCase("for")){ id=null; data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent('(')){ data.cfml.setPos(pos); return null; } } else { data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent(':')){ data.cfml.setPos(pos); return null; } data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent("for",'(')){ data.cfml.setPos(pos); return null; } } //if(!data.cfml.forwardIfCurrent("for",'(')) // return null; Expression left=null; Body body=new BodyBase(); Position line = data.cfml.getPosition(); comments(data); if(!data.cfml.isCurrent(';')) { // left left=expression(data); comments(data); } // middle for if(data.cfml.forwardIfCurrent(';')) { Expression cont=null; Expression update=null; // condition comments(data); if(!data.cfml.isCurrent(';')) { cont=condition(data); comments(data); } // middle if(!data.cfml.forwardIfCurrent(';')) throw new TemplateException(data.cfml,"invalid syntax in for statement"); // update comments(data); if(!data.cfml.isCurrent(')')) { update=expression(data); comments(data); } // start ) if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"invalid syntax in for statement, for statement must end with a [)]"); // ex block statement(data,body,CTX_FOR); return new For(left,cont,update,body,line,data.cfml.getPosition(),id); } // middle foreach else if(data.cfml.forwardIfCurrent("in")) { // condition comments(data); Expression value = expression(data); comments(data); if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"invalid syntax in for statement, for statement must end with a [)]"); // ex block statement(data,body,CTX_FOR); if(!(left instanceof Variable)) throw new TemplateException(data.cfml,"invalid syntax in for statement, left value is invalid"); if(!(value instanceof Variable)) throw new TemplateException(data.cfml,"invalid syntax in for statement, right value is invalid"); return new ForEach((Variable)left,(Variable)value,body,line,data.cfml.getPosition(),id); } else throw new TemplateException(data.cfml,"invalid syntax in for statement"); } /** * Liest ein function Statement ein. * <br /> * EBNF:<br /> * <code>identifier spaces "(" spaces identifier spaces {"," spaces identifier spaces} ")" spaces block;</code> * @return function Statement * @throws TemplateException */ private final Function funcStatement(ExprData data,Body parent) throws TemplateException { int pos=data.cfml.getPos(); // access modifier String strAccess=variableDec(data, false); if(strAccess==null) { data.cfml.setPos(pos); return null; } String rtnType=null; if(strAccess.equalsIgnoreCase("FUNCTION")){ strAccess=null; comments(data); // only happens when return type is function if(data.cfml.forwardIfCurrent("function ")){ rtnType="function"; comments(data); } } else{ comments(data); rtnType=variableDec(data, false); if(rtnType==null){ data.cfml.setPos(pos); return null; } if(rtnType.equalsIgnoreCase("FUNCTION")){ comments(data); // only happens when return type is function if(data.cfml.forwardIfCurrent("function ")){ comments(data); } else rtnType=null; } comments(data); if(rtnType!=null && !data.cfml.forwardIfCurrent("function ") && !rtnType.equalsIgnoreCase("FUNCTION")){ data.cfml.setPos(pos); return null; } comments(data); } // check access returntype int access=Component.ACCESS_PUBLIC; if(strAccess!=null && rtnType!=null){ access = ComponentUtil.toIntAccess(strAccess,-1); if(access==-1) throw new TemplateException(data.cfml,"invalid access type ["+strAccess+"], access types are remote, public, package, private"); } if(strAccess!=null && rtnType==null){ access = ComponentUtil.toIntAccess(strAccess,-1); if(access==-1){ rtnType=strAccess; strAccess=null; access=Component.ACCESS_PUBLIC; } } Position line = data.cfml.getPosition(); comments(data); // Name String id=identifier(data,false); if(id==null) { if(data.cfml.isCurrent('(')) { data.cfml.setPos(pos); return null; } throw new TemplateException(data.cfml,"invalid name for a function"); } if(!data.isCFC && !data.isInterface){ FunctionLibFunction flf = getFLF(data,id); if(flf!=null && flf.getClazz()!=CFFunction.class)throw new TemplateException(data.cfml,"The name ["+id+"] is already used by a built in Function"); } return closurePart(data, id,access,rtnType,line,false); } protected final Function closurePart(ExprData data, String id, int access, String rtnType, Position line,boolean closure) throws TemplateException { Body body=new FunctionBody(); Function func=closure? new Closure(data.page,id,access,rtnType,body,line,null) :new FunctionImpl(data.page,id,access,rtnType,body,line,null); comments(data); if(!data.cfml.forwardIfCurrent('(')) throw new TemplateException(data.cfml,"invalid syntax in function head, missing begin [(]"); // arguments LitBoolean passByRef; Expression displayName; Expression hint; Map<String,Attribute> meta; String _name; do { comments(data); // finish if(data.cfml.isCurrent(')'))break; // attribute // name //String idName=identifier(data,false,true); boolean required=false; String idName = variableDec(data, false); // required if("required".equalsIgnoreCase(idName)){ comments(data); String idName2=variableDec(data, false); if(idName2!=null){ idName=idName2; required=true; } } String typeName="any"; if(idName==null) throw new TemplateException(data.cfml,"invalid argument definition"); comments(data); if(!data.cfml.isCurrent(')') && !data.cfml.isCurrent('=') && !data.cfml.isCurrent(':') && !data.cfml.isCurrent(',')) { typeName=idName.toLowerCase(); idName=identifier(data,false); // MUST was upper case before, is this a problem? } else if(idName.indexOf('.')!=-1 || idName.indexOf('[')!=-1) { throw new TemplateException(data.cfml,"invalid argument name ["+idName+"] definition"); } comments(data); Expression defaultValue; if(data.cfml.isCurrent('=') || data.cfml.isCurrent(':')) { data.cfml.next(); comments(data); defaultValue=expression(data); } else defaultValue=null; // assign meta data defined in doc comment passByRef = LitBoolean.TRUE; displayName=LitString.EMPTY; hint=LitString.EMPTY; meta=null; if(data.docComment!=null){ Map<String, Attribute> params = data.docComment.getParams(); Attribute[] attrs = params.values().toArray(new Attribute[params.size()]); Attribute attr; String name; for(int i=0;i<attrs.length;i++){ attr=attrs[i]; name=attr.getName(); // hint if(idName.equalsIgnoreCase(name) || name.equalsIgnoreCase(idName+".hint")) { hint=CastString.toExprString(attr.getValue()); params.remove(name); } //meta if(StringUtil.startsWithIgnoreCase(name, idName+".")) { if(name.length()>idName.length()+1){ if(meta==null) meta=new HashMap<String, Attribute>(); _name=name.substring(idName.length()+1); meta.put(_name, new Attribute(attr.isDynamicType(), _name,attr.getValue(), attr.getType())); } params.remove(name); } } } // argument attributes Attribute[] _attrs = attributes(null,null,data,COMMA_ENDBRACKED,LitString.EMPTY,Boolean.TRUE,null,false); Attribute _attr; if(!ArrayUtil.isEmpty(_attrs)){ if(meta==null) meta=new HashMap<String, Attribute>(); for(int i=0;i<_attrs.length;i++){ _attr=_attrs[i]; meta.put(_attr.getName(), _attr); } } func.addArgument( LitString.toExprString(idName), LitString.toExprString(typeName), LitBoolean.toExprBoolean(required), defaultValue,passByRef,displayName,hint,meta); comments(data); } while(data.cfml.forwardIfCurrent(',')); // end ) comments(data); if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"invalid syntax in function head, missing ending [)]"); //TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,"function"); // doc comment if(data.docComment!=null){ func.setHint(data.docComment.getHint()); // params /*Map<String, Attribute> params = data.docComment.getParams(); Iterator<Attribute> it = params.values().iterator(); Attribute attr; String name; while(it.hasNext()){ attr=it.next(); name=attr.getName(); }*/ func.setMetaData(data.docComment.getParams()); data.docComment=null; } comments(data); // attributes Attribute[] attrs = attributes(null,null,data,SEMI_BLOCK,LitString.EMPTY,Boolean.TRUE,null,false); for(int i=0;i<attrs.length;i++){ func.addAttribute(attrs[i]); } // body boolean oldInsideFunction=data.insideFunction; data.insideFunction=true; try { // ex block statement(data,body,CTX_FUNCTION); } finally{ data.insideFunction=oldInsideFunction; } func.setEnd(data.cfml.getPosition()); //eval(tlt,data,func); return func; } private Statement tagStatement(ExprData data, Body parent) throws TemplateException { Statement child; //TagLibTag[] tags = getScriptTags(data); for(int i=0;i<data.scriptTags.length;i++){ // single if(data.scriptTags[i].getScript().getType()==TagLibTagScript.TYPE_SINGLE) { if((child=_singleAttrStatement(parent,data,data.scriptTags[i]))!=null)return child; } // multiple else {//if(tags[i].getScript().getType()==TagLibTagScript.TYPE_MULTIPLE) { if((child=_multiAttrStatement(parent,data,data.scriptTags[i]))!=null)return child; } } //if((child=_singleAttrStatement(parent,data,"abort","showerror",ATTR_TYPE_OPTIONAL,true))!=null) return child; //if((child=_multiAttrStatement(parent,data,"admin",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"application",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"associate",CTX_OTHER,false,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"break",null,ATTR_TYPE_NONE,false))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"cache",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"content",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"collection",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"cookie",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"component",CTX_CFC,true,false))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"continue",null,ATTR_TYPE_NONE,false))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"dbinfo",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"execute",CTX_OTHER,true,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"exit","method",ATTR_TYPE_OPTIONAL,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"feed",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"file",CTX_OTHER,false,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"flush","interval",ATTR_TYPE_OPTIONAL,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"ftp",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"http",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"httpparam",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"imap",CTX_OTHER,false,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"import","path",ATTR_TYPE_REQUIRED,false))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"index",CTX_OTHER,false,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"include","template",ATTR_TYPE_REQUIRED,true))!=null)return child; //else if((child=_multiAttrStatement(parent,data,"interface",CTX_INTERFACE,true,false))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"ldap",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"lock",CTX_LOCK,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"loop",CTX_LOOP,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"login",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"loginuser",CTX_OTHER,false,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"logout",null,ATTR_TYPE_NONE,false))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"mail",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"mailpart",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"mailparam",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"module",CTX_OTHER,true,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"pageencoding","charset",ATTR_TYPE_OPTIONAL,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"param",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"pdf",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"pdfparam",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"procparam",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"procresult",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"query",CTX_QUERY,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"queryparam",CTX_OTHER,false,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"rethrow",null,ATTR_TYPE_NONE,false))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"savecontent",CTX_SAVECONTENT,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"schedule",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"search",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"setting",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"stopwatch",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"storedproc",CTX_OTHER,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"thread",CTX_THREAD,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"trace",CTX_OTHER,true,true))!=null) return child; //else if((child=_singleAttrStatement(parent,data,"throw","message",ATTR_TYPE_OPTIONAL,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"transaction",CTX_TRANSACTION,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"wddx",CTX_OTHER,false,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"zip",CTX_ZIP,true,true))!=null) return child; //else if((child=_multiAttrStatement(parent,data,"zipparam",CTX_ZIP,false,true))!=null) return child; return null; } private final Statement _multiAttrStatement(Body parent, ExprData data,TagLibTag tlt) throws TemplateException { int pos = data.cfml.getPos(); try { return __multiAttrStatement(parent,data,tlt); } catch (ProcessingDirectiveException e) { throw e; } catch (TemplateException e) { try { data.cfml.setPos(pos); return expressionStatement(data,parent); } catch (TemplateException e1) { if(tlt.getScript().getContext()==CTX_CFC) throw new ComponentTemplateException(e); throw e; } } } private final Tag __multiAttrStatement(Body parent, ExprData data,TagLibTag tlt) throws TemplateException { if(data.ep==null) return null; String type=tlt.getName(); if(data.cfml.forwardIfCurrent(type)) { boolean isValid=(data.cfml.isCurrent(' ') || (tlt.getHasBody() && data.cfml.isCurrent('{'))); if(!isValid){ data.cfml.setPos(data.cfml.getPos()-type.length()); return null; } } else return null; Position line = data.cfml.getPosition(); TagLibTagScript script = tlt.getScript(); //TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,type); if(script.getContext()==CTX_CFC)data.isCFC=true; else if(script.getContext()==CTX_INTERFACE)data.isInterface=true; //Tag tag=new TagComponent(line); Tag tag=getTag(data,parent,tlt, line,null); tag.setTagLibTag(tlt); tag.setScriptBase(true); // add component meta data if(data.isCFC) { addMetaData(data,tag,IGNORE_LIST_COMPONENT); } if(data.isInterface) { addMetaData(data,tag,IGNORE_LIST_INTERFACE); } //EvaluatorPool.getPool(); comments(data); // attributes //attributes(func,data); Attribute[] attrs = attributes(tag,tlt,data,SEMI_BLOCK,LitString.EMPTY,script.getRtexpr()?Boolean.TRUE:Boolean.FALSE,null,false); for(int i=0;i<attrs.length;i++){ tag.addAttribute(attrs[i]); } comments(data); // body if(tlt.getHasBody()){ Body body=new BodyBase(); boolean wasSemiColon=statement(data,body,script.getContext()); if(!wasSemiColon || !tlt.isBodyFree() || body.hasStatements()) tag.setBody(body); } else checkSemiColonLineFeed(data,true,true); tag.setEnd(data.cfml.getPosition()); eval(tlt,data,tag); return tag; } private final void addMetaData(ExprData data, Tag tag, String[] ignoreList) { if(data.docComment==null) return; tag.addMetaData(data.docComment.getHintAsAttribute()); Map<String, Attribute> params = data.docComment.getParams(); Iterator<Attribute> it = params.values().iterator(); Attribute attr; outer:while(it.hasNext()){ attr = it.next(); // ignore list if(!ArrayUtil.isEmpty(ignoreList)) { for(int i=0;i<ignoreList.length;i++){ if(ignoreList[i].equalsIgnoreCase(attr.getName())) continue outer; } } tag.addMetaData(attr); } data.docComment=null; } private final Statement propertyStatement(ExprData data,Body parent) throws TemplateException { int pos = data.cfml.getPos(); try { return _propertyStatement(data, parent); } catch (TemplateException e) { try { data.cfml.setPos(pos); return expressionStatement(data,parent); } catch (TemplateException e1) { throw e; } } } private final Tag _propertyStatement(ExprData data,Body parent) throws TemplateException { if(data.context!=CTX_CFC || !data.cfml.forwardIfCurrent("property ")) return null; Position line = data.cfml.getPosition(); TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,"property"); Tag property=new TagOther(line,null); addMetaData(data, property,IGNORE_LIST_PROPERTY); boolean hasName=false,hasType=false; // TODO allow the following pattern property "a.b.C" d; //Expression t = string(data); // print.o("name:"+t.getClass().getName()); int pos = data.cfml.getPos(); String tmp=variableDec(data, true); if(!StringUtil.isEmpty(tmp)) { if(tmp.indexOf('.')!=-1) { property.addAttribute(new Attribute(false,"type",LitString.toExprString(tmp),"string")); hasType=true; } else { data.cfml.setPos(pos); } } else data.cfml.setPos(pos); // folgend wird tlt extra nicht uebergeben, sonst findet pruefung statt Attribute[] attrs = attributes(property,tlt,data,SEMI, NULL,Boolean.FALSE,"name",true); checkSemiColonLineFeed(data,true,true); property.setTagLibTag(tlt); property.setScriptBase(true); Attribute attr; // first fill all regular attribute -> name="value" for(int i=attrs.length-1;i>=0;i--){ attr=attrs[i]; if(!attr.getValue().equals(NULL)){ if(attr.getName().equalsIgnoreCase("name")){ hasName=true; //attr=new Attribute(attr.isDynamicType(),attr.getName(),CastString.toExprString(attr.getValue()),"string"); } else if(attr.getName().equalsIgnoreCase("type")){ hasType=true; //attr=new Attribute(attr.isDynamicType(),attr.getName(),CastString.toExprString(attr.getValue()),"string"); } property.addAttribute(attr); } } // now fill name named attributes -> attr1 attr2 String first=null,second=null; for(int i=0;i<attrs.length;i++){ attr=attrs[i]; if(attr.getValue().equals(NULL)){ // type if(first==null && (!hasName || !hasType)){ first=attr.getName(); //type=new Attribute(false,"type",LitString.toExprString(attr.getName()),"string"); //property.addAttribute(type); } // name else if(second==null && !hasName && !hasType){ second=attr.getName(); //name=new Attribute(false,"name",LitString.toExprString(attr.getName()),"string"); //property.addAttribute(name); } // attr with no value else { attr=new Attribute(true,attr.getName(),LitString.EMPTY,"string"); property.addAttribute(attr); } } } if(first!=null) { hasName=true; if(second!=null){ hasType=true; property.addAttribute(new Attribute(false,"name",LitString.toExprString(second),"string")); property.addAttribute(new Attribute(false,"type",LitString.toExprString(first),"string")); } else { property.addAttribute(new Attribute(false,"name",LitString.toExprString(first),"string")); } } if(!hasType) property.addAttribute(ANY); if(!hasName) throw new TemplateException(data.cfml,"missing name declaration for property"); /*Tag property=new TagBase(line); property.setTagLibTag(tlt); property.addAttribute(new Attribute(false,"name",LitString.toExprString(name),"string")); property.addAttribute(new Attribute(false,"type",LitString.toExprString(type),"string")); */ property.setEnd(data.cfml.getPosition()); return property; } public Statement paramStatement(ExprData data,Body parent) throws TemplateException { int pos = data.cfml.getPos(); try { return _paramStatement(data, parent); } catch (TemplateException e) { try { data.cfml.setPos(pos); return expressionStatement(data,parent); } catch (TemplateException e1) { throw e; } } } private Tag _paramStatement(ExprData data,Body parent) throws TemplateException { if(!data.cfml.forwardIfCurrent("param ")) return null; Position line = data.cfml.getPosition(); TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,"param"); TagParam param=new TagParam(line,null); // type boolean hasType=false; int pos = data.cfml.getPos(); String tmp=variableDec(data, true); if(!StringUtil.isEmpty(tmp)) { if(tmp.indexOf('.')!=-1) { param.addAttribute(new Attribute(false,"type",LitString.toExprString(tmp),"string")); hasType=true; } else data.cfml.setPos(pos); } else data.cfml.setPos(pos); // folgend wird tlt extra nicht uebergeben, sonst findet pruefung statt Attribute[] attrs = attributes(param,tlt,data,SEMI, NULL,Boolean.TRUE,"name",true); checkSemiColonLineFeed(data,true,true); param.setTagLibTag(tlt); param.setScriptBase(true); Attribute attr; // first fill all regular attribute -> name="value" boolean hasDynamic=false; boolean hasName=false; for(int i=attrs.length-1;i>=0;i--){ attr=attrs[i]; if(!attr.getValue().equals(NULL)){ if(attr.getName().equalsIgnoreCase("name")){ hasName=true; param.addAttribute(attr); } else if(attr.getName().equalsIgnoreCase("type")){ hasType=true; param.addAttribute(attr); } else if(attr.isDynamicType()){ hasName=true; if(hasDynamic) throw attrNotSupported(data.cfml,tlt,attr.getName()); hasDynamic=true; param.addAttribute(new Attribute(false,"name",LitString.toExprString(attr.getName()),"string")); param.addAttribute(new Attribute(false,"default",attr.getValue(),"any")); } else param.addAttribute(attr); } } // now fill name named attributes -> attr1 attr2 String first=null,second=null; for(int i=0;i<attrs.length;i++){ attr=attrs[i]; if(attr.getValue().equals(NULL)){ // type if(first==null && (!hasName || !hasType)){ first=attr.getName(); } // name else if(second==null && !hasName && !hasType){ second=attr.getName(); } // attr with no value else { attr=new Attribute(true,attr.getName(),LitString.EMPTY,"string"); param.addAttribute(attr); } } } if(first!=null) { if(second!=null){ hasName=true; hasType=true; if(hasDynamic) throw attrNotSupported(data.cfml,tlt,first); hasDynamic=true; param.addAttribute(new Attribute(false,"name",LitString.toExprString(second),"string")); param.addAttribute(new Attribute(false,"type",LitString.toExprString(first),"string")); } else { param.addAttribute(new Attribute(false,hasName?"type":"name",LitString.toExprString(first),"string")); hasName=true; } } //if(!hasType) // param.addAttribute(ANY); if(!hasName) throw new TemplateException(data.cfml,"missing name declaration for param"); param.setEnd(data.cfml.getPosition()); return param; } private TemplateException attrNotSupported(CFMLString cfml, TagLibTag tag, String id) { String names=tag.getAttributeNames(); if(StringUtil.isEmpty(names)) return new TemplateException(cfml,"Attribute "+id+" is not allowed for tag "+tag.getFullName()); return new TemplateException(cfml, "Attribute "+id+" is not allowed for statement "+tag.getName(), "valid attribute names are ["+names+"]"); } private final String variableDec(ExprData data,boolean firstCanBeNumber) { String id=identifier(data, firstCanBeNumber); if(id==null) return null; StringBuffer rtn=new StringBuffer(id); data.cfml.removeSpace(); while(data.cfml.forwardIfCurrent('.')){ data.cfml.removeSpace(); rtn.append('.'); id=identifier(data, firstCanBeNumber); if(id==null)return null; rtn.append(id); data.cfml.removeSpace(); } while(data.cfml.forwardIfCurrent("[]")){ data.cfml.removeSpace(); rtn.append("[]"); } return rtn.toString(); } /** * Liest ein return Statement ein. * <br /> * EBNF:<br /> * <code>spaces expressionStatement spaces;</code> * @return return Statement * @throws TemplateException */ private final Return returnStatement(ExprData data) throws TemplateException { if(!data.cfml.forwardIfCurrentAndNoVarExt("return")) return null; Position line = data.cfml.getPosition(); Return rtn; comments(data); if(checkSemiColonLineFeed(data, false,false)) rtn=new Return(line,data.cfml.getPosition()); else { Expression expr = expression(data); checkSemiColonLineFeed(data, true,true); rtn=new Return(expr,line,data.cfml.getPosition()); } comments(data); return rtn; } private final Statement _singleAttrStatement(Body parent, ExprData data, TagLibTag tlt) throws TemplateException { int pos = data.cfml.getPos(); try { return __singleAttrStatement(parent,data,tlt, false); } catch (ProcessingDirectiveException e) { throw e; } catch (TemplateException e) { data.cfml.setPos(pos); try { return expressionStatement(data,parent); } catch (TemplateException e1) { throw e; } } } private final Statement __singleAttrStatement(Body parent, ExprData data, TagLibTag tlt, boolean allowTwiceAttr) throws TemplateException { String tagName = tlt.getName(); if(data.cfml.forwardIfCurrent(tagName)){ if(!data.cfml.isCurrent(' ') && !data.cfml.isCurrent(';')){ data.cfml.setPos(data.cfml.getPos()-tagName.length()); return null; } } else return null; int pos=data.cfml.getPos()-tagName.length(); Position line = data.cfml.getPosition(); //TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,tagName.equals("pageencoding")?"processingdirective":tagName); Tag tag=getTag(data,parent,tlt,line,null); tag.setScriptBase(true); tag.setTagLibTag(tlt); comments(data); // attribute TagLibTagAttr attr = tlt.getScript().getSingleAttr(); String attrName=null; Expression attrValue=null; short attrType=ATTR_TYPE_NONE; if(attr!=null){ attrType = attr.getScriptSupport(); char c = data.cfml.getCurrent(); if(ATTR_TYPE_REQUIRED==attrType || (!data.cfml.isCurrent(';') && ATTR_TYPE_OPTIONAL==attrType)) { attrValue =attributeValue(data, tlt.getScript().getRtexpr()); if(attrValue!=null && isOperator(c)) { data.cfml.setPos(pos); return null; } } } if(attrValue!=null){ attrName=attr.getName(); TagLibTagAttr tlta = tlt.getAttribute(attr.getName()); tag.addAttribute(new Attribute(false,attrName,CastOther.toExpression(attrValue,tlta.getType()),tlta.getType())); } else if(ATTR_TYPE_REQUIRED==attrType){ data.cfml.setPos(pos); return null; } checkSemiColonLineFeed(data,true,true); if(!StringUtil.isEmpty(tlt.getTteClassName()))data.ep.add(tlt, tag, data.flibs, data.cfml); if(!StringUtil.isEmpty(attrName))validateAttributeName(attrName, data.cfml, new ArrayList<String>(), tlt, new RefBooleanImpl(false), new StringBuffer(), allowTwiceAttr); tag.setEnd(data.cfml.getPosition()); eval(tlt,data,tag); return tag; } private boolean isOperator(char c) { return c=='=' || c=='+' || c=='-'; } /*protected Statement __singleAttrStatement(Body parent, Data data, String tagName,String attrName,int attrType, boolean allowExpression, boolean allowTwiceAttr) throws TemplateException { if(data.cfml.forwardIfCurrent(tagName)){ if(!data.cfml.isCurrent(' ') && !data.cfml.isCurrent(';')){ data.cfml.setPos(data.cfml.getPos()-tagName.length()); return null; } } else return null; int pos=data.cfml.getPos()-tagName.length(); int line=data.cfml.getLine(); TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,tagName.equals("pageencoding")?"processingdirective":tagName); Tag tag=getTag(parent,tlt,line); tag.setScriptBase(true); tag.setTagLibTag(tlt); comments(data); // attribute Expression attrValue=null; if(ATTR_TYPE_REQUIRED==attrType || (!data.cfml.isCurrent(';') && ATTR_TYPE_OPTIONAL==attrType)) attrValue =attributeValue(data, allowExpression); //allowExpression?super.expression(data):string(data); if(attrValue!=null){ TagLibTagAttr tlta = tlt.getAttribute(attrName); tag.addAttribute(new Attribute(false,attrName,Cast.toExpression(attrValue,tlta.getType()),tlta.getType())); } else if(ATTR_TYPE_REQUIRED==attrType){ data.cfml.setPos(pos); return null; } checkSemiColonLineFeed(data,true); if(!StringUtil.isEmpty(tlt.getTteClassName()))data.ep.add(tlt, tag, data.fld, data.cfml); if(!StringUtil.isEmpty(attrName))validateAttributeName(attrName, data.cfml, new ArrayList<String>(), tlt, new RefBooleanImpl(false), new StringBuffer(), allowTwiceAttr); eval(tlt,data,tag); return tag; }*/ private final void eval(TagLibTag tlt, railo.transformer.cfml.expression.CFMLExprTransformer.ExprData data, Tag tag) throws TemplateException { if(!StringUtil.isEmpty(tlt.getTteClassName())){ try { tlt.getEvaluator().execute(data.config, tag, tlt,data.flibs, data); } catch (EvaluatorException e) { throw new TemplateException(e.getMessage()); } data.ep.add(tlt, tag, data.flibs, data.cfml); } } private final Tag getTag(ExprData data,Body parent, TagLibTag tlt, Position start,Position end) throws TemplateException { try { Tag tag = tlt.getTag(start, end); tag.setParent(parent); return tag; } catch (TagLibException e) { throw new TemplateException(data.cfml,e); } /*if(StringUtil.isEmpty(tlt.getTttClassName()))tag= new TagBase(line); else { try { Class<Tag> clazz = ClassUtil.loadClass(tlt.getTttClassName()); Constructor<Tag> constr = clazz.getConstructor(new Class[]{Position.class}); tag = constr.newInstance(new Object[]{line}); } catch (Exception e) { e.printStackTrace(); tag= new TagBase(line); } }*/ } /** * List mithilfe des data.cfmlExprTransformer einen Ausruck ein. * <br /> * EBNF:<br /> * <code>expression ";";</code> * @param parent * @return Ausdruck * @throws TemplateException */ private Statement expressionStatement(ExprData data, Body parent) throws TemplateException { Expression expr=expression(data); checkSemiColonLineFeed(data,true,true); if(expr instanceof ClosureAsExpression) return ((ClosureAsExpression)expr).getClosure(); return new ExpressionAsStatement(expr); } private final boolean checkSemiColonLineFeed(ExprData data,boolean throwError, boolean checkNLBefore) throws TemplateException { comments(data); if(!data.cfml.forwardIfCurrent(';')){ if((!checkNLBefore || !data.cfml.hasNLBefore()) && !data.cfml.isCurrent("</",data.tagName) && !data.cfml.isCurrent('}')){ if(!throwError) return false; throw new TemplateException(data.cfml,"Missing [;] or [line feed] after expression"); } } return true; } /** * Ruft die Methode expression der zu vererbenten Klasse auf * und prueft ob der Rueckgabewert einen boolschen Wert repraesentiert und castet den Wert allenfalls. * <br /> * EBNF:<br /> * <code>TemplateException::expression;</code> * @return condition * @throws TemplateException */ private final ExprBoolean condition(ExprData data) throws TemplateException { ExprBoolean condition=null; comments(data); condition=CastBoolean.toExprBoolean(super.expression(data)); comments(data); return condition; } /** * Liest eine try Block ein * <br /> * EBNF:<br /> * <code>;</code> * @return Try Block * @throws TemplateException */ private final TryCatchFinally tryStatement(ExprData data) throws TemplateException { if(!data.cfml.forwardIfCurrent("try",'{') && !data.cfml.forwardIfCurrent("try ") && !data.cfml.forwardIfCurrent("try",'/')) return null; data.cfml.previous(); Body body=new BodyBase(); TryCatchFinally tryCatchFinally=new TryCatchFinally(body,data.cfml.getPosition(),null); statement(data,body,CTX_TRY); comments(data); // catches short catchCount=0; while(data.cfml.forwardIfCurrent("catch",'(')) { catchCount++; comments(data); // type int pos=data.cfml.getPos(); Position line=data.cfml.getPosition(); Expression name = null,type = null; StringBuffer sbType=new StringBuffer(); String id; while(true) { id=identifier(data,false); if(id==null)break; sbType.append(id); data.cfml.removeSpace(); if(!data.cfml.forwardIfCurrent('.'))break; sbType.append('.'); data.cfml.removeSpace(); } if(sbType.length()==0) { type=string(data); if(type==null) throw new TemplateException(data.cfml,"a catch statement must begin with the throwing type (query, application ...)."); } else { type=LitString.toExprString(sbType.toString()); } //name = expression(); comments(data); // name if(!data.cfml.isCurrent(')')) { name=expression(data); } else { data.cfml.setPos(pos); name=expression(data); type = LitString.toExprString( "any" ); } comments(data); Body b=new BodyBase(); try { tryCatchFinally.addCatch(type,name,b,line); } catch (BytecodeException e) { throw new TemplateException(data.cfml,e.getMessage()); } comments(data); if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"invalid catch statement, missing closing )"); statement(data,b,CTX_CATCH); comments(data); } // finally if(finallyStatement(data,tryCatchFinally)) { comments(data); } else if(catchCount==0) throw new TemplateException(data.cfml,"a try statement must have at least one catch statement"); //if(body.isEmpty()) return null; tryCatchFinally.setEnd(data.cfml.getPosition()); return tryCatchFinally; } /** * Prueft ob sich der Zeiger am Ende eines Script Blockes befindet * @return Ende ScriptBlock? * @throws TemplateException */ private final boolean isFinish(ExprData data) throws TemplateException { comments(data); return data.cfml.isCurrent("</",data.tagName); } /** * Liest den Block mit Statements ein. * <br /> * EBNF:<br /> * <code>"{" spaces {statements} "}" | statement;</code> * @param block * @return was a block * @throws TemplateException */ private final boolean block(ExprData data,Body body) throws TemplateException { if(!data.cfml.forwardIfCurrent('{')) return false; comments(data); if(data.cfml.forwardIfCurrent('}')) { return true; } statements(data,body,false); if(!data.cfml.forwardIfCurrent('}')) throw new TemplateException(data.cfml,"Missing ending [}]"); return true; } private final Attribute[] attributes(Tag tag,TagLibTag tlt, ExprData data, EndCondition endCond,Expression defaultValue,Object oAllowExpression, String ignoreAttrReqFor, boolean allowTwiceAttr) throws TemplateException { ArrayList<Attribute> attrs=new ArrayList<Attribute>(); ArrayList<String> ids=new ArrayList<String>(); while(data.cfml.isValidIndex()) { data.cfml.removeSpace(); // if no more attributes break if(endCond.isEnd(data)) break; //if((allowBlock && data.cfml.isCurrent('{')) || data.cfml.isCurrent(';')) break; Attribute attr = attribute(tlt,data,ids,defaultValue,oAllowExpression, allowTwiceAttr); attrs.add(attr); } // not defined attributes if(tlt!=null){ boolean hasAttributeCollection=attrs.contains("attributecollection"); int type=tlt.getAttributeType(); if(type==TagLibTag.ATTRIBUTE_TYPE_FIXED || type==TagLibTag.ATTRIBUTE_TYPE_MIXED) { Map<String, TagLibTagAttr> hash = tlt.getAttributes(); Iterator<String> it = hash.keySet().iterator(); while(it.hasNext()) { TagLibTagAttr att=hash.get(it.next()); if(att.isRequired() && !contains(attrs,att.getName()) && att.getDefaultValue()==null && !att.getName().equals(ignoreAttrReqFor)) { if(!hasAttributeCollection)throw new TemplateException(data.cfml,"attribute "+att.getName()+" is required for statement "+tlt.getName()); if(tag!=null)tag.addMissingAttribute(att.getName(),att.getType()); } } } } return attrs.toArray(new Attribute[attrs.size()]); } private final boolean contains(ArrayList<Attribute> attrs, String name) { Iterator<Attribute> it = attrs.iterator(); while(it.hasNext()){ if(it.next().getName().equals(name)) return true; } return false; } private final Attribute attribute(TagLibTag tlt, ExprData data, ArrayList<String> args, Expression defaultValue,Object oAllowExpression, boolean allowTwiceAttr) throws TemplateException { StringBuffer sbType=new StringBuffer(); RefBoolean dynamic=new RefBooleanImpl(false); // Name String name=attributeName(data.cfml,args,tlt,dynamic,sbType, allowTwiceAttr); boolean allowExpression=false; if(oAllowExpression instanceof Boolean)allowExpression=((Boolean)oAllowExpression).booleanValue(); else if(oAllowExpression instanceof String)allowExpression=((String)oAllowExpression).equalsIgnoreCase(name); Expression value=null; CFMLTransformer.comment(data.cfml,true); // value if(data.cfml.forwardIfCurrent('=')) { CFMLTransformer.comment(data.cfml,true); value=attributeValue(data,allowExpression); } else { value=defaultValue; } CFMLTransformer.comment(data.cfml,true); // Type TagLibTagAttr tlta=null; if(tlt!=null){ tlta = tlt.getAttribute(name); } return new Attribute(dynamic.toBooleanValue(),name,tlta!=null?CastOther.toExpression(value, tlta.getType()):value,sbType.toString()); } /*private String attributeName(CFMLString cfml, ArrayList<String> args,TagLibTag tag, RefBoolean dynamic, StringBuffer sbType) throws TemplateException { String id=StringUtil.toLowerCase(CFMLTransformer.identifier(cfml,true)); if(args.contains(id)) throw new TemplateException(cfml,"you can't use the same attribute ["+id+"] twice"); args.add(id); int typeDef=tag.getAttributeType(); if("attributecollection".equals(id)){ dynamic.setValue(tag.getAttribute(id)==null); sbType.append("struct"); } else if(typeDef==TagLibTag.ATTRIBUTE_TYPE_FIXED || typeDef==TagLibTag.ATTRIBUTE_TYPE_MIXED) { TagLibTagAttr attr=tag.getAttribute(id); if(attr==null) { if(typeDef==TagLibTag.ATTRIBUTE_TYPE_FIXED) { String names=tag.getAttributeNames(); if(StringUtil.isEmpty(names)) throw new TemplateException(cfml,"Attribute "+id+" is not allowed for tag "+tag.getFullName()); throw new TemplateException(cfml, "Attribute "+id+" is not allowed for statement "+tag.getName(), "valid attribute names are ["+names+"]"); } } else { sbType.append(attr.getType()); //parseExpression[0]=attr.getRtexpr(); } } else if(typeDef==TagLibTag.ATTRIBUTE_TYPE_DYNAMIC){ dynamic.setValue(true); } return id; }*/ private final String attributeName(CFMLString cfml, ArrayList<String> args,TagLibTag tag, RefBoolean dynamic, StringBuffer sbType, boolean allowTwiceAttr) throws TemplateException { String id=StringUtil.toLowerCase(CFMLTransformer.identifier(cfml,true)); return validateAttributeName(id, cfml, args, tag, dynamic, sbType,allowTwiceAttr); } private final String validateAttributeName(String id,CFMLString cfml, ArrayList<String> args,TagLibTag tag, RefBoolean dynamic, StringBuffer sbType, boolean allowTwiceAttr) throws TemplateException { if(args.contains(id) && !allowTwiceAttr) throw new TemplateException(cfml,"you can't use the same attribute ["+id+"] twice"); args.add(id); if(tag==null) return id; int typeDef=tag.getAttributeType(); if("attributecollection".equals(id)){ dynamic.setValue(tag.getAttribute(id)==null); sbType.append("struct"); } else if(typeDef==TagLibTag.ATTRIBUTE_TYPE_FIXED || typeDef==TagLibTag.ATTRIBUTE_TYPE_MIXED) { TagLibTagAttr attr=tag.getAttribute(id); if(attr==null) { if(typeDef==TagLibTag.ATTRIBUTE_TYPE_FIXED) { String names=tag.getAttributeNames(); if(StringUtil.isEmpty(names)) throw new TemplateException(cfml,"Attribute "+id+" is not allowed for tag "+tag.getFullName()); throw new TemplateException(cfml, "Attribute "+id+" is not allowed for statement "+tag.getName(), "valid attribute names are ["+names+"]"); } dynamic.setValue(true); } else { sbType.append(attr.getType()); //parseExpression[0]=attr.getRtexpr(); } } else if(typeDef==TagLibTag.ATTRIBUTE_TYPE_DYNAMIC){ dynamic.setValue(true); } return id; } private final Expression attributeValue(ExprData data, boolean allowExpression) throws TemplateException { return allowExpression?super.expression(data):transformAsString(data,new String[]{" ", ";", "{"}); } public static interface EndCondition { public boolean isEnd(ExprData data); } }