Package railo.transformer.cfml.script

Source Code of railo.transformer.cfml.script.AbstrCFMLScriptTransformer

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))!=nullparent.addStatement(child);
    else if((child=paramStatement(data,parent))!=nullparent.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))!=nullparent.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);
  }
}
TOP

Related Classes of railo.transformer.cfml.script.AbstrCFMLScriptTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.