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