Package railo.runtime.interpreter

Source Code of railo.runtime.interpreter.CFMLExpressionInterpreter

package railo.runtime.interpreter;

import java.util.ArrayList;
import java.util.Map;

import org.apache.commons.collections.map.ReferenceMap;

import railo.commons.lang.CFTypes;
import railo.commons.lang.ParserString;
import railo.runtime.PageContext;
import railo.runtime.config.ConfigImpl;
import railo.runtime.config.ConfigWebImpl;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.exp.PageException;
import railo.runtime.interpreter.ref.Ref;
import railo.runtime.interpreter.ref.Set;
import railo.runtime.interpreter.ref.cast.Casting;
import railo.runtime.interpreter.ref.func.BIFCall;
import railo.runtime.interpreter.ref.func.UDFCall;
import railo.runtime.interpreter.ref.literal.LBoolean;
import railo.runtime.interpreter.ref.literal.LFunctionValue;
import railo.runtime.interpreter.ref.literal.LNumber;
import railo.runtime.interpreter.ref.literal.LString;
import railo.runtime.interpreter.ref.literal.LStringBuffer;
import railo.runtime.interpreter.ref.literal.Literal;
import railo.runtime.interpreter.ref.op.And;
import railo.runtime.interpreter.ref.op.BigDiv;
import railo.runtime.interpreter.ref.op.BigIntDiv;
import railo.runtime.interpreter.ref.op.BigMinus;
import railo.runtime.interpreter.ref.op.BigMod;
import railo.runtime.interpreter.ref.op.BigMulti;
import railo.runtime.interpreter.ref.op.BigPlus;
import railo.runtime.interpreter.ref.op.CT;
import railo.runtime.interpreter.ref.op.Concat;
import railo.runtime.interpreter.ref.op.Cont;
import railo.runtime.interpreter.ref.op.Div;
import railo.runtime.interpreter.ref.op.EEQ;
import railo.runtime.interpreter.ref.op.EQ;
import railo.runtime.interpreter.ref.op.EQV;
import railo.runtime.interpreter.ref.op.Elvis;
import railo.runtime.interpreter.ref.op.Exp;
import railo.runtime.interpreter.ref.op.GT;
import railo.runtime.interpreter.ref.op.GTE;
import railo.runtime.interpreter.ref.op.Imp;
import railo.runtime.interpreter.ref.op.IntDiv;
import railo.runtime.interpreter.ref.op.LT;
import railo.runtime.interpreter.ref.op.LTE;
import railo.runtime.interpreter.ref.op.Minus;
import railo.runtime.interpreter.ref.op.Mod;
import railo.runtime.interpreter.ref.op.Multi;
import railo.runtime.interpreter.ref.op.NCT;
import railo.runtime.interpreter.ref.op.NEEQ;
import railo.runtime.interpreter.ref.op.NEQ;
import railo.runtime.interpreter.ref.op.Negate;
import railo.runtime.interpreter.ref.op.Not;
import railo.runtime.interpreter.ref.op.Or;
import railo.runtime.interpreter.ref.op.Plus;
import railo.runtime.interpreter.ref.op.Xor;
import railo.runtime.interpreter.ref.var.Assign;
import railo.runtime.interpreter.ref.var.Bind;
import railo.runtime.interpreter.ref.var.DynAssign;
import railo.runtime.interpreter.ref.var.Variable;
import railo.runtime.type.scope.Scope;
import railo.runtime.type.scope.ScopeSupport;
import railo.transformer.library.function.FunctionLib;
import railo.transformer.library.function.FunctionLibFunction;
import railo.transformer.library.function.FunctionLibFunctionArg;

/**
*
*
    Der CFMLExprTransfomer implementiert das Interface ExprTransfomer,
    er bildet die Parser Grammatik ab, die unten definiert ist.
    Er erh¦lt als Eingabe CFML Code, als String oder CFMLString,
    der einen CFML Expression erh¦lt und liefert ein CFXD Element zurck,
    das diesen Ausdruck abbildet.
    Mithilfe der FunctionLibメs, kann er Funktionsaufrufe,
    die Teil eines Ausdruck sein k￶nnen, erkennen und validieren.
    Dies geschieht innerhalb der Methode function.
    Falls ein Funktionsaufruf, einer Funktion innerhalb einer FunctionLib entspricht,
    werden diese gegeneinander verglichen und der Aufruf wird als Build-In-Funktion bernommen,
    andernfalls wird der Funktionsaufruf als User-Defined-Funktion interpretiert.
    Die Klasse Cast, Operator und ElementFactory (siehe 3.2) helfen ihm beim erstellen des Ausgabedokument CFXD.

* <pre>
* Parser Grammatik EBNF (Extended Backus-Naur Form)

    transform      = spaces impOp;
    impOp          = eqvOp {"imp" spaces eqvOp};
    eqvOp          = xorOp {"eqv" spaces xorOp};
    xorOp          = orOp {"xor" spaces  orOp};
    orOp           = andOp {("or" | "||") spaces andOp};
            (* "||" Existiert in CFMX nicht *)
    andOp          = notOp {("and" | "&&") spaces notOp};
            (* "&&" Existiert in CFMX nicht *)
    notOp          = [("not"|"!") spaces] decsionOp;
            (* "!" Existiert in CFMX nicht *)
    decsionOp      = concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"|
                     "contains"|"nct"|"does not contain") spaces concatOp};
            (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *)
    concatOp       = plusMinusOp {"&" spaces plusMinusOp};
    plusMinusOp    = modOp {("-"|"+") spaces modOp};
   
    modOp          = divMultiOp {("mod" | "%") spaces divMultiOp};
                    (* modulus operator , "%" Existiert in CFMX nicht *)
    divMultiOp     = expoOp {("*"|"/") spaces expoOp};
    expoOp         = clip {("exp"|"^") spaces clip};
                    (*exponent operator, " exp " Existiert in CFMX nicht *)
    clip           = ("(" spaces impOp ")" spaces) | checker;
    checker        = string | number | dynamic | sharp;
    string         = ("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") |
                     (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """);
    number         = ["+"|"-"] digit {digit} {"." digit {digit}};
    digit          = "0"|..|"9";
    dynamic        = "true" | "false" | "yes" | "no" | startElement 
                     {("." identifier | "[" structElement "]")[function] };
    startElement   = identifier "(" functionArg ")" | scope | identifier;
    scope          = "variable" | "cgi" | "url" | "form" | "session" | "application" |
                     "arguments" | "cookie" | " client";
    identifier     = (letter | "_") {letter | "_"|digit};
    structElement  = "[" impOp "]";
    functionArg    = [impOp{"," impOp}];
    sharp          = "#" checker "#";
    spaces         = {space};
    space          = "\s"|"\t"|"\f"|"\t"|"\n";
    letter         = "a"|..|"z"|"A"|..|"Z";

{"x"}= 0 bis n mal "x"
["x"]= 0 bis 1 mal "x"
("x" | "y")"z" = "xz" oder "yz"

</pre>
*
*/
public class CFMLExpressionInterpreter {


