001    package railo.runtime.interpreter;
002    
003    import java.util.ArrayList;
004    import java.util.Map;
005    import java.util.WeakHashMap;
006    
007    import org.apache.commons.collections.map.ReferenceMap;
008    
009    import railo.commons.lang.CFTypes;
010    import railo.commons.lang.ParserString;
011    import railo.runtime.PageContext;
012    import railo.runtime.config.ConfigImpl;
013    import railo.runtime.exp.ExpressionException;
014    import railo.runtime.exp.PageException;
015    import railo.runtime.interpreter.ref.Ref;
016    import railo.runtime.interpreter.ref.Set;
017    import railo.runtime.interpreter.ref.cast.Casting;
018    import railo.runtime.interpreter.ref.func.BIFCall;
019    import railo.runtime.interpreter.ref.func.UDFCall;
020    import railo.runtime.interpreter.ref.literal.LBoolean;
021    import railo.runtime.interpreter.ref.literal.LFunctionValue;
022    import railo.runtime.interpreter.ref.literal.LNumber;
023    import railo.runtime.interpreter.ref.literal.LString;
024    import railo.runtime.interpreter.ref.literal.LStringBuffer;
025    import railo.runtime.interpreter.ref.literal.Literal;
026    import railo.runtime.interpreter.ref.op.And;
027    import railo.runtime.interpreter.ref.op.BigDiv;
028    import railo.runtime.interpreter.ref.op.BigIntDiv;
029    import railo.runtime.interpreter.ref.op.BigMinus;
030    import railo.runtime.interpreter.ref.op.BigMod;
031    import railo.runtime.interpreter.ref.op.BigMulti;
032    import railo.runtime.interpreter.ref.op.BigPlus;
033    import railo.runtime.interpreter.ref.op.CT;
034    import railo.runtime.interpreter.ref.op.Concat;
035    import railo.runtime.interpreter.ref.op.Cont;
036    import railo.runtime.interpreter.ref.op.Div;
037    import railo.runtime.interpreter.ref.op.EEQ;
038    import railo.runtime.interpreter.ref.op.EQ;
039    import railo.runtime.interpreter.ref.op.EQV;
040    import railo.runtime.interpreter.ref.op.Exp;
041    import railo.runtime.interpreter.ref.op.GT;
042    import railo.runtime.interpreter.ref.op.GTE;
043    import railo.runtime.interpreter.ref.op.Imp;
044    import railo.runtime.interpreter.ref.op.IntDiv;
045    import railo.runtime.interpreter.ref.op.LT;
046    import railo.runtime.interpreter.ref.op.LTE;
047    import railo.runtime.interpreter.ref.op.Minus;
048    import railo.runtime.interpreter.ref.op.Mod;
049    import railo.runtime.interpreter.ref.op.Multi;
050    import railo.runtime.interpreter.ref.op.NCT;
051    import railo.runtime.interpreter.ref.op.NEEQ;
052    import railo.runtime.interpreter.ref.op.NEQ;
053    import railo.runtime.interpreter.ref.op.Negate;
054    import railo.runtime.interpreter.ref.op.Not;
055    import railo.runtime.interpreter.ref.op.Or;
056    import railo.runtime.interpreter.ref.op.Plus;
057    import railo.runtime.interpreter.ref.op.Xor;
058    import railo.runtime.interpreter.ref.var.Assign;
059    import railo.runtime.interpreter.ref.var.Bind;
060    import railo.runtime.interpreter.ref.var.DynAssign;
061    import railo.runtime.interpreter.ref.var.Variable;
062    import railo.runtime.type.Scope;
063    import railo.runtime.type.scope.ScopeSupport;
064    import railo.transformer.library.function.FunctionLib;
065    import railo.transformer.library.function.FunctionLibFunction;
066    import railo.transformer.library.function.FunctionLibFunctionArg;
067    
068    /**
069     * 
070     * 
071        Der CFMLExprTransfomer implementiert das Interface ExprTransfomer, 
072        er bildet die Parser Grammatik ab, die unten definiert ist. 
073        Er erh¦lt als Eingabe CFML Code, als String oder CFMLString, 
074        der einen CFML Expression erh¦lt und liefert ein CFXD Element zurck, 
075        das diesen Ausdruck abbildet.
076        Mithilfe der FunctionLibメs, kann er Funktionsaufrufe, 
077        die Teil eines Ausdruck sein k￶nnen, erkennen und validieren. 
078        Dies geschieht innerhalb der Methode function.
079        Falls ein Funktionsaufruf, einer Funktion innerhalb einer FunctionLib entspricht, 
080        werden diese gegeneinander verglichen und der Aufruf wird als Build-In-Funktion bernommen, 
081        andernfalls wird der Funktionsaufruf als User-Defined-Funktion interpretiert.
082        Die Klasse Cast, Operator und ElementFactory (siehe 3.2) helfen ihm beim erstellen des Ausgabedokument CFXD.
083    
084     * <pre>
085     * Parser Grammatik EBNF (Extended Backus-Naur Form) 
086    
087        transform      = spaces impOp;
088        impOp          = eqvOp {"imp" spaces eqvOp};
089        eqvOp          = xorOp {"eqv" spaces xorOp};
090        xorOp          = orOp {"xor" spaces  orOp};
091        orOp           = andOp {("or" | "||") spaces andOp}; 
092                (* "||" Existiert in CFMX nicht *)
093        andOp          = notOp {("and" | "&&") spaces notOp}; 
094                (* "&&" Existiert in CFMX nicht *) 
095        notOp          = [("not"|"!") spaces] decsionOp; 
096                (* "!" Existiert in CFMX nicht *)
097        decsionOp      = concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"|
098                         "contains"|"nct"|"does not contain") spaces concatOp}; 
099                (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *)
100        concatOp       = plusMinusOp {"&" spaces plusMinusOp};
101        plusMinusOp    = modOp {("-"|"+") spaces modOp};
102        
103        modOp          = divMultiOp {("mod" | "%") spaces divMultiOp}; 
104                        (* modulus operator , "%" Existiert in CFMX nicht *)
105        divMultiOp     = expoOp {("*"|"/") spaces expoOp};
106        expoOp         = clip {("exp"|"^") spaces clip}; 
107                        (*exponent operator, " exp " Existiert in CFMX nicht *)
108        clip           = ("(" spaces impOp ")" spaces) | checker;
109        checker        = string | number | dynamic | sharp;
110        string         = ("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") | 
111                         (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """);
112        number         = ["+"|"-"] digit {digit} {"." digit {digit}};
113        digit          = "0"|..|"9";
114        dynamic        = "true" | "false" | "yes" | "no" | startElement  
115                         {("." identifier | "[" structElement "]")[function] };
116        startElement   = identifier "(" functionArg ")" | scope | identifier;
117        scope          = "variable" | "cgi" | "url" | "form" | "session" | "application" | 
118                         "arguments" | "cookie" | " client";
119        identifier     = (letter | "_") {letter | "_"|digit};
120        structElement  = "[" impOp "]";
121        functionArg    = [impOp{"," impOp}];
122        sharp          = "#" checker "#";
123        spaces         = {space};
124        space          = "\s"|"\t"|"\f"|"\t"|"\n";
125        letter         = "a"|..|"z"|"A"|..|"Z";
126    
127    {"x"}= 0 bis n mal "x"
128    ["x"]= 0 bis 1 mal "x"
129    ("x" | "y")"z" = "xz" oder "yz"
130    
131    </pre>
132     *
133     */
134    public class CFMLExpressionInterpreter {
135    
136    
137        private static final LNumber PLUS_ONE = new LNumber(new Double(1));
138        private static final LNumber MINUS_ONE = new LNumber(new Double(-1));
139            
140        protected static final short STATIC=0;
141        private static final short DYNAMIC=1;
142            private static FunctionLibFunction JSON_ARRAY = null;
143            private static FunctionLibFunction JSON_STRUCT = null;
144            
145    
146            //private static final int CASE_TYPE_UPPER = 0;
147            //private static final int CASE_TYPE_LOWER = 1;
148            //private static final int CASE_TYPE_ORIGINAL = 2;
149            
150        protected short mode=0;
151        
152        protected ParserString cfml;
153        //protected Document doc;
154        //protected FunctionLib[] fld;
155        protected PageContext pc;
156        private FunctionLib fld;
157            protected boolean allowNullConstant=false;
158            private boolean preciseMath;
159            
160        private final static Map<String,Ref> data=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT);
161            
162    
163             
164        public Object interpret(PageContext pc,String str) throws PageException {
165            return interpret(pc,str,false);
166        }
167        
168    
169        public Object interpret(PageContext pc,String str, boolean preciseMath) throws PageException { 
170            //Ref ref = data.get(str+":"+preciseMath);
171            //if(ref!=null)return ref.getValue();
172            
173            this.cfml=new ParserString(str);
174            this.preciseMath = preciseMath;
175            this.pc=pc;
176            if(pc!=null)fld=((ConfigImpl)pc.getConfig()).getCombinedFLDs();
177            
178            if(JSON_ARRAY==null)JSON_ARRAY=fld.getFunction("_jsonArray");
179                    if(JSON_STRUCT==null)JSON_STRUCT=fld.getFunction("_jsonStruct");
180            
181            cfml.removeSpace();
182            Ref ref = assignOp();
183            cfml.removeSpace();
184            
185            if(cfml.isAfterLast()) {
186                    //data.put(str+":"+preciseMath,ref);
187                return ref.getValue();
188            }
189            throw new ExpressionException("Syntax Error, invalid Expression ["+cfml.toString()+"]");
190        }
191    
192        
193        /*private FunctionLibFunction getFLF(String name) {
194                    FunctionLibFunction flf=null;
195                    for (int i = 0; i < flds.length; i++) {
196                            flf = flds[i].getFunction(name);
197                            if (flf != null)
198                                    break;
199                    }
200                    return flf;
201            }*/
202        
203        
204        protected Object interpretPart(PageContext pc,ParserString cfml) throws PageException { 
205            this.cfml = cfml;
206            this.pc=pc;
207            if(pc!=null)fld=((ConfigImpl)pc.getConfig()).getCombinedFLDs();
208            
209            cfml.removeSpace();
210            return assignOp().getValue();
211        }
212    
213        /**
214        * Liest einen gelableten  Funktionsparamter ein
215        * <br />
216        * EBNF:<br />
217        * <code>assignOp [":" spaces assignOp];</code>
218        * @return CFXD Element
219        * @throws PageException 
220        */
221        private Ref functionArgDeclarationVarString() throws PageException {
222            
223                cfml.removeSpace();
224                StringBuffer str=new StringBuffer();
225                String id=null;
226                while((id=identifier(false))!=null) {
227                    if(str.length()>0)str.append('.');
228                    str.append(id);
229                    cfml.removeSpace();
230                    if(!cfml.forwardIfCurrent('.')) break;
231                    cfml.removeSpace();
232                }
233                cfml.removeSpace();
234                if(str.length()>0 && cfml.charAt(cfml.getPos()-1)!='.') 
235                    return new LString(str.toString());
236    
237            throw new ExpressionException("invalid variable name definition");
238        }
239    
240        /**
241        * Liest einen gelableten  Funktionsparamter ein
242        * <br />
243        * EBNF:<br />
244        * <code>assignOp [":" spaces assignOp];</code>
245        * @return CFXD Element
246        * @throws PageException 
247        */
248        private Ref functionArgDeclaration() throws PageException {
249            Ref ref = impOp();
250            if (cfml.forwardIfCurrent(':') || cfml.forwardIfCurrent('=')) {
251                cfml.removeSpace();
252                ref=new LFunctionValue(ref,assignOp());
253            }
254            return ref;
255        }
256    
257        /**
258        * Transfomiert Zuweisungs Operation.
259        * <br />
260        * EBNF:<br />
261        * <code>eqvOp ["=" spaces assignOp];</code>
262        * @return CFXD Element
263        * @throws PageException 
264        */
265        protected Ref assignOp() throws PageException {
266            Ref ref = contOp();
267    
268            if (cfml.forwardIfCurrent('=')) {
269                cfml.removeSpace();
270                if(mode==STATIC || ref instanceof Literal) {
271                    ref=new DynAssign(pc,ref,assignOp());
272                }
273                else {
274                    ref=new Assign(ref,assignOp());
275                }
276            }
277            return ref;
278        }
279        
280    
281        private Ref contOp() throws PageException {
282            Ref ref = impOp();
283            while(cfml.forwardIfCurrent('?')) {
284                cfml.removeSpace();
285                Ref left = assignOp();            
286                if(!cfml.forwardIfCurrent(':'))
287                    throw new ExpressionException("Syntax Error, invalid conditional operator ["+cfml.toString()+"]");
288                cfml.removeSpace();
289                Ref right = assignOp();
290                ref=new Cont(ref,left,right);
291            }
292            return ref;
293        }
294    
295        /**
296        * Transfomiert eine Implication (imp) Operation.
297        * <br />
298        * EBNF:<br />
299        * <code>eqvOp {"imp" spaces eqvOp};</code>
300        * @return CFXD Element
301        * @throws PageException 
302        */
303        private Ref impOp() throws PageException {
304            Ref ref = eqvOp();
305            while(cfml.forwardIfCurrentAndNoWordAfter("imp")) {
306                cfml.removeSpace();
307                ref=new Imp(ref,eqvOp());
308            }
309            return ref;
310        }
311    
312        /**
313        * Transfomiert eine  Equivalence (eqv) Operation.
314        * <br />
315        * EBNF:<br />
316        * <code>xorOp {"eqv" spaces xorOp};</code>
317        * @return CFXD Element
318        * @throws PageException 
319        */
320        private Ref eqvOp() throws PageException {
321            Ref ref = xorOp();
322            while(cfml.forwardIfCurrent("eqv")) {
323                cfml.removeSpace();
324                ref=new EQV(ref,xorOp());
325            }
326            return ref;
327        }
328    
329        /**
330        * Transfomiert eine  Xor (xor) Operation.
331        * <br />
332        * EBNF:<br />
333        * <code>orOp {"xor" spaces  orOp};</code>
334        * @return CFXD Element
335        * @throws PageException 
336        */
337        private Ref xorOp() throws PageException {
338            Ref ref = orOp();
339            while(cfml.forwardIfCurrent("xor")) {
340                cfml.removeSpace();
341                ref=new Xor(ref,orOp());
342            }
343            return ref;
344        }
345    
346        /**
347        * Transfomiert eine  Or (or) Operation. Im Gegensatz zu CFMX ,
348        * werden "||" Zeichen auch als Or Operatoren anerkannt.
349        * <br />
350        * EBNF:<br />
351        * <code>andOp {("or" | "||") spaces andOp}; (* "||" Existiert in CFMX nicht *)</code>
352        * @return CFXD Element
353        * @throws PageException 
354        */
355        private Ref orOp() throws PageException {
356            Ref ref = andOp();
357            while(cfml.isValidIndex() && (cfml.forwardIfCurrent("||") || cfml.forwardIfCurrent("or"))) {
358                cfml.removeSpace();
359                ref=new Or(ref,andOp());
360            }
361            return ref;
362        }
363    
364        /**
365        * Transfomiert eine  And (and) Operation. Im Gegensatz zu CFMX ,
366        * werden "&&" Zeichen auch als And Operatoren anerkannt.
367        * <br />
368        * EBNF:<br />
369        * <code>notOp {("and" | "&&") spaces notOp}; (* "&&" Existiert in CFMX nicht *)</code>
370        * @return CFXD Element
371        * @throws PageException 
372        */
373        private Ref andOp() throws PageException {
374            Ref ref = notOp();
375            while(cfml.isValidIndex() && (cfml.forwardIfCurrent("&&") || cfml.forwardIfCurrent("and"))) {
376                cfml.removeSpace();
377                ref=new And(ref,notOp());
378            }
379            return ref;
380        }
381    
382        /**
383        * Transfomiert eine  Not (not) Operation. Im Gegensatz zu CFMX ,
384        * wird das "!" Zeichen auch als Not Operator anerkannt.
385        * <br />
386        * EBNF:<br />
387        * <code>[("not"|"!") spaces] decsionOp; (* "!" Existiert in CFMX nicht *)</code>
388        * @return CFXD Element
389        * @throws PageException 
390        */
391        private Ref notOp() throws PageException {
392            if(cfml.isValidIndex()) {
393                    if (cfml.isCurrent('!') && !cfml.isCurrent("!=")) {
394                            cfml.next();
395                        cfml.removeSpace();
396                        return new Not(decsionOp());
397                    }
398                    else if (cfml.forwardIfCurrentAndNoWordAfter("not")) {
399                        cfml.removeSpace();
400                        return new Not(decsionOp());
401                    }
402            }
403            return decsionOp();
404        }
405    
406        /**
407        * <font f>Transfomiert eine Vergleichs Operation.
408        * <br />
409        * EBNF:<br />
410        * <code>concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"|
411                         "contains"|"nct"|"does not contain") spaces concatOp}; 
412                (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *)</code>
413        * @return CFXD Element
414        * @throws PageException 
415        */
416        private Ref decsionOp() throws PageException {
417    
418            Ref ref = concatOp();
419            boolean hasChanged=false;
420            // ct, contains
421            if(cfml.isValidIndex()){
422                do {
423                    hasChanged=false;
424                    if(cfml.isCurrent('c')) {
425                            if (cfml.forwardIfCurrent("ct")) {
426                                cfml.removeSpace();
427                                ref=new CT(ref,concatOp());
428                                hasChanged=true;
429                            } 
430                            else if (cfml.forwardIfCurrent("contains")){ 
431                                cfml.removeSpace();
432                                ref=new CT(ref,concatOp());
433                                hasChanged=true;
434                            }
435                    }
436                    // does not contain
437                    else if (cfml.forwardIfCurrent("does","not","contain")){ 
438                        cfml.removeSpace();
439                        ref=new NCT(ref,concatOp());
440                        hasChanged=true;
441                    }
442                    
443                    // equal, eq
444                    else if (cfml.isCurrent("eq") && !cfml.isCurrent("eqv")) {
445                        cfml.setPos(cfml.getPos()+2);
446                        cfml.forwardIfCurrent("ual");
447                        cfml.removeSpace();
448                        ref=new EQ(ref,concatOp());
449                        hasChanged=true;
450                    }
451                    // ==
452                    else if (cfml.forwardIfCurrent("==")) {
453                        if(cfml.forwardIfCurrent('='))              {
454                            cfml.removeSpace();
455                            ref = new EEQ(ref,concatOp());
456                        }
457                                    else {
458                                            cfml.removeSpace();
459                            ref=new EQ(ref,concatOp());
460                                    }
461                        hasChanged=true;
462                    }
463                    
464                    // !=
465                    else if (cfml.forwardIfCurrent("!=")) {
466                        if(cfml.forwardIfCurrent('=')) {
467                            cfml.removeSpace();
468                            ref = new NEEQ(ref,concatOp());
469                        }
470                                    else {
471                                            cfml.removeSpace();
472                            ref=new NEQ(ref,concatOp());
473                                    }
474                        hasChanged=true;
475                    }
476    
477                    // <=/</<>
478                            else if (cfml.forwardIfCurrent('<')) {
479                                    if(cfml.forwardIfCurrent('='))          {
480                                            cfml.removeSpace();
481                            ref = new LTE(ref,concatOp());
482                                    }
483                                    else if(cfml.forwardIfCurrent('>')) {
484                                            cfml.removeSpace();
485                            ref = new NEQ(ref,concatOp());
486                                    }
487                                    else                                                            {
488                                            cfml.removeSpace();
489                            ref = new LT(ref,concatOp());
490                                    }
491                                    hasChanged=true;
492                            }
493                    // >/>=
494                            else if (cfml.forwardIfCurrent('>')) {
495                                    if(cfml.forwardIfCurrent('='))          {
496                                            cfml.removeSpace();
497                            ref = new GTE(ref,concatOp());
498                                    }
499                                    else                                                            {
500                                            cfml.removeSpace();
501                            ref = new GT(ref,concatOp());
502                                    }
503                                    hasChanged=true;
504                            }
505                    
506                    // gt, gte, greater than or equal to, greater than
507                    else if (cfml.isCurrent('g')) {
508                        if (cfml.forwardIfCurrent("gt")) {
509                            if(cfml.forwardIfCurrent('e')) {
510                                cfml.removeSpace();
511                                ref=new GTE(ref,concatOp());
512                            }
513                            else {
514                                cfml.removeSpace();
515                                ref=new GT(ref,concatOp());
516                            }
517                            hasChanged=true;
518                        } 
519                        else if (cfml.forwardIfCurrent("greater","than")) {
520                            if(cfml.forwardIfCurrent("or" ,"equal", "to",true)) {
521                                cfml.removeSpace();
522                                ref=new GTE(ref,concatOp());
523                            }
524                            else {
525                                cfml.removeSpace();
526                                ref=new GT(ref,concatOp());
527                            }
528                            hasChanged=true;
529                        }   
530                        else if (cfml.forwardIfCurrent("ge")) {
531                            cfml.removeSpace();
532                            ref=new GTE(ref,concatOp());
533                            hasChanged=true;
534                        }               
535                    }
536                    
537                    // is, is not
538                    else if (cfml.forwardIfCurrent("is")) {
539                        if(cfml.forwardIfCurrent("not",true)) {
540                            cfml.removeSpace();
541                            ref=new NEQ(ref,concatOp());
542                        }
543                        else {
544                            cfml.removeSpace();
545                            ref=new EQ(ref,concatOp());
546                        }
547                        hasChanged=true;
548                    }
549                    
550                    // lt, lte, less than, less than or equal to
551                    else if (cfml.isCurrent('l')) {
552                        if (cfml.forwardIfCurrent("lt")) {
553                            if(cfml.forwardIfCurrent('e')) {
554                                cfml.removeSpace();
555                                ref=new LTE(ref,concatOp());
556                            }
557                            else {
558                                cfml.removeSpace();
559                                ref=new LT(ref,concatOp());
560                            }
561                            hasChanged=true;
562                        } 
563                        else if (cfml.forwardIfCurrent("less","than")) {
564                            if(cfml.forwardIfCurrent("or", "equal", "to",true)) {
565                                cfml.removeSpace();
566                                ref=new LTE(ref,concatOp());
567                            }
568                            else {
569                                cfml.removeSpace();
570                                ref=new LT(ref,concatOp());
571                            }
572                            hasChanged=true;
573                        }   
574                        else if (cfml.forwardIfCurrent("le")) {
575                            cfml.removeSpace();
576                            ref=new LTE(ref,concatOp());
577                            hasChanged=true;
578                        }               
579                    }
580                    
581                    // neq, not equal, nct
582                    else if (cfml.isCurrent('n')) {
583                        // Not Equal
584                            if (cfml.forwardIfCurrent("neq"))   {
585                                cfml.removeSpace(); 
586                                ref=new NEQ(ref,concatOp());
587                                hasChanged=true;
588                            }
589                        // Not Equal (Alias)
590                            else if (cfml.forwardIfCurrent("not","equal")){ 
591                                cfml.removeSpace();
592                                ref=new NEQ(ref,concatOp());
593                                hasChanged=true; 
594                            }
595                        // nct
596                            else if (cfml.forwardIfCurrent("nct"))  { 
597                                cfml.removeSpace();
598                                ref=new NCT(ref,concatOp());
599                                hasChanged=true;
600                            }   
601                    }
602                }while(hasChanged);
603            }
604            return ref;
605        }
606    
607        /**
608        * Transfomiert eine  Konkatinations-Operator (&) Operation. Im Gegensatz zu CFMX ,
609        * wird das "!" Zeichen auch als Not Operator anerkannt.
610        * <br />
611        * EBNF:<br />
612        * <code>plusMinusOp {"&" spaces concatOp};</code>
613        * @return CFXD Element
614        * @throws PageException 
615        */
616        private Ref concatOp() throws PageException {
617            Ref ref = plusMinusOp();
618            
619            while(cfml.isCurrent('&') && !cfml.isNext('&')) {
620                cfml.next();
621                ref=_concat(ref);
622                //cfml.removeSpace();
623                //ref=new Concat(pc,ref,plusMinusOp());
624            }
625            return ref;
626        }
627    
628        /**
629        * Transfomiert die mathematischen Operatoren Plus und Minus (1,-).
630        * <br />
631        * EBNF:<br />
632        * <code>modOp [("-"|"+") spaces plusMinusOp];</code>
633        * @return CFXD Element
634        * @throws PageException 
635        */
636        private Ref plusMinusOp() throws PageException {
637            Ref ref = modOp();
638            
639            while(!cfml.isLast()) {
640                // Plus Operation
641                if (cfml.forwardIfCurrent('+')) {
642                    ref=_plus(ref);
643                    //cfml.removeSpace();
644                    //ref=new Plus(ref,modOp());
645                }
646                // Minus Operation
647                else if (cfml.forwardIfCurrent('-')) {
648                    ref=_minus(ref);
649                    //cfml.removeSpace();
650                    //ref=new Minus(ref,modOp());
651                }
652                else break;
653            }
654            return ref;
655        }
656    
657        private Ref _plus(Ref ref) throws PageException {
658                    // +=
659                    if (cfml.isCurrent('=')) {
660                            cfml.next();
661                            cfml.removeSpace();
662                            Ref right = assignOp();
663                            Ref res = preciseMath?new BigPlus(ref,right):new Plus(ref,right);
664                            ref=new Assign(ref,res);
665                    }
666                    /*/ ++
667                    else if (cfml.isCurrent('+')) {
668                            cfml.next();
669                            cfml.removeSpace();
670                            Ref res = new Plus(ref,new LNumber(new Double(1)));
671                            ref=new Assign(ref,res);
672                            ref=new Minus(ref,new LNumber(new Double(1)));
673                    }*/
674                    else {  
675                cfml.removeSpace();
676                ref=preciseMath?new BigPlus(ref,modOp()):new Plus(ref,modOp());
677                    }
678                    return ref;
679            }
680        
681        private Ref _minus(Ref ref) throws PageException {
682                    // -=
683                    if (cfml.isCurrent('=')) {
684                            cfml.next();
685                            cfml.removeSpace();
686                            Ref right = assignOp();
687                            Ref res = preciseMath?new BigMinus(ref,right):new Minus(ref,right);
688                            ref=new Assign(ref,res);
689                    }
690                    /*/ --
691                    else if (cfml.isCurrent('-')) {
692                            cfml.next();
693                            cfml.removeSpace();
694                            Ref res = new Minus(ref,new LNumber(new Double(1)));
695                            ref=new Assign(ref,res);
696                            ref=new Plus(ref,new LNumber(new Double(1)));
697                    }*/
698                    else {  
699                cfml.removeSpace();
700                ref=preciseMath?new BigMinus(ref,modOp()):new Minus(ref,modOp());
701                    }
702                    return ref;
703            }
704        
705    
706        private Ref _div(Ref ref) throws PageException {
707                    // /=
708                    if (cfml.forwardIfCurrent('=')) {
709                            cfml.removeSpace();
710                            Ref right = assignOp();
711                            Ref res = preciseMath?new BigDiv(ref, right):new Div(ref,right);
712                            ref=new Assign(ref,res);
713                    }
714                    else {  
715                cfml.removeSpace();
716                ref=preciseMath?new BigDiv(ref,expoOp()):new Div(ref,expoOp());
717                    }
718                    return ref;
719            }
720        
721        private Ref _intdiv(Ref ref) throws PageException {
722                    // \=
723                    if (cfml.forwardIfCurrent('=')) {
724                            cfml.removeSpace();
725                            Ref right = assignOp();
726                            Ref res = preciseMath?new BigIntDiv(ref,right):new IntDiv(ref,right);
727                            ref=new Assign(ref,res);
728                    }
729                    else {  
730                cfml.removeSpace();
731                ref=preciseMath?new BigIntDiv(ref,expoOp()):new IntDiv(ref,expoOp());
732                    }
733                    return ref;
734            }
735    
736        private Ref _mod(Ref ref) throws PageException {
737                    // %=
738                    if (cfml.forwardIfCurrent('=')) {
739                            cfml.removeSpace();
740                            Ref right = assignOp();
741                            Ref res = preciseMath?new BigMod(ref,right):new Mod(ref,right);
742                            ref=new Assign(ref,res);
743                    }
744                    else {  
745                cfml.removeSpace();
746                ref=preciseMath?new BigMod(ref,divMultiOp()):new Mod(ref,divMultiOp());
747                    }
748                    return ref;
749            }
750        private Ref _concat(Ref ref) throws PageException {
751                    // &=
752                    if (cfml.forwardIfCurrent('=')) {
753                            cfml.removeSpace();
754                            Ref right = assignOp();
755                            Ref res = new  Concat(pc,ref,right);
756                            ref=new Assign(ref,res);
757                    }
758                    else {  
759                cfml.removeSpace();
760                ref=new Concat(pc,ref,plusMinusOp());
761                    }
762                    return ref;
763            }
764        
765        private Ref _multi(Ref ref) throws PageException {
766                    // \=
767                    if (cfml.forwardIfCurrent('=')) {
768                            cfml.removeSpace();
769                            Ref right = assignOp();
770                            Ref res = preciseMath?new BigMulti(ref,right):new Multi(ref,right);
771                            ref=new Assign(ref,res);
772                    }
773                    else {  
774                cfml.removeSpace();
775                ref=preciseMath?new BigMulti(ref,expoOp()):new Multi(ref,expoOp());
776                    }
777                    return ref;
778            }
779        
780        
781        
782        
783    
784        /**
785        * Transfomiert eine Modulus Operation. Im Gegensatz zu CFMX ,
786        * wird das "%" Zeichen auch als Modulus Operator anerkannt.
787        * <br />
788        * EBNF:<br />
789        * <code>divMultiOp {("mod" | "%") spaces divMultiOp}; (* modulus operator , "%" Existiert in CFMX nicht *)</code>
790        * @return CFXD Element
791        * @throws PageException 
792        */
793        private Ref modOp() throws PageException {
794            Ref ref = divMultiOp();
795            
796            while(cfml.isValidIndex() && (cfml.forwardIfCurrent('%') || cfml.forwardIfCurrent("mod"))) {
797                ref=_mod(ref);
798                    
799                    //cfml.removeSpace();
800                //ref=new Mod(ref,divMultiOp());
801            }
802            return ref;
803        }
804    
805        /**
806        * Transfomiert die mathematischen Operatoren Mal und Durch (*,/).
807        * <br />
808        * EBNF:<br />
809        * <code>expoOp {("*"|"/") spaces expoOp};</code>
810        * @return CFXD Element
811        * @throws PageException 
812        */
813        private Ref divMultiOp() throws PageException {
814            Ref ref = expoOp();
815    
816            while (!cfml.isLast()) {
817                // Multiply Operation
818                if(cfml.forwardIfCurrent('*')) {
819                    ref=_multi(ref);
820                    //cfml.removeSpace();
821                    //ref=new Multi(ref,expoOp());
822                }
823                // Divide Operation
824                else if (cfml.isCurrent('/') && (!cfml.isCurrent("/>") )) {
825                    cfml.next(); 
826                    ref=_div(ref);
827                    //cfml.removeSpace();
828                    //ref=new Div(ref,expoOp());
829                }
830                // Divide Operation
831                else if (cfml.isCurrent('\\')) {
832                    cfml.next(); 
833                    ref=_intdiv(ref);
834                    //cfml.removeSpace();
835                    //ref=new IntDiv(ref,expoOp());
836                }
837                else {
838                    break;
839                }
840            }
841            return ref;
842        }
843    
844        /**
845        * Transfomiert den Exponent Operator (^,exp). Im Gegensatz zu CFMX ,
846        * werden die Zeichen " exp " auch als Exponent anerkannt.
847        * <br />
848        * EBNF:<br />
849        * <code>clip {("exp"|"^") spaces clip};</code>
850        * @return CFXD Element
851        * @throws PageException 
852        */
853        private Ref expoOp() throws PageException {
854            Ref ref = unaryOp();
855    
856            while(cfml.isValidIndex() && (cfml.forwardIfCurrent('^') || cfml.forwardIfCurrent("exp"))) {
857                cfml.removeSpace();
858                ref=new Exp(ref,unaryOp());
859            }
860            return ref;
861        }
862        
863    
864        private Ref unaryOp() throws PageException {
865            Ref ref = negateMinusOp();
866            
867                    if (cfml.forwardIfCurrent("--")) 
868                            ref=_unaryOp(ref, false);
869                    
870                    else if (cfml.forwardIfCurrent("++")) 
871                            ref=_unaryOp(ref, true);
872                    return ref;
873            }
874        
875        private Ref _unaryOp(Ref ref,boolean isPlus) throws PageException {
876            cfml.removeSpace();
877                    Ref res = preciseMath?new BigPlus(ref,isPlus?PLUS_ONE:MINUS_ONE):new Plus(ref,isPlus?PLUS_ONE:MINUS_ONE);
878                    ref=new Assign(ref,res);
879                    return preciseMath?new BigPlus(ref,isPlus?MINUS_ONE:PLUS_ONE):new Plus(ref,isPlus?MINUS_ONE:PLUS_ONE);
880            }
881        
882    
883        /**
884        * Liest die Vordlobe einer Zahl ein
885        * @return CFXD Element
886        * @throws PageException 
887        */
888        private Ref negateMinusOp() throws PageException {
889            // And Operation
890            if (cfml.forwardIfCurrent('-')) {
891                    if (cfml.forwardIfCurrent('-')) {
892                            cfml.removeSpace();
893                                    Ref expr = clip();
894                                    Ref res = preciseMath?new BigMinus(expr,new LNumber(new Double(1))):new Minus(expr,new LNumber(new Double(1)));
895                                    return new Assign(expr,res);
896                            }       
897                cfml.removeSpace();
898                return new Negate(clip());
899                    
900            }
901            if (cfml.forwardIfCurrent('+')) {
902                    if (cfml.forwardIfCurrent('+')) {
903                            cfml.removeSpace();
904                                    Ref expr = clip();
905                                    Ref res = preciseMath?new BigPlus(expr,new LNumber(new Double(1))):new Plus(expr,new LNumber(new Double(1)));
906                                    return new Assign(expr,res);
907                            }
908                    cfml.removeSpace();
909                    return new Casting(pc,"numeric",CFTypes.TYPE_NUMERIC,clip());
910                    
911            }
912            return clip();
913        }
914    
915        /**
916        * Verarbeitet Ausdrcke die inerhalb einer Klammer stehen.
917        * <br />
918        * EBNF:<br />
919        * <code>("(" spaces impOp ")" spaces) | checker;</code>
920        * @return CFXD Element
921        * @throws PageException 
922        */
923        private Ref clip() throws PageException {
924            return checker();
925        }
926        
927        /**
928        * Hier werden die verschiedenen M￶glichen Werte erkannt 
929        * und jenachdem wird mit der passenden Methode weitergefahren
930        * <br />
931        * EBNF:<br />
932        * <code>string | number | dynamic | sharp;</code>
933        * @return CFXD Element
934        * @throws PageException 
935        */
936        private Ref checker() throws PageException {
937            
938            Ref ref=null;  
939            // String
940                if(cfml.isCurrentQuoter()) {
941                    // mode=STATIC; is at the end of the string function because must set after execution
942                    return string();
943                } 
944            // Number
945                if(cfml.isCurrentDigit() || cfml.isCurrent('.')) {
946                    // mode=STATIC; is at the end of the string function because must set after execution
947                    return number();
948                } 
949            // Dynamic
950                if((ref=dynamic())!=null) {
951                    mode=DYNAMIC;
952                    return ref;
953                } 
954            // Sharp
955                if((ref=sharp())!=null) {
956                    mode=DYNAMIC;
957                    return ref;
958                }  
959            // JSON
960                if((ref=json(JSON_ARRAY,'[',']'))!=null) {
961                                    mode=DYNAMIC;
962                                    return ref;
963                            } 
964                            if((ref=json(JSON_STRUCT,'{','}'))!=null) {
965                                    mode=DYNAMIC;
966                                    return ref;
967                            } 
968                
969                            if(cfml.isAfterLast() && cfml.toString().trim().length()==0)
970                                    return new LString("");
971                
972            // else Error
973                            throw new ExpressionException("Syntax Error, Invalid Construct","at position "+cfml.getPos()+" in ["+cfml.toString()+"]");  
974        }
975        
976        
977        protected Ref json(FunctionLibFunction flf, char start, char end) throws PageException {
978                    //print.out("start:"+start+":"+cfml.getCurrent());
979                    if(!cfml.isCurrent(start))return null;
980                    
981                    Ref[] args = functionArg(flf.getName(), false, flf,end);
982                    
983                    //if (!cfml.forwardIfCurrent(end))
984                    //      throw new ExpressionException("Invalid Syntax Closing ["+end+"] not found");
985                    
986                    return new BIFCall(pc,flf,args);
987            }
988        
989        /**
990        * Transfomiert einen lierale Zeichenkette.
991        * <br />
992        * EBNF:<br />
993        * <code>("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") | 
994                         (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """);</code>
995        * @return CFXD Element
996        * @throws PageException 
997        */
998        protected Ref string() throws PageException {
999                            
1000            // Init Parameter
1001            char quoter = cfml.getCurrentLower();
1002            //String str="";
1003            LStringBuffer str=new LStringBuffer();
1004            Ref value=null;
1005            
1006            while(cfml.hasNext()) {
1007                cfml.next();
1008                // check sharp
1009                if(cfml.isCurrent('#')) {
1010                    if(cfml.isNext('#')){
1011                        cfml.next();
1012                        str.append('#');
1013                    }
1014                    else {
1015                        cfml.next();
1016                        cfml.removeSpace();
1017                        if(!str.isEmpty() || value!=null) str.append(assignOp());
1018                        else value=assignOp();
1019                        cfml.removeSpace();
1020                        if (!cfml.isCurrent('#')) throw new ExpressionException("Invalid Syntax Closing [#] not found");
1021                    }
1022                }
1023                else if(cfml.isCurrent(quoter)) {
1024                    if(cfml.isNext(quoter)){
1025                        cfml.next();
1026                        str.append(quoter);
1027                    }
1028                    else {
1029                        break;
1030                    }               
1031                }
1032                // all other character
1033                else {
1034                    str.append(cfml.getCurrent());
1035                }
1036            }
1037            if(!cfml.forwardIfCurrent(quoter))
1038                throw new ExpressionException("Invalid String Literal Syntax Closing ["+quoter+"] not found");
1039            
1040            cfml.removeSpace();
1041            mode=STATIC;
1042            if(value!=null) {
1043                if(str.isEmpty()) return value;
1044                return new Concat(pc,value,str);
1045            }
1046            return str;
1047        }
1048    
1049        /**
1050        * Transfomiert einen numerische Wert. 
1051        * Die L¦nge des numerischen Wertes interessiert nicht zu ᅵbersetzungszeit, 
1052        * ein "Overflow" fhrt zu einem Laufzeitfehler. 
1053        * Da die zu erstellende CFXD, bzw. dieser Transfomer, keine Vorwegnahme des Laufzeitsystems vornimmt. 
1054        * <br />
1055        * EBNF:<br />
1056        * <code>["+"|"-"] digit {digit} {"." digit {digit}};</code>
1057        * @return CFXD Element
1058        * @throws PageException 
1059        */
1060        private Ref number() throws PageException {
1061            // check first character is a number literal representation
1062            //if(!cfml.isCurrentDigit()) return null;
1063            
1064            StringBuilder rtn=new StringBuilder(6);
1065            
1066            // get digit on the left site of the dot
1067            if(cfml.isCurrent('.')) rtn.append('0');
1068            else digit(rtn);
1069            // read dot if exist
1070            if(cfml.forwardIfCurrent('.')) {
1071                rtn.append('.');
1072                int before=cfml.getPos();
1073                digit(rtn);
1074    
1075                if(before<cfml.getPos() && cfml.forwardIfCurrent('e')) {
1076                    Boolean expOp=null;
1077                                    if(cfml.forwardIfCurrent('+')) expOp=Boolean.TRUE;
1078                                    else if(cfml.forwardIfCurrent('-')) expOp=Boolean.FALSE;
1079                                    
1080                    
1081                    if(cfml.isCurrentDigit()) {
1082                            if(expOp==Boolean.FALSE) rtn.append("e-");
1083                                            else if(expOp==Boolean.TRUE) rtn.append("e+");
1084                                            else rtn.append('e');
1085                        digit(rtn);
1086                    }
1087                    else {
1088                            if(expOp!=null) cfml.previous();
1089                                    cfml.previous();
1090                    }
1091                }
1092                
1093                
1094                // read right side of the dot
1095                if(before==cfml.getPos())
1096                    throw new ExpressionException("Number can't end with [.]");
1097                //rtn.append(rightSite);
1098            }
1099            cfml.removeSpace();
1100            mode=STATIC;
1101            return new LNumber(rtn.toString());
1102            
1103        }
1104        
1105        /**
1106        * Liest die reinen Zahlen innerhalb des CFMLString aus und gibt diese als Zeichenkette zurck. 
1107        * <br />
1108        * EBNF:<br />
1109        * <code>"0"|..|"9";</code>
1110         * @param rtn
1111        */
1112        private void digit(StringBuilder rtn) {
1113            
1114            while (cfml.isValidIndex()) {
1115                if(!cfml.isCurrentDigit())break;
1116                rtn.append(cfml.getCurrentLower());
1117                cfml.next();
1118            }
1119        }
1120    
1121        /**
1122        * Liest den folgenden idetifier ein und prft ob dieser ein boolscher Wert ist. 
1123        * Im Gegensatz zu CFMX wird auch "yes" und "no" als bolscher <wert akzeptiert, 
1124        * was bei CFMX nur beim Umwandeln einer Zeichenkette zu einem boolschen Wert der Fall ist.<br />
1125        * Wenn es sich um keinen bolschen Wert handelt wird der folgende Wert eingelesen mit seiner ganzen Hirarchie.
1126        * <br />
1127        * EBNF:<br />
1128        * <code>"true" | "false" | "yes" | "no" | startElement  
1129                         {("." identifier | "[" structElement "]" )[function] };</code>
1130        * @return CFXD Element
1131        * @throws PageException 
1132        */
1133        private Ref dynamic() throws PageException {
1134            // Die Implementation weicht ein wenig von der Grammatik ab, 
1135            // aber nicht in der Logik sondern rein wie es umgesetzt wurde.
1136            
1137            // get First Element of the Variable
1138            String name = identifier(false);
1139            if(name == null) {
1140                if (!cfml.forwardIfCurrent('('))return null;
1141                cfml.removeSpace();
1142                Ref ref = assignOp();
1143    
1144                if (!cfml.forwardIfCurrent(')'))
1145                    throw new ExpressionException("Invalid Syntax Closing [)] not found");
1146                cfml.removeSpace();
1147                return subDynamic(ref);
1148            }
1149    
1150            //Element el;
1151            cfml.removeSpace();
1152            char first=name.charAt(0);
1153            
1154            // Boolean constant 
1155            if(first=='T' && name.equals("TRUE"))   {
1156                cfml.removeSpace();
1157                return LBoolean.TRUE;
1158            }
1159            else if(first=='F' && name.equals("FALSE")) {
1160                cfml.removeSpace();
1161                return LBoolean.FALSE;
1162            }   
1163            else if(first=='Y' && name.equals("YES"))   {
1164                cfml.removeSpace();
1165                return LBoolean.TRUE;
1166            }
1167            else if(first=='N')    {
1168                    if(name.equals("NO")){
1169                            cfml.removeSpace();
1170                            return LBoolean.FALSE;
1171                    }
1172                    else if(allowNullConstant && name.equals("NULL")){
1173                            cfml.removeSpace();
1174                            return new  LString(null);
1175                    }
1176                    else if(name.equals("NEW")){
1177                            Ref res = newOp();
1178                            if(res!=null) return res;
1179                    }
1180            }  
1181            
1182            
1183            
1184            // Extract Scope from the Variable
1185    
1186            //Object value = startElement(name);
1187            return subDynamic(startElement(name));
1188    
1189        }
1190        
1191        private Ref subDynamic(Ref ref) throws PageException {
1192            String name=null;
1193            
1194            // Loop over nested Variables
1195            while (cfml.isValidIndex()) {
1196                // .
1197                if (cfml.forwardIfCurrent('.')) {
1198                    // Extract next Var String
1199                    cfml.removeSpace();
1200                    name = identifier(true);
1201                    if(name==null) throw new ExpressionException("Invalid identifier");
1202                    cfml.removeSpace();
1203                    ref=new Variable(pc,ref,name);
1204                }
1205                // []
1206                else if (cfml.forwardIfCurrent('[')) {
1207                    cfml.removeSpace();
1208                    ref=new Variable(pc,ref,assignOp());
1209                    cfml.removeSpace();
1210                    if (!cfml.forwardIfCurrent(']'))
1211                        throw new ExpressionException("Invalid Syntax Closing []] not found");
1212                }
1213                // finish
1214                else {
1215                    break;
1216                }
1217    
1218                cfml.removeSpace();
1219                
1220                if (cfml.isCurrent('(')) {
1221                    if(!(ref instanceof Set)) throw new ExpressionException("invalid syntax "+ref.getTypeName()+" can't called as function");
1222                    Set set=(Set) ref;
1223                    ref=new UDFCall(pc,set.getParent(),set.getKey(),functionArg(name,false, null,')'));
1224                }
1225            }
1226            if(ref instanceof railo.runtime.interpreter.ref.var.Scope) { 
1227                railo.runtime.interpreter.ref.var.Scope s=(railo.runtime.interpreter.ref.var.Scope)ref;
1228                if(s.getScope()==Scope.SCOPE_ARGUMENTS || s.getScope()==Scope.SCOPE_LOCAL || s.getScope()==ScopeSupport.SCOPE_VAR) {
1229                    ref=new Bind(s);
1230                }
1231            }
1232            return ref;
1233        }
1234    
1235        /**
1236        * Extrahiert den Start Element einer Variale, 
1237        * dies ist entweder eine Funktion, eine Scope Definition oder eine undefinierte Variable. 
1238        * <br />
1239        * EBNF:<br />
1240        * <code>identifier "(" functionArg ")" | scope | identifier;</code>
1241        * @param name Einstiegsname
1242        * @return CFXD Element
1243        * @throws PageException 
1244        */
1245        private Ref startElement(String name) throws PageException {
1246            
1247            // check function
1248            if (cfml.isCurrent('(')) {
1249                FunctionLibFunction function = fld.getFunction(name);
1250                Ref[] arguments = functionArg(name,true, function,')');
1251                    //print.out(name+":"+(function!=null));
1252                if(function!=null) return new BIFCall(pc,function,arguments);
1253    
1254                Ref ref = new railo.runtime.interpreter.ref.var.Scope(pc,Scope.SCOPE_UNDEFINED);
1255                return new UDFCall(pc,ref,name,arguments);
1256            }
1257            //check scope
1258            return scope(name);
1259        }
1260        
1261            private Ref newOp() throws PageException {
1262                    
1263                    int start=cfml.getPos();
1264                String name=null;
1265                cfml.removeSpace();
1266                
1267                // first identifier
1268                name = identifier(true);
1269                    Ref refName=null;
1270                    if(name!=null) {
1271                            StringBuilder fullName=new StringBuilder();
1272                            fullName.append(name);
1273                            // Loop over addional identifier
1274                            while (cfml.isValidIndex()) {
1275                                    if (cfml.forwardIfCurrent('.')) {
1276                            cfml.removeSpace();
1277                            name = identifier(true);
1278                            if(name==null) throw new ExpressionException("invalid Component declaration");
1279                            cfml.removeSpace();
1280                                            fullName.append('.');
1281                                            fullName.append(name);
1282                        }
1283                                    else break;
1284                            }
1285                            refName=new LString(fullName.toString());
1286                    }
1287                    else {
1288                            if(cfml.isCurrentQuoter())refName=string();
1289                            if(refName==null){
1290                                    cfml.setPos(start);
1291                                    return null;
1292                            }
1293                    }
1294                    cfml.removeSpace();
1295            
1296            if (cfml.isCurrent('(')) {
1297                    FunctionLibFunction function = fld.getFunction("_createComponent");
1298                Ref[] arguments = functionArg("_createComponent",true, function,')');
1299                Ref[] args=new Ref[arguments.length+1];
1300                for(int i=0;i<arguments.length;i++){
1301                    args[i]=arguments[i];
1302                }
1303                args[args.length-1]=refName;
1304                BIFCall bif = new BIFCall(pc,function,args);
1305                    cfml.removeSpace();
1306                    return bif;
1307                    
1308                            
1309                            
1310                    } 
1311            throw new ExpressionException("invalid Component declaration ");
1312                    
1313            }
1314        
1315        
1316        
1317        
1318        /**
1319        * Liest einen CFML Scope aus, 
1320        * falls der folgende identifier keinem Scope entspricht, 
1321        * gibt die Variable null zurck.
1322        * <br />
1323        * EBNF:<br />
1324        * <code>"variable" | "cgi" | "url" | "form" | "session" | "application" | "arguments" | "cookie" | " client";</code>
1325         * @param idStr String identifier, 
1326         * wird aus Optimierungszwechen nicht innerhalb dieser Funktion ausgelsen.
1327         * @return CFXD Variable Element oder null
1328        */
1329        private Ref scope(String idStr) {
1330            if (idStr.equals("var")) {
1331                String name=identifier(false);
1332                if(name!=null){
1333                    cfml.removeSpace();
1334                    return new Variable(pc,new railo.runtime.interpreter.ref.var.Scope(pc,ScopeSupport.SCOPE_VAR),name);
1335                }
1336            }
1337            int scope = VariableInterpreter.scopeString2Int(idStr);
1338            if(scope==Scope.SCOPE_UNDEFINED) {
1339                return new Variable(pc,new railo.runtime.interpreter.ref.var.Scope(pc,Scope.SCOPE_UNDEFINED),idStr);
1340            }
1341            return new railo.runtime.interpreter.ref.var.Scope(pc,scope);
1342            
1343        }
1344        
1345        /**
1346        * Liest einen Identifier aus und gibt diesen als String zurck.
1347        * <br />
1348        * EBNF:<br />
1349        * <code>(letter | "_") {letter | "_"|digit};</code>
1350         * @param firstCanBeNumber 
1351        * @return Identifier.
1352        */
1353        private String identifier(boolean firstCanBeNumber) {
1354            //int start = cfml.getPos();
1355            if(!cfml.isCurrentLetter() && !cfml.isCurrentSpecial()) {
1356                if(!firstCanBeNumber)return null;
1357                else if(!cfml.isCurrentDigit())return null;
1358            }
1359            
1360            StringBuffer sb=new StringBuffer();
1361            //if(CASE_TYPE_UPPER==caseType)
1362                    sb.append(cfml.getCurrentUpper());
1363            /*else if(CASE_TYPE_ORIGINAL==caseType)
1364                    sb.append(cfml.getCurrent());
1365            else 
1366                    sb.append(cfml.getCurrentLower());*/
1367            do {
1368                cfml.next();
1369                if(!(cfml.isCurrentLetter()
1370                    || cfml.isCurrentDigit()
1371                    || cfml.isCurrentSpecial())) {
1372                        break;
1373                    }
1374    
1375                //if(CASE_TYPE_UPPER==caseType)
1376                    sb.append(cfml.getCurrentUpper());
1377                /*else if(CASE_TYPE_ORIGINAL==caseType)
1378                    sb.append(cfml.getCurrent());
1379                else 
1380                    sb.append(cfml.getCurrentLower());*/
1381                
1382                
1383            }
1384            while (cfml.isValidIndex());
1385            return sb.toString();//cfml.substringLower(start,cfml.getPos()-start);
1386        }
1387    
1388        /**
1389        * Transfomiert ein Collection Element das in eckigen Klammern aufgerufen wird. 
1390        * <br />
1391        * EBNF:<br />
1392        * <code>"[" impOp "]"</code>
1393        * @return CFXD Element
1394        * @throws PageException 
1395        */
1396        private Ref structElement() throws PageException {
1397            cfml.removeSpace();
1398            Ref ref = new Casting(pc,"string",CFTypes.TYPE_STRING,assignOp());
1399            cfml.removeSpace();
1400            return ref;
1401        }
1402    
1403        /**
1404        * Liest die Argumente eines Funktonsaufruf ein und prft ob die Funktion 
1405        * innerhalb der FLD (Function Library Descriptor) definiert ist. 
1406        * Falls sie existiert wird die Funktion gegen diese geprft und ein build-in-function CFXD Element generiert, 
1407        * ansonsten ein normales funcion-call Element.
1408        * <br />
1409        * EBNF:<br />
1410        * <code>[impOp{"," impOp}];</code>
1411        * @param name Identifier der Funktion als Zeichenkette
1412        * @param checkLibrary Soll geprft werden ob die Funktion innerhalb der Library existiert.
1413        * @param flf FLD Function definition .
1414        * @return CFXD Element
1415        * @throws PageException 
1416        */
1417        private Ref[] functionArg(String name,boolean checkLibrary,FunctionLibFunction flf,char end) throws PageException {
1418    
1419            // get Function Library
1420            checkLibrary=checkLibrary && flf!=null;     
1421            
1422    
1423            // Function Attributes
1424            ArrayList arr = new ArrayList();
1425            
1426            ArrayList arrFuncLibAtt = null;
1427            int libLen = 0;
1428            if (checkLibrary) {
1429                arrFuncLibAtt = flf.getArg();
1430                libLen = arrFuncLibAtt.size();
1431            }
1432            int count = 0;
1433            Ref ref;
1434            do {
1435                cfml.next();
1436                cfml.removeSpace();
1437    
1438                // finish
1439                if (cfml.isCurrent(end))
1440                    break;
1441    
1442                // too many Attributes
1443                boolean isDynamic=false;
1444                int max=-1;
1445                if(checkLibrary) {
1446                    isDynamic=isDynamic(flf);
1447                    max=flf.getArgMax();
1448                // Dynamic
1449                    if(isDynamic) {
1450                        if(max!=-1 && max <= count)
1451                            throw new ExpressionException("too many Attributes in function [" + name + "]");
1452                    }
1453                // Fix
1454                    else {
1455                        if(libLen <= count)
1456                            throw new ExpressionException("too many Attributes in function [" + name + "]");
1457                    }
1458                }
1459    
1460                
1461                if (checkLibrary && !isDynamic) {
1462                    // current attribues from library
1463                    FunctionLibFunctionArg funcLibAtt = (FunctionLibFunctionArg) arrFuncLibAtt.get(count);
1464                    short type=CFTypes.toShort(funcLibAtt.getType(),CFTypes.TYPE_UNKNOW);
1465                    if(type==CFTypes.TYPE_VARIABLE_STRING) {
1466                        arr.add(functionArgDeclarationVarString());
1467                    }
1468                    else {
1469                            ref = functionArgDeclaration();
1470                            arr.add(new Casting(pc,funcLibAtt.getTypeAsString(),type,ref));
1471                    }
1472                } 
1473                else {
1474                    arr.add(functionArgDeclaration());
1475                }
1476    
1477                // obj=andOrXor();
1478                cfml.removeSpace();
1479                count++;
1480            } 
1481            while (cfml.isCurrent(','));
1482    
1483            // end with ) ??        
1484            if (!cfml.forwardIfCurrent(end)) {
1485                if(name.startsWith("_json")) throw new ExpressionException("Invalid Syntax Closing ["+end+"] not found");
1486                throw new ExpressionException("Invalid Syntax Closing ["+end+"] for function ["+ name + "] not found");
1487            }
1488    
1489            // check min attributes
1490            if (checkLibrary && flf.getArgMin() > count)
1491                throw new ExpressionException("to less Attributes in function [" + name + "]");
1492    
1493            cfml.removeSpace();
1494            return (Ref[]) arr.toArray(new Ref[arr.size()]);
1495        }
1496     
1497        
1498        private boolean isDynamic(FunctionLibFunction flf) {
1499            return flf.getArgType()==FunctionLibFunction.ARG_DYNAMIC;
1500        }
1501        
1502        /**
1503         * Sharps (#) die innerhalb von Expressions auftauchen haben in CFML keine weitere Beteutung 
1504         * und werden durch diese Methode einfach entfernt.
1505         * <br />
1506         * Beispiel:<br />
1507         * <code>arrayLen(#arr#)</code> und <code>arrayLen(arr)</code> sind identisch.
1508         * EBNF:<br />
1509         * <code>"#" checker "#";</code>
1510         * @return CFXD Element
1511         * @throws PageException 
1512        */
1513        private Ref sharp() throws PageException {
1514            if(!cfml.forwardIfCurrent('#'))
1515                return null;
1516            Ref ref;
1517            cfml.removeSpace();
1518            ref = assignOp();
1519            cfml.removeSpace();
1520            if (!cfml.forwardIfCurrent('#'))
1521                throw new ExpressionException("Syntax Error, Invalid Construct");
1522            cfml.removeSpace();
1523            return ref;
1524        }
1525    
1526        /* *
1527         * Wandelt eine variable und ein key in eine reference um
1528         * @param value
1529         * @param name
1530         * @return cast a vlue in a reference
1531         * @throws PageException
1532         * /
1533        private Reference toReference(Object value, String name) {
1534            return NativeReference.getInstance(value, name);
1535        }*/
1536        
1537    }