    private static final LNumber PLUS_ONE = new LNumber(new Double(1));
    private static final LNumber MINUS_ONE = new LNumber(new Double(-1));
 
    protected static final short STATIC=0;
    private static final short DYNAMIC=1;
  private static FunctionLibFunction JSON_ARRAY = null;
  private static FunctionLibFunction JSON_STRUCT = null;
 

  //private static final int CASE_TYPE_UPPER = 0;
  //private static final int CASE_TYPE_LOWER = 1;
  //private static final int CASE_TYPE_ORIGINAL = 2;
 
    protected short mode=0;
   
    protected ParserString cfml;
    //protected Document doc;
    //protected FunctionLib[] fld;
    protected PageContext pc;
    private FunctionLib fld;
  protected boolean allowNullConstant=false;
  private boolean preciseMath;
  private boolean isJson;
 
    private final static Map<String,Ref> data=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT);
 

  
    public Object interpret(PageContext pc,String str) throws PageException {
      return interpret(pc,str,false);
    }
   

    public Object interpret(PageContext pc,String str, boolean preciseMath) throws PageException {

      //Ref ref = data.get(str+":"+preciseMath);
      //if(ref!=null)return ref.getValue();
     
      this.cfml=new ParserString(str);
      this.preciseMath = preciseMath;
      this.pc=ThreadLocalPageContext.get(pc);
        if(pc!=null)fld=((ConfigImpl)pc.getConfig()).getCombinedFLDs();
       
        if(JSON_ARRAY==null)JSON_ARRAY=fld.getFunction("_jsonArray");
    if(JSON_STRUCT==null)JSON_STRUCT=fld.getFunction("_jsonStruct");
        isJson=this instanceof JSONExpressionInterpreter;
       
   
        cfml.removeSpace();
        Ref ref = assignOp();
        cfml.removeSpace();
       
        if(cfml.isAfterLast()) {
          //data.put(str+":"+preciseMath,ref);
            return ref.getValue(pc);
        }
        throw new InterpreterException("Syntax Error, invalid Expression ["+cfml.toString()+"]");
    }

   
    /*private FunctionLibFunction getFLF(String name) {
    FunctionLibFunction flf=null;
    for (int i = 0; i < flds.length; i++) {
      flf = flds[i].getFunction(name);
      if (flf != null)
        break;
    }
    return flf;
  }*/
   
   
    protected Object interpretPart(PageContext pc,ParserString cfml) throws PageException {
        this.cfml = cfml;
        this.pc=ThreadLocalPageContext.get(pc);
        if(pc!=null)fld=((ConfigImpl)pc.getConfig()).getCombinedFLDs();
       
        cfml.removeSpace();
        return assignOp().getValue(pc);
    }

    /**
    * Liest einen gelableten  Funktionsparamter ein
    * <br />
    * EBNF:<br />
    * <code>assignOp [":" spaces assignOp];</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref functionArgDeclarationVarString() throws PageException {
       
            cfml.removeSpace();
            StringBuffer str=new StringBuffer();
            String id=null;
            while((id=identifier(false))!=null) {
                if(str.length()>0)str.append('.');
                str.append(id);
                cfml.removeSpace();
                if(!cfml.forwardIfCurrent('.')) break;
                cfml.removeSpace();
            }
            cfml.removeSpace();
            if(str.length()>0 && cfml.charAt(cfml.getPos()-1)!='.')
                return new LString(str.toString());

        throw new InterpreterException("invalid variable name definition");
    }

    /**
    * Liest einen gelableten  Funktionsparamter ein
    * <br />
    * EBNF:<br />
    * <code>assignOp [":" spaces assignOp];</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref functionArgDeclaration() throws PageException {
        Ref ref = impOp();
        if (cfml.forwardIfCurrent(':') || cfml.forwardIfCurrent('=')) {
            cfml.removeSpace();
            ref=new LFunctionValue(ref,assignOp());
        }
        return ref;
    }

    /**
    * Transfomiert Zuweisungs Operation.
    * <br />
    * EBNF:<br />
    * <code>eqvOp ["=" spaces assignOp];</code>
    * @return CFXD Element
    * @throws PageException
    */
    protected Ref assignOp() throws PageException {
        Ref ref = contOp();

        if (cfml.forwardIfCurrent('=')) {
            cfml.removeSpace();
            if(mode==STATIC || ref instanceof Literal) {
                ref=new DynAssign(ref,assignOp());
            }
            else {
                ref=new Assign(ref,assignOp());
            }
        }
        return ref;
    }
   

    private Ref contOp() throws PageException {
        Ref ref = impOp();
        while(cfml.forwardIfCurrent('?')) {
            cfml.removeSpace();
            if(cfml.forwardIfCurrent(':')){
              cfml.removeSpace();
              Ref right = assignOp();   
              //if(!(ref instanceof Variable))
            //  throw new InterpreterException("left operant of the Elvis operator has to be a variable declaration "+ref.getClass().getName());
           
            ref=new Elvis(ref,right);
             
            }
            else {
              Ref left = assignOp();           
              if(!cfml.forwardIfCurrent(':'))
                throw new InterpreterException("Syntax Error, invalid conditional operator ["+cfml.toString()+"]");
              cfml.removeSpace();
              Ref right = assignOp();
              ref=new Cont(ref,left,right);
            }
        }
        return ref;
    }


  /**
    * Transfomiert eine Implication (imp) Operation.
    * <br />
    * EBNF:<br />
    * <code>eqvOp {"imp" spaces eqvOp};</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref impOp() throws PageException {
        Ref ref = eqvOp();
        while(cfml.forwardIfCurrentAndNoWordAfter("imp")) {
            cfml.removeSpace();
            ref=new Imp(ref,eqvOp());
        }
        return ref;
    }

    /**
    * Transfomiert eine  Equivalence (eqv) Operation.
    * <br />
    * EBNF:<br />
    * <code>xorOp {"eqv" spaces xorOp};</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref eqvOp() throws PageException {
        Ref ref = xorOp();
        while(cfml.forwardIfCurrent("eqv")) {
            cfml.removeSpace();
            ref=new EQV(ref,xorOp());
        }
        return ref;
    }

    /**
    * Transfomiert eine  Xor (xor) Operation.
    * <br />
    * EBNF:<br />
    * <code>orOp {"xor" spaces  orOp};</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref xorOp() throws PageException {
        Ref ref = orOp();
        while(cfml.forwardIfCurrent("xor")) {
            cfml.removeSpace();
            ref=new Xor(ref,orOp());
        }
        return ref;
    }

    /**
    * Transfomiert eine  Or (or) Operation. Im Gegensatz zu CFMX ,
    * werden "||" Zeichen auch als Or Operatoren anerkannt.
    * <br />
    * EBNF:<br />
    * <code>andOp {("or" | "||") spaces andOp}; (* "||" Existiert in CFMX nicht *)</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref orOp() throws PageException {
        Ref ref = andOp();
        while(cfml.isValidIndex() && (cfml.forwardIfCurrent("||") || cfml.forwardIfCurrent("or"))) {
            cfml.removeSpace();
            ref=new Or(ref,andOp());
        }
        return ref;
    }

    /**
    * Transfomiert eine  And (and) Operation. Im Gegensatz zu CFMX ,
    * werden "&&" Zeichen auch als And Operatoren anerkannt.
    * <br />
    * EBNF:<br />
    * <code>notOp {("and" | "&&") spaces notOp}; (* "&&" Existiert in CFMX nicht *)</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref andOp() throws PageException {
        Ref ref = notOp();
        while(cfml.isValidIndex() && (cfml.forwardIfCurrent("&&") || cfml.forwardIfCurrent("and"))) {
            cfml.removeSpace();
            ref=new And(ref,notOp());
        }
        return ref;
    }

    /**
    * Transfomiert eine  Not (not) Operation. Im Gegensatz zu CFMX ,
    * wird das "!" Zeichen auch als Not Operator anerkannt.
    * <br />
    * EBNF:<br />
    * <code>[("not"|"!") spaces] decsionOp; (* "!" Existiert in CFMX nicht *)</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref notOp() throws PageException {
      if(cfml.isValidIndex()) {
        if (cfml.isCurrent('!') && !cfml.isCurrent("!=")) {
          cfml.next();
              cfml.removeSpace();
              return new Not(decsionOp());
          }
        else if (cfml.forwardIfCurrentAndNoWordAfter("not")) {
              cfml.removeSpace();
              return new Not(decsionOp());
          }
      }
        return decsionOp();
    }

    /**
    * <font f>Transfomiert eine Vergleichs Operation.
    * <br />
    * EBNF:<br />
    * <code>concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"|
                     "contains"|"nct"|"does not contain") spaces concatOp};
            (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *)</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref decsionOp() throws PageException {

        Ref ref = concatOp();
        boolean hasChanged=false;
        // ct, contains
        if(cfml.isValidIndex()){
            do {
                hasChanged=false;
                if(cfml.isCurrent('c')) {
                        if (cfml.forwardIfCurrent("ct")) {
                            cfml.removeSpace();
                            ref=new CT(ref,concatOp());
                            hasChanged=true;
                        }
                        else if (cfml.forwardIfCurrent("contains")){
                            cfml.removeSpace();
                            ref=new CT(ref,concatOp());
                            hasChanged=true;
                        }
                }
                // does not contain
                else if (cfml.forwardIfCurrent("does","not","contain")){
                    cfml.removeSpace();
                    ref=new NCT(ref,concatOp());
                    hasChanged=true;
                }
               
                // equal, eq
                else if (cfml.isCurrent("eq") && !cfml.isCurrent("eqv")) {
                    cfml.setPos(cfml.getPos()+2);
                    cfml.forwardIfCurrent("ual");
                    cfml.removeSpace();
                    ref=new EQ(ref,concatOp());
                    hasChanged=true;
                }
                // ==
                else if (cfml.forwardIfCurrent("==")) {
                    if(cfml.forwardIfCurrent('='))     {
                      cfml.removeSpace();
                      ref = new EEQ(ref,concatOp());
                    }
            else {
              cfml.removeSpace();
                      ref=new EQ(ref,concatOp());
            }
                    hasChanged=true;
                }
               
                // !=
                else if (cfml.forwardIfCurrent("!=")) {
                    if(cfml.forwardIfCurrent('=')) {
                      cfml.removeSpace();
                      ref = new NEEQ(ref,concatOp());
                    }
            else {
              cfml.removeSpace();
                      ref=new NEQ(ref,concatOp());
            }
                    hasChanged=true;
                }

                // <=/</<>
          else if (cfml.forwardIfCurrent('<')) {
            if(cfml.forwardIfCurrent('='))     {
              cfml.removeSpace();
                      ref = new LTE(ref,concatOp());
            }
            else if(cfml.forwardIfCurrent('>')) {
              cfml.removeSpace();
                      ref = new NEQ(ref,concatOp());
            }
            else                 {
              cfml.removeSpace();
                      ref = new LT(ref,concatOp());
            }
            hasChanged=true;
          }
                // >/>=
          else if (cfml.forwardIfCurrent('>')) {
            if(cfml.forwardIfCurrent('='))     {
              cfml.removeSpace();
                      ref = new GTE(ref,concatOp());
            }
            else                 {
              cfml.removeSpace();
                      ref = new GT(ref,concatOp());
            }
            hasChanged=true;
          }
               
                // gt, gte, greater than or equal to, greater than
                else if (cfml.isCurrent('g')) {
                    if (cfml.forwardIfCurrent("gt")) {
                        if(cfml.forwardIfCurrent('e')) {
                            cfml.removeSpace();
                            ref=new GTE(ref,concatOp());
                        }
                        else {
                            cfml.removeSpace();
                            ref=new GT(ref,concatOp());
                        }
                        hasChanged=true;
                    }
                    else if (cfml.forwardIfCurrent("greater","than")) {
                        if(cfml.forwardIfCurrent("or" ,"equal", "to",true)) {
                            cfml.removeSpace();
                            ref=new GTE(ref,concatOp());
                        }
                        else {
                            cfml.removeSpace();
                            ref=new GT(ref,concatOp());
                        }
                        hasChanged=true;
                    }  
                    else if (cfml.forwardIfCurrent("ge")) {
                        cfml.removeSpace();
                        ref=new GTE(ref,concatOp());
                        hasChanged=true;
                    }              
                }
               
                // is, is not
                else if (cfml.forwardIfCurrent("is")) {
                    if(cfml.forwardIfCurrent("not",true)) {
                        cfml.removeSpace();
                        ref=new NEQ(ref,concatOp());
                    }
                    else {
                        cfml.removeSpace();
                        ref=new EQ(ref,concatOp());
                    }
                    hasChanged=true;
                }
               
                // lt, lte, less than, less than or equal to
                else if (cfml.isCurrent('l')) {
                    if (cfml.forwardIfCurrent("lt")) {
                        if(cfml.forwardIfCurrent('e')) {
                            cfml.removeSpace();
                            ref=new LTE(ref,concatOp());
                        }
                        else {
                            cfml.removeSpace();
                            ref=new LT(ref,concatOp());
                        }
                        hasChanged=true;
                    }
                    else if (cfml.forwardIfCurrent("less","than")) {
                        if(cfml.forwardIfCurrent("or", "equal", "to",true)) {
                            cfml.removeSpace();
                            ref=new LTE(ref,concatOp());
                        }
                        else {
                            cfml.removeSpace();
                            ref=new LT(ref,concatOp());
                        }
                        hasChanged=true;
                    }  
                    else if (cfml.forwardIfCurrent("le")) {
                        cfml.removeSpace();
                        ref=new LTE(ref,concatOp());
                        hasChanged=true;
                    }              
                }
               
                // neq, not equal, nct
                else if (cfml.isCurrent('n')) {
                    // Not Equal
                        if (cfml.forwardIfCurrent("neq"))   {
                            cfml.removeSpace();
                            ref=new NEQ(ref,concatOp());
                            hasChanged=true;
                        }
                    // Not Equal (Alias)
                        else if (cfml.forwardIfCurrent("not","equal")){
                            cfml.removeSpace();
                            ref=new NEQ(ref,concatOp());
                            hasChanged=true;
                        }
                    // nct
                        else if (cfml.forwardIfCurrent("nct"))  {
                            cfml.removeSpace();
                            ref=new NCT(ref,concatOp());
                            hasChanged=true;
                        }  
                }
            }while(hasChanged);
        }
        return ref;
    }

    /**
    * Transfomiert eine  Konkatinations-Operator (&) Operation. Im Gegensatz zu CFMX ,
    * wird das "!" Zeichen auch als Not Operator anerkannt.
    * <br />
    * EBNF:<br />
    * <code>plusMinusOp {"&" spaces concatOp};</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref concatOp() throws PageException {
        Ref ref = plusMinusOp();
       
        while(cfml.isCurrent('&') && !cfml.isNext('&')) {
            cfml.next();
            ref=_concat(ref);
            //cfml.removeSpace();
            //ref=new Concat(pc,ref,plusMinusOp());
        }
        return ref;
    }

    /**
    * Transfomiert die mathematischen Operatoren Plus und Minus (1,-).
    * <br />
    * EBNF:<br />
    * <code>modOp [("-"|"+") spaces plusMinusOp];</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref plusMinusOp() throws PageException {
        Ref ref = modOp();
       
        while(!cfml.isLast()) {
            // Plus Operation
            if (cfml.forwardIfCurrent('+')) {
                ref=_plus(ref);
              //cfml.removeSpace();
                //ref=new Plus(ref,modOp());
            }
            // Minus Operation
            else if (cfml.forwardIfCurrent('-')) {
                ref=_minus(ref);
              //cfml.removeSpace();
                //ref=new Minus(ref,modOp());
            }
            else break;
        }
        return ref;
    }

    private Ref _plus(Ref ref) throws PageException {
    // +=
    if (cfml.isCurrent('=')) {
      cfml.next();
      cfml.removeSpace();
      Ref right = assignOp();
      Ref res = preciseMath?new BigPlus(ref,right):new Plus(ref,right);
      ref=new Assign(ref,res);
    }
    /*/ ++
    else if (cfml.isCurrent('+')) {
      cfml.next();
      cfml.removeSpace();
      Ref res = new Plus(ref,new LNumber(new Double(1)));
      ref=new Assign(ref,res);
      ref=new Minus(ref,new LNumber(new Double(1)));
    }*/
    else
            cfml.removeSpace();
            ref=preciseMath?new BigPlus(ref,modOp()):new Plus(ref,modOp());
    }
    return ref;
  }
   
    private Ref _minus(Ref ref) throws PageException {
    // -=
    if (cfml.isCurrent('=')) {
      cfml.next();
      cfml.removeSpace();
      Ref right = assignOp();
      Ref res = preciseMath?new BigMinus(ref,right):new Minus(ref,right);
      ref=new Assign(ref,res);
    }
    /*/ --
    else if (cfml.isCurrent('-')) {
      cfml.next();
      cfml.removeSpace();
      Ref res = new Minus(ref,new LNumber(new Double(1)));
      ref=new Assign(ref,res);
      ref=new Plus(ref,new LNumber(new Double(1)));
    }*/
    else
            cfml.removeSpace();
            ref=preciseMath?new BigMinus(ref,modOp()):new Minus(ref,modOp());
    }
    return ref;
  }
   

    private Ref _div(Ref ref) throws PageException {
    // /=
    if (cfml.forwardIfCurrent('=')) {
      cfml.removeSpace();
      Ref right = assignOp();
      Ref res = preciseMath?new BigDiv(ref, right):new Div(ref,right);
      ref=new Assign(ref,res);
    }
    else
            cfml.removeSpace();
            ref=preciseMath?new BigDiv(ref,expoOp()):new Div(ref,expoOp());
    }
    return ref;
  }
   
    private Ref _intdiv(Ref ref) throws PageException {
    // \=
    if (cfml.forwardIfCurrent('=')) {
      cfml.removeSpace();
      Ref right = assignOp();
      Ref res = preciseMath?new BigIntDiv(ref,right):new IntDiv(ref,right);
      ref=new Assign(ref,res);
    }
    else
            cfml.removeSpace();
            ref=preciseMath?new BigIntDiv(ref,expoOp()):new IntDiv(ref,expoOp());
    }
    return ref;
  }

    private Ref _mod(Ref ref) throws PageException {
    // %=
    if (cfml.forwardIfCurrent('=')) {
      cfml.removeSpace();
      Ref right = assignOp();
      Ref res = preciseMath?new BigMod(ref,right):new Mod(ref,right);
      ref=new Assign(ref,res);
    }
    else
            cfml.removeSpace();
            ref=preciseMath?new BigMod(ref,divMultiOp()):new Mod(ref,divMultiOp());
    }
    return ref;
  }
    private Ref _concat(Ref ref) throws PageException {
    // &=
    if (cfml.forwardIfCurrent('=')) {
      cfml.removeSpace();
      Ref right = assignOp();
      Ref res = new  Concat(ref,right);
      ref=new Assign(ref,res);
    }
    else
            cfml.removeSpace();
            ref=new Concat(ref,plusMinusOp());
    }
    return ref;
  }
   
    private Ref _multi(Ref ref) throws PageException {
    // \=
    if (cfml.forwardIfCurrent('=')) {
      cfml.removeSpace();
      Ref right = assignOp();
      Ref res = preciseMath?new BigMulti(ref,right):new Multi(ref,right);
      ref=new Assign(ref,res);
    }
    else
            cfml.removeSpace();
            ref=preciseMath?new BigMulti(ref,expoOp()):new Multi(ref,expoOp());
    }
    return ref;
  }
   
   
   
   

    /**
    * Transfomiert eine Modulus Operation. Im Gegensatz zu CFMX ,
    * wird das "%" Zeichen auch als Modulus Operator anerkannt.
    * <br />
    * EBNF:<br />
    * <code>divMultiOp {("mod" | "%") spaces divMultiOp}; (* modulus operator , "%" Existiert in CFMX nicht *)</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref modOp() throws PageException {
        Ref ref = divMultiOp();
       
        while(cfml.isValidIndex() && (cfml.forwardIfCurrent('%') || cfml.forwardIfCurrent("mod"))) {
            ref=_mod(ref);
         
          //cfml.removeSpace();
            //ref=new Mod(ref,divMultiOp());
        }
        return ref;
    }

    /**
    * Transfomiert die mathematischen Operatoren Mal und Durch (*,/).
    * <br />
    * EBNF:<br />
    * <code>expoOp {("*"|"/") spaces expoOp};</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref divMultiOp() throws PageException {
        Ref ref = expoOp();

        while (!cfml.isLast()) {
            // Multiply Operation
            if(cfml.forwardIfCurrent('*')) {
                ref=_multi(ref);
              //cfml.removeSpace();
                //ref=new Multi(ref,expoOp());
            }
            // Divide Operation
            else if (cfml.isCurrent('/') && (!cfml.isCurrent("/>") )) {
                cfml.next();
                ref=_div(ref);
                //cfml.removeSpace();
                //ref=new Div(ref,expoOp());
            }
            // Divide Operation
            else if (cfml.isCurrent('\\')) {
                cfml.next();
                ref=_intdiv(ref);
                //cfml.removeSpace();
                //ref=new IntDiv(ref,expoOp());
            }
            else {
                break;
            }
        }
        return ref;
    }

    /**
    * Transfomiert den Exponent Operator (^,exp). Im Gegensatz zu CFMX ,
    * werden die Zeichen " exp " auch als Exponent anerkannt.
    * <br />
    * EBNF:<br />
    * <code>clip {("exp"|"^") spaces clip};</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref expoOp() throws PageException {
        Ref ref = unaryOp();

        while(cfml.isValidIndex() && (cfml.forwardIfCurrent('^') || cfml.forwardIfCurrent("exp"))) {
            cfml.removeSpace();
            ref=new Exp(ref,unaryOp());
        }
        return ref;
    }
   

    private Ref unaryOp() throws PageException {
        Ref ref = negateMinusOp();
       
    if (cfml.forwardIfCurrent("--"))
      ref=_unaryOp(ref, false);
   
    else if (cfml.forwardIfCurrent("++"))
      ref=_unaryOp(ref, true);
    return ref;
  }
   
    private Ref _unaryOp(Ref ref,boolean isPlus) throws PageException {
        cfml.removeSpace();
    Ref res = preciseMath?new BigPlus(ref,isPlus?PLUS_ONE:MINUS_ONE):new Plus(ref,isPlus?PLUS_ONE:MINUS_ONE);
    ref=new Assign(ref,res);
    return preciseMath?new BigPlus(ref,isPlus?MINUS_ONE:PLUS_ONE):new Plus(ref,isPlus?MINUS_ONE:PLUS_ONE);
  }
   

    /**
    * Liest die Vordlobe einer Zahl ein
    * @return CFXD Element
    * @throws PageException
    */
    private Ref negateMinusOp() throws PageException {
        // And Operation
        if (cfml.forwardIfCurrent('-')) {
          if (cfml.forwardIfCurrent('-')) {
            cfml.removeSpace();
        Ref expr = clip();
        Ref res = preciseMath?new BigMinus(expr,new LNumber(new Double(1))):new Minus(expr,new LNumber(new Double(1)));
        return new Assign(expr,res);
     
            cfml.removeSpace();
            return new Negate(clip());
         
        }
        if (cfml.forwardIfCurrent('+')) {
          if (cfml.forwardIfCurrent('+')) {
            cfml.removeSpace();
        Ref expr = clip();
        Ref res = preciseMath?new BigPlus(expr,new LNumber(new Double(1))):new Plus(expr,new LNumber(new Double(1)));
        return new Assign(expr,res);
      }
          cfml.removeSpace();
          return new Casting("numeric",CFTypes.TYPE_NUMERIC,clip());
         
        }
        return clip();
    }

    /**
    * Verarbeitet Ausdrcke die inerhalb einer Klammer stehen.
    * <br />
    * EBNF:<br />
    * <code>("(" spaces impOp ")" spaces) | checker;</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref clip() throws PageException {
        return checker();
    }
   
    /**
    * Hier werden die verschiedenen M￶glichen Werte erkannt
    * und jenachdem wird mit der passenden Methode weitergefahren
    * <br />
    * EBNF:<br />
    * <code>string | number | dynamic | sharp;</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref checker() throws PageException {
       
        Ref ref=null
        // String
            if(cfml.isCurrentQuoter()) {
                // mode=STATIC; is at the end of the string function because must set after execution
                return string();
            }
        // Number
            if(cfml.isCurrentDigit() || cfml.isCurrent('.')) {
                // mode=STATIC; is at the end of the string function because must set after execution
                return number();
            }
        // Dynamic
            if((ref=dynamic())!=null) {
                mode=DYNAMIC;
                return ref;
            }
        // Sharp
            if((ref=sharp())!=null) {
                mode=DYNAMIC;
                return ref;
           
        // JSON
            if((ref=json(JSON_ARRAY,'[',']'))!=null) {
        mode=DYNAMIC;
        return ref;
      }
      if((ref=json(JSON_STRUCT,'{','}'))!=null) {
        mode=DYNAMIC;
        return ref;
      }
           
      if(cfml.isAfterLast() && cfml.toString().trim().length()==0)
        return new LString("");
           
        // else Error
      String str=cfml.toString();
      int pos=cfml.getPos();
      if(str.length()>100) {
        // Failure is in the beginning
        if(pos<=10) {
          str=str.substring(0,20)+" ...";
        }
        // Failure is in the end
        else if((str.length()-pos)<=10) {
          str="... "+str.substring(str.length()-20,str.length());
        }
        else {
          str="... "+str.substring(pos-10,pos+10)+" ...";
        }
      }
      throw new InterpreterException("Syntax Error, Invalid Construct","at position "+(pos+1)+" in ["+str+"]")
    }
   
   
    protected Ref json(FunctionLibFunction flf, char start, char end) throws PageException {
    //print.out("start:"+start+":"+cfml.getCurrent());
    if(!cfml.isCurrent(start))return null;
   
    Ref[] args = functionArg(flf.getName(), false, flf,end);
   
    //if (!cfml.forwardIfCurrent(end))
    //  throw new InterpreterException("Invalid Syntax Closing ["+end+"] not found");
   
    return new BIFCall(flf,args);
  }
   
    /**
    * Transfomiert einen lierale Zeichenkette.
    * <br />
    * EBNF:<br />
    * <code>("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") |
                     (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """);</code>
    * @return CFXD Element
    * @throws PageException
    */
    protected Ref string() throws PageException {
                       
        // Init Parameter
        char quoter = cfml.getCurrentLower();
        //String str="";
        LStringBuffer str=new LStringBuffer();
        Ref value=null;
       
        while(cfml.hasNext()) {
            cfml.next();
            // check sharp
            if(cfml.isCurrent('#')) {
                if(cfml.isNext('#')){
                    cfml.next();
                    str.append('#');
                }
                else {
                    cfml.next();
                    cfml.removeSpace();
                    if(!str.isEmpty() || value!=null) str.append(assignOp());
                    else value=assignOp();
                    cfml.removeSpace();
                    if (!cfml.isCurrent('#')) throw new InterpreterException("Invalid Syntax Closing [#] not found");
                }
            }
            else if(cfml.isCurrent(quoter)) {
                if(cfml.isNext(quoter)){
                    cfml.next();
                    str.append(quoter);
                }
                else {
                    break;
                }              
            }
            // all other character
            else {
                str.append(cfml.getCurrent());
            }
        }
        if(!cfml.forwardIfCurrent(quoter))
            throw new InterpreterException("Invalid String Literal Syntax Closing ["+quoter+"] not found");
       
        cfml.removeSpace();
        mode=STATIC;
        if(value!=null) {
            if(str.isEmpty()) return value;
            return new Concat(value,str);
        }
        return str;
    }

    /**
    * Transfomiert einen numerische Wert.
    * Die L¦nge des numerischen Wertes interessiert nicht zu ᅵbersetzungszeit,
    * ein "Overflow" fhrt zu einem Laufzeitfehler.
    * Da die zu erstellende CFXD, bzw. dieser Transfomer, keine Vorwegnahme des Laufzeitsystems vornimmt.
    * <br />
    * EBNF:<br />
    * <code>["+"|"-"] digit {digit} {"." digit {digit}};</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref number() throws PageException {
        // check first character is a number literal representation
        //if(!cfml.isCurrentDigit()) return null;
       
        StringBuilder rtn=new StringBuilder(6);
       
        // get digit on the left site of the dot
        if(cfml.isCurrent('.')) rtn.append('0');
        else digit(rtn);
        // read dot if exist
        if(cfml.forwardIfCurrent('.')) {
            rtn.append('.');
            int before=cfml.getPos();
            digit(rtn);

            if(before<cfml.getPos() && cfml.forwardIfCurrent('e')) {
              Boolean expOp=null;
        if(cfml.forwardIfCurrent('+')) expOp=Boolean.TRUE;
        else if(cfml.forwardIfCurrent('-')) expOp=Boolean.FALSE;
       
             
              if(cfml.isCurrentDigit()) {
                if(expOp==Boolean.FALSE) rtn.append("e-");
          else if(expOp==Boolean.TRUE) rtn.append("e+");
          else rtn.append('e');
                    digit(rtn);
                }
                else {
                  if(expOp!=null) cfml.previous();
              cfml.previous();
                }
            }
           
           
            // read right side of the dot
            if(before==cfml.getPos())
                throw new InterpreterException("Number can't end with [.]");
            //rtn.append(rightSite);
        }
        cfml.removeSpace();
        mode=STATIC;
        return new LNumber(rtn.toString());
       
    }
   
    /**
    * Liest die reinen Zahlen innerhalb des CFMLString aus und gibt diese als Zeichenkette zurck.
    * <br />
    * EBNF:<br />
    * <code>"0"|..|"9";</code>
     * @param rtn
    */
    private void digit(StringBuilder rtn) {
       
        while (cfml.isValidIndex()) {
            if(!cfml.isCurrentDigit())break;
            rtn.append(cfml.getCurrentLower());
            cfml.next();
        }
    }

    /**
    * Liest den folgenden idetifier ein und prft ob dieser ein boolscher Wert ist.
    * Im Gegensatz zu CFMX wird auch "yes" und "no" als bolscher <wert akzeptiert,
    * was bei CFMX nur beim Umwandeln einer Zeichenkette zu einem boolschen Wert der Fall ist.<br />
    * Wenn es sich um keinen bolschen Wert handelt wird der folgende Wert eingelesen mit seiner ganzen Hirarchie.
    * <br />
    * EBNF:<br />
    * <code>"true" | "false" | "yes" | "no" | startElement 
                     {("." identifier | "[" structElement "]" )[function] };</code>
    * @return CFXD Element
    * @throws PageException
    */
    private Ref dynamic() throws PageException {
        // Die Implementation weicht ein wenig von der Grammatik ab,
        // aber nicht in der Logik sondern rein wie es umgesetzt wurde.
       
        // get First Element of the Variable
        String name = identifier(false);
        if(name == null) {
            if (!cfml.forwardIfCurrent('('))return null;
            cfml.removeSpace();
            Ref ref = assignOp();

            if (!cfml.forwardIfCurrent(')'))
                throw new InterpreterException("Invalid Syntax Closing [)] not found");
            cfml.removeSpace();
            return subDynamic(ref);
        }

        //Element el;
        cfml.removeSpace();
        //char first=name.charAt(0);
       
        // Boolean constant
        if(name.equalsIgnoreCase("TRUE"))   {
            cfml.removeSpace();
            return LBoolean.TRUE;
        }
        else if(name.equalsIgnoreCase("FALSE")) {
            cfml.removeSpace();
            return LBoolean.FALSE;
        }  
        else if(name.equalsIgnoreCase("YES"))   {
            cfml.removeSpace();
            return LBoolean.TRUE;
        }
        else if(name.equalsIgnoreCase("NO")){
        cfml.removeSpace();
        return LBoolean.FALSE;
      }
      else if(allowNullConstant && name.equalsIgnoreCase("NULL")){
        cfml.removeSpace();
        return new  LString(null);
      }
      else if(name.equalsIgnoreCase("NEW")){
        Ref res = newOp();
        if(res!=null) return res;
     
       
       
       
        // Extract Scope from the Variable

        //Object value = startElement(name);
        return subDynamic(startElement(name));

    }
   
    private Ref subDynamic(Ref ref) throws PageException {
        String name=null;
       
        // Loop over nested Variables
        while (cfml.isValidIndex()) {
            // .
            if (cfml.forwardIfCurrent('.')) {
                // Extract next Var String
                cfml.removeSpace();
                name = identifier(true);
                if(name==null) throw new InterpreterException("Invalid identifier");
                cfml.removeSpace();
                ref=new Variable(ref,name);
            }
            // []
            else if (cfml.forwardIfCurrent('[')) {
              cfml.removeSpace();
                ref=new Variable(ref,assignOp());
                cfml.removeSpace();
                if (!cfml.forwardIfCurrent(']'))
                    throw new InterpreterException("Invalid Syntax Closing []] not found");
            }
            // finish
            else {
                break;
            }

            cfml.removeSpace();
           
            if (cfml.isCurrent('(')) {
                if(!(ref instanceof Set)) throw new InterpreterException("invalid syntax "+ref.getTypeName()+" can't called as function");
                Set set=(Set) ref;
                ref=new UDFCall(set.getParent(pc),set.getKey(pc),functionArg(name,false, null,')'));
            }
        }
        if(ref instanceof railo.runtime.interpreter.ref.var.Scope) {
            railo.runtime.interpreter.ref.var.Scope s=(railo.runtime.interpreter.ref.var.Scope)ref;
            if(s.getScope()==Scope.SCOPE_ARGUMENTS || s.getScope()==Scope.SCOPE_LOCAL || s.getScope()==ScopeSupport.SCOPE_VAR) {
                ref=new Bind(s);
            }
        }
        return ref;
    }

    /**
    * Extrahiert den Start Element einer Variale,
    * dies ist entweder eine Funktion, eine Scope Definition oder eine undefinierte Variable.
    * <br />
    * EBNF:<br />
    * <code>identifier "(" functionArg ")" | scope | identifier;</code>
    * @param name Einstiegsname
    * @return CFXD Element
    * @throws PageException
    */
    private Ref startElement(String name) throws PageException {
       
        // check function
        if (cfml.isCurrent('(')) {
            FunctionLibFunction function = fld.getFunction(name);
            Ref[] arguments = functionArg(name,true, function,')');
          //print.out(name+":"+(function!=null));
            if(function!=null) return new BIFCall(function,arguments);

            Ref ref = new railo.runtime.interpreter.ref.var.Scope(Scope.SCOPE_UNDEFINED);
            return new UDFCall(ref,name,arguments);
        }
        //check scope
        return scope(name);
    }
   
  private Ref newOp() throws PageException {
   
    int start=cfml.getPos();
      String name=null;
      cfml.removeSpace();
     
      // first identifier
      name = identifier(true);
    Ref refName=null;
    if(name!=null) {
      StringBuilder fullName=new StringBuilder();
      fullName.append(name);
      // Loop over addional identifier
      while (cfml.isValidIndex()) {
        if (cfml.forwardIfCurrent('.')) {
                  cfml.removeSpace();
                  name = identifier(true);
                  if(name==null) throw new InterpreterException("invalid Component declaration");
                  cfml.removeSpace();
          fullName.append('.');
          fullName.append(name);
              }
        else break;
      }
      refName=new LString(fullName.toString());
    }
    else {
      if(cfml.isCurrentQuoter())refName=string();
      if(refName==null){
        cfml.setPos(start);
        return null;
      }
    }
    cfml.removeSpace();
       
        if (cfml.isCurrent('(')) {
          FunctionLibFunction function = fld.getFunction("_createComponent");
            Ref[] arguments = functionArg("_createComponent",true, function,')');
            Ref[] args=new Ref[arguments.length+1];
            for(int i=0;i<arguments.length;i++){
              args[i]=arguments[i];
            }
            args[args.length-1]=refName;
            BIFCall bif = new BIFCall(function,args);
          cfml.removeSpace();
          return bif;
         
     
     
    }
        throw new InterpreterException("invalid Component declaration ");
   
  }
   
   
   
   
    /**
    * Liest einen CFML Scope aus,
    * falls der folgende identifier keinem Scope entspricht,
    * gibt die Variable null zurck.
    * <br />
    * EBNF:<br />
    * <code>"variable" | "cgi" | "url" | "form" | "session" | "application" | "arguments" | "cookie" | " client";</code>
     * @param idStr String identifier,
     * wird aus Optimierungszwechen nicht innerhalb dieser Funktion ausgelsen.
     * @return CFXD Variable Element oder null
    */
    private Ref scope(String idStr) {
        if (idStr.equals("var")) {
            String name=identifier(false);
            if(name!=null){
                cfml.removeSpace();
                return new Variable(new railo.runtime.interpreter.ref.var.Scope(ScopeSupport.SCOPE_VAR),name);
            }
        }
        int scope = VariableInterpreter.scopeString2Int(idStr);
        if(scope==Scope.SCOPE_UNDEFINED) {
            return new Variable(new railo.runtime.interpreter.ref.var.Scope(Scope.SCOPE_UNDEFINED),idStr);
        }
        return new railo.runtime.interpreter.ref.var.Scope(scope);
       
    }
   
    /**
    * Liest einen Identifier aus und gibt diesen als String zurck.
    * <br />
    * EBNF:<br />
    * <code>(letter | "_") {letter | "_"|digit};</code>
     * @param firstCanBeNumber
    * @return Identifier.
    */
    private String identifier(boolean firstCanBeNumber) {
        //int start = cfml.getPos();
        if(!cfml.isCurrentLetter() && !cfml.isCurrentSpecial()) {
            if(!firstCanBeNumber)return null;
            else if(!cfml.isCurrentDigit())return null;
        }
       
        boolean doUpper = !isJson && ((ConfigWebImpl)pc.getConfig()).getDotNotationUpperCase();
        StringBuilder sb=new StringBuilder();
        sb.append(doUpper?cfml.getCurrentUpper():cfml.getCurrent());
        do {
            cfml.next();
            if(!(cfml.isCurrentLetter()
                || cfml.isCurrentDigit()
                || cfml.isCurrentSpecial())) {
                    break;
                }

            sb.append(doUpper?cfml.getCurrentUpper():cfml.getCurrent());
        }
        while (cfml.isValidIndex());
        return sb.toString();//cfml.substringLower(start,cfml.getPos()-start);
    }

    /* *
    * Transfomiert ein Collection Element das in eckigen Klammern aufgerufen wird.
    * <br />
    * EBNF:<br />
    * <code>"[" impOp "]"</code>
    * @return CFXD Element
    * @throws PageException
    * /
    private Ref structElement() throws PageException {
        cfml.removeSpace();
        Ref ref = new Casting(pc,"string",CFTypes.TYPE_STRING,assignOp());
        cfml.removeSpace();
        return ref;
    }*/

    /**
    * Liest die Argumente eines Funktonsaufruf ein und prft ob die Funktion
    * innerhalb der FLD (Function Library Descriptor) definiert ist.
    * Falls sie existiert wird die Funktion gegen diese geprft und ein build-in-function CFXD Element generiert,
    * ansonsten ein normales funcion-call Element.
    * <br />
    * EBNF:<br />
    * <code>[impOp{"," impOp}];</code>
    * @param name Identifier der Funktion als Zeichenkette
    * @param checkLibrary Soll geprft werden ob die Funktion innerhalb der Library existiert.
    * @param flf FLD Function definition .
    * @return CFXD Element
    * @throws PageException
    */
    private Ref[] functionArg(String name,boolean checkLibrary,FunctionLibFunction flf,char end) throws PageException {

        // get Function Library
        checkLibrary=checkLibrary && flf!=null;    
       

        // Function Attributes
        ArrayList arr = new ArrayList();
       
        ArrayList arrFuncLibAtt = null;
        int libLen = 0;
        if (checkLibrary) {
            arrFuncLibAtt = flf.getArg();
            libLen = arrFuncLibAtt.size();
        }
        int count = 0;
        Ref ref;
        do {
            cfml.next();
            cfml.removeSpace();

            // finish
            if (cfml.isCurrent(end))
                break;

            // too many Attributes
            boolean isDynamic=false;
            int max=-1;
            if(checkLibrary) {
                isDynamic=isDynamic(flf);
                max=flf.getArgMax();
            // Dynamic
                if(isDynamic) {
                    if(max!=-1 && max <= count)
                        throw new InterpreterException("too many Attributes in function [" + name + "]");
                }
            // Fix
                else {
                    if(libLen <= count)
                        throw new InterpreterException("too many Attributes in function [" + name + "]");
                }
            }

           
            if (checkLibrary && !isDynamic) {
                // current attribues from library
                FunctionLibFunctionArg funcLibAtt = (FunctionLibFunctionArg) arrFuncLibAtt.get(count);
                short type=CFTypes.toShort(funcLibAtt.getTypeAsString(),false,CFTypes.TYPE_UNKNOW);
                if(type==CFTypes.TYPE_VARIABLE_STRING) {
                    arr.add(functionArgDeclarationVarString());
                }
                else {
                  ref = functionArgDeclaration();
                  arr.add(new Casting(funcLibAtt.getTypeAsString(),type,ref));
                }
            }
            else {
                arr.add(functionArgDeclaration());
            }

            // obj=andOrXor();
            cfml.removeSpace();
            count++;
        }
        while (cfml.isCurrent(','));

        // end with ) ??       
        if (!cfml.forwardIfCurrent(end)) {
            if(name.startsWith("_json")) throw new InterpreterException("Invalid Syntax Closing ["+end+"] not found");
            throw new InterpreterException("Invalid Syntax Closing ["+end+"] for function ["+ name + "] not found");
        }

        // check min attributes
        if (checkLibrary && flf.getArgMin() > count)
            throw new InterpreterException("to less Attributes in function [" + name + "]");

        cfml.removeSpace();
        return (Ref[]) arr.toArray(new Ref[arr.size()]);
    }
   
    private boolean isDynamic(FunctionLibFunction flf) {
        return flf.getArgType()==FunctionLibFunction.ARG_DYNAMIC;
    }
   
    /**
     * Sharps (#) die innerhalb von Expressions auftauchen haben in CFML keine weitere Beteutung
     * und werden durch diese Methode einfach entfernt.
     * <br />
     * Beispiel:<br />
     * <code>arrayLen(#arr#)</code> und <code>arrayLen(arr)</code> sind identisch.
     * EBNF:<br />
     * <code>"#" checker "#";</code>
     * @return CFXD Element
     * @throws PageException
    */
    private Ref sharp() throws PageException {
        if(!cfml.forwardIfCurrent('#'))
            return null;
        Ref ref;
        cfml.removeSpace();
        ref = assignOp();
        cfml.removeSpace();
        if (!cfml.forwardIfCurrent('#'))
            throw new InterpreterException("Syntax Error, Invalid Construct");
        cfml.removeSpace();
        return ref;
    }

    /* *
     * Wandelt eine variable und ein key in eine reference um
     * @param value
     * @param name
     * @return cast a vlue in a reference
     * @throws PageException
     * /
    private Reference toReference(Object value, String name) {
        return NativeReference.getInstance(value, name);
    }*/
   
}
TOP

Related Classes of railo.runtime.interpreter.CFMLExpressionInterpreter

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.