001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.transformer.cfml.expression;
020
021import java.util.ArrayList;
022import java.util.Iterator;
023
024import lucee.runtime.Component;
025import lucee.runtime.config.NullSupportHelper;
026import lucee.runtime.exp.CasterException;
027import lucee.runtime.exp.TemplateException;
028import lucee.runtime.functions.other.CreateUniqueId;
029import lucee.runtime.op.Caster;
030import lucee.runtime.type.scope.Scope;
031import lucee.runtime.type.scope.ScopeSupport;
032import lucee.runtime.type.util.UDFUtil;
033import lucee.transformer.bytecode.BytecodeException;
034import lucee.transformer.bytecode.Literal;
035import lucee.transformer.bytecode.Page;
036import lucee.transformer.bytecode.Position;
037import lucee.transformer.bytecode.cast.CastDouble;
038import lucee.transformer.bytecode.cast.CastString;
039import lucee.transformer.bytecode.expression.ClosureAsExpression;
040import lucee.transformer.bytecode.expression.ExprBoolean;
041import lucee.transformer.bytecode.expression.ExprDouble;
042import lucee.transformer.bytecode.expression.ExprString;
043import lucee.transformer.bytecode.expression.Expression;
044import lucee.transformer.bytecode.expression.ExpressionInvoker;
045import lucee.transformer.bytecode.expression.Invoker;
046import lucee.transformer.bytecode.expression.var.Argument;
047import lucee.transformer.bytecode.expression.var.Assign;
048import lucee.transformer.bytecode.expression.var.BIF;
049import lucee.transformer.bytecode.expression.var.DataMember;
050import lucee.transformer.bytecode.expression.var.DynAssign;
051import lucee.transformer.bytecode.expression.var.FunctionMember;
052import lucee.transformer.bytecode.expression.var.Member;
053import lucee.transformer.bytecode.expression.var.NamedArgument;
054import lucee.transformer.bytecode.expression.var.UDF;
055import lucee.transformer.bytecode.expression.var.Variable;
056import lucee.transformer.bytecode.literal.Identifier;
057import lucee.transformer.bytecode.literal.LitBoolean;
058import lucee.transformer.bytecode.literal.LitDouble;
059import lucee.transformer.bytecode.literal.LitString;
060import lucee.transformer.bytecode.literal.Null;
061import lucee.transformer.bytecode.op.OPDecision;
062import lucee.transformer.bytecode.op.OPUnary;
063import lucee.transformer.bytecode.op.OpBool;
064import lucee.transformer.bytecode.op.OpContional;
065import lucee.transformer.bytecode.op.OpDouble;
066import lucee.transformer.bytecode.op.OpElvis;
067import lucee.transformer.bytecode.op.OpNegate;
068import lucee.transformer.bytecode.op.OpNegateNumber;
069import lucee.transformer.bytecode.op.OpString;
070import lucee.transformer.bytecode.op.OpVariable;
071import lucee.transformer.bytecode.statement.tag.Attribute;
072import lucee.transformer.bytecode.statement.udf.Closure;
073import lucee.transformer.bytecode.statement.udf.Function;
074import lucee.transformer.bytecode.util.ASMUtil;
075import lucee.transformer.cfml.Data;
076import lucee.transformer.cfml.TransfomerSettings;
077import lucee.transformer.cfml.evaluator.EvaluatorPool;
078import lucee.transformer.cfml.script.DocComment;
079import lucee.transformer.cfml.script.DocCommentTransformer;
080import lucee.transformer.cfml.tag.CFMLTransformer;
081import lucee.transformer.library.function.FunctionLib;
082import lucee.transformer.library.function.FunctionLibFunction;
083import lucee.transformer.library.function.FunctionLibFunctionArg;
084import lucee.transformer.library.tag.TagLib;
085import lucee.transformer.library.tag.TagLibTag;
086import lucee.transformer.library.tag.TagLibTagAttr;
087import lucee.transformer.library.tag.TagLibTagScript;
088import lucee.transformer.util.CFMLString;
089
090/**
091 * 
092 * 
093        Der CFMLExprTransfomer implementiert das Interface ExprTransfomer, 
094        er bildet die Parser Grammatik ab, die unten definiert ist. 
095        Er erhaelt als Eingabe CFML Code, als String oder CFMLString, 
096        der einen CFML Expression erhaelt und liefert ein CFXD Element zurueck, 
097        das diesen Ausdruck abbildet.
098        Mithilfe der FunctionLibs, kann er Funktionsaufrufe, 
099        die Teil eines Ausdruck sein koennen, erkennen und validieren. 
100        Dies geschieht innerhalb der Methode function.
101        Falls ein Funktionsaufruf, einer Funktion innerhalb einer FunctionLib entspricht, 
102        werden diese gegeneinander verglichen und der Aufruf wird als Build-In-Funktion uebernommen, 
103        andernfalls wird der Funktionsaufruf als User-Defined-Funktion interpretiert.
104        Die Klasse Cast, Operator und ElementFactory (siehe 3.2) helfen ihm beim erstellen des Ausgabedokument CFXD.
105
106 * <pre>
107 * Parser Grammatik EBNF (Extended Backus-Naur Form) 
108
109        transform      = spaces impOp;
110        impOp          = eqvOp {"imp" spaces eqvOp};
111        eqvOp          = xorOp {"eqv" spaces xorOp};
112        xorOp          = orOp {"xor" spaces  orOp};
113        orOp           = andOp {("or" | "||") spaces andOp}; 
114                        (* "||" Existiert in CFMX nicht *)
115        andOp          = notOp {("and" | "&&") spaces notOp}; 
116                        (* "&&" Existiert in CFMX nicht *) 
117        notOp          = [("not"|"!") spaces] decsionOp; 
118                        (* "!" Existiert in CFMX nicht *)
119        decsionOp      = concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"|
120                         "contains"|"nct"|"does not contain") spaces concatOp}; 
121                        (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *)
122        concatOp       = plusMinusOp {"&" spaces plusMinusOp};
123        plusMinusOp    = modOp {("-"|"+") spaces modOp};
124        modOp          = divMultiOp {("mod" | "%") spaces divMultiOp}; 
125                        (* modulus operator , "%" Existiert in CFMX nicht *)
126        divMultiOp     = expoOp {("*"|"/") spaces expoOp};
127        expoOp         = clip {("exp"|"^") spaces clip}; 
128                        (*exponent operator, " exp " Existiert in CFMX nicht *)
129        clip           = ("(" spaces impOp ")" spaces) | checker;
130        checker        = string | number | dynamic | sharp;
131        string         = ("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") | 
132                         (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """);
133        number         = ["+"|"-"] digit {digit} {"." digit {digit}};
134        digit          = "0"|..|"9";
135        dynamic        = "true" | "false" | "yes" | "no" | startElement  
136                         {("." identifier | "[" structElement "]")[function] };
137        startElement   = identifier "(" functionArg ")" | scope | identifier;
138        scope          = "variable" | "cgi" | "url" | "form" | "session" | "application" | 
139                         "arguments" | "cookie" | "client ";
140        identifier     = (letter | "_") {letter | "_"|digit};
141        structElement  = "[" impOp "]";
142        functionArg    = [impOp{"," impOp}];
143        sharp          = "#" checker "#";
144        spaces         = {space};
145        space          = "\s"|"\t"|"\f"|"\t"|"\n";
146        letter         = "a"|..|"z"|"A"|..|"Z";
147
148{"x"}= 0 bis n mal "x"
149["x"]= 0 bis 1 mal "x"
150("x" | "y")"z" = "xz" oder "yz"
151
152</pre>
153 *
154 */
155public abstract class AbstrCFMLExprTransformer {
156
157        private static final short STATIC=0;
158        private static final short DYNAMIC=1;
159        private static FunctionLibFunction JSON_ARRAY = null;
160        protected static FunctionLibFunction JSON_STRUCT = null;
161
162        public static final short CTX_OTHER = TagLibTagScript.CTX_OTHER;
163        public static final short CTX_NONE = TagLibTagScript.CTX_NONE;
164        public static final short CTX_IF = TagLibTagScript.CTX_IF;
165        public static final short CTX_ELSE_IF = TagLibTagScript.CTX_ELSE_IF;
166        public static final short CTX_ELSE = TagLibTagScript.CTX_ELSE;
167        public static final short CTX_FOR = TagLibTagScript.CTX_FOR;
168        public static final short CTX_WHILE = TagLibTagScript.CTX_WHILE;
169        public static final short CTX_DO_WHILE = TagLibTagScript.CTX_DO_WHILE;
170        public static final short CTX_CFC = TagLibTagScript.CTX_CFC;
171        public static final short CTX_INTERFACE = TagLibTagScript.CTX_INTERFACE;
172        public static final short CTX_FUNCTION =TagLibTagScript.CTX_FUNCTION;
173        public static final short CTX_BLOCK = TagLibTagScript.CTX_BLOCK;
174        public static final short CTX_FINALLY = TagLibTagScript.CTX_FINALLY;
175        public static final short CTX_SWITCH = TagLibTagScript.CTX_SWITCH;
176        public static final short CTX_TRY = TagLibTagScript.CTX_TRY;
177        public static final short CTX_CATCH = TagLibTagScript.CTX_CATCH;
178        public static final short CTX_TRANSACTION = TagLibTagScript.CTX_TRANSACTION;
179        public static final short CTX_THREAD = TagLibTagScript.CTX_THREAD;
180        public static final short CTX_SAVECONTENT = TagLibTagScript.CTX_SAVECONTENT;
181        public static final short CTX_LOCK = TagLibTagScript.CTX_LOCK;
182        public static final short CTX_LOOP = TagLibTagScript.CTX_LOOP;
183        public static final short CTX_QUERY = TagLibTagScript.CTX_QUERY;
184        public static final short CTX_ZIP = TagLibTagScript.CTX_ZIP;
185        
186        
187        private DocCommentTransformer docCommentTransformer= new DocCommentTransformer();
188        
189
190        protected short ATTR_TYPE_NONE=TagLibTagAttr.SCRIPT_SUPPORT_NONE;
191        protected short ATTR_TYPE_OPTIONAL=TagLibTagAttr.SCRIPT_SUPPORT_OPTIONAL;
192        protected short ATTR_TYPE_REQUIRED=TagLibTagAttr.SCRIPT_SUPPORT_REQUIRED;
193        
194        protected static final Expression NULL = LitString.toExprString("NULL"); 
195        protected static final Attribute ANY = new Attribute(false,"type",LitString.toExprString("any"),"string"); 
196
197
198        protected static EndCondition SEMI_BLOCK=new EndCondition() {
199                public boolean isEnd(ExprData data) {
200                        return data.cfml.isCurrent('{') || data.cfml.isCurrent(';');
201                }
202        };
203        protected static EndCondition SEMI=new EndCondition() {
204                public boolean isEnd(ExprData data) {
205                        return data.cfml.isCurrent(';');
206                }
207        };
208        protected static EndCondition COMMA_ENDBRACKED=new EndCondition() {
209                public boolean isEnd(ExprData data) {
210                        return data.cfml.isCurrent(',') || data.cfml.isCurrent(')');
211                }
212        };
213
214        public static interface EndCondition {
215                public boolean isEnd(ExprData data);
216        }
217        
218        /*private short mode=0;
219        protected CFMLString cfml;
220        protected FunctionLib[] fld;
221        private boolean ignoreScopes=false;
222        private boolean allowLowerThan;*/
223        
224        public class ExprData extends Data {
225                
226                private short mode=0;
227                private boolean ignoreScopes=false;
228                private boolean allowLowerThan;
229                public boolean insideFunction;
230                public String tagName;
231                public boolean isCFC;
232                public boolean isInterface;
233                public short context=CTX_NONE; 
234                public DocComment docComment;
235                
236                public ExprData(Page page, EvaluatorPool ep, CFMLString cfml, TagLib[][] tlibs,FunctionLib[] flibs, TransfomerSettings settings,boolean allowLowerThan,TagLibTag[] scriptTags) {
237                        super(page,cfml,ep,settings,tlibs,flibs,scriptTags);
238                        this.allowLowerThan=allowLowerThan;
239                }
240        }
241        
242        protected Expression transformAsString(ExprData data,String[] breakConditions) throws TemplateException {
243                Expression el=null;
244                
245                // parse the houle Page String
246        comments(data);         
247                                
248                // String
249                        if((el=string(data))!=null) {
250                                data.mode=STATIC;
251                                return el;
252                        } 
253                // Sharp
254                        if((el=sharp(data))!=null) {
255                                data.mode=DYNAMIC;
256                                return el;
257                        }  
258                // Simple
259                        return simple(data,breakConditions);
260        }
261        
262        
263
264        /**
265         * Initialmethode, wird aufgerufen um den internen Zustand des Objektes zu setzten.
266         * @param fld Function Libraries zum validieren der Funktionen
267         * @param cfml CFML Code der transfomiert werden soll.
268         */
269        protected ExprData init(Page page,EvaluatorPool ep,TagLib[][] tld, FunctionLib[] fld,TagLibTag[] scriptTags, CFMLString cfml, TransfomerSettings settings, boolean allowLowerThan) {
270                ExprData data = new ExprData(page,ep,cfml,tld,fld,settings,allowLowerThan,scriptTags);
271                if(JSON_ARRAY==null)JSON_ARRAY=getFLF(data,"_literalArray");
272                if(JSON_STRUCT==null)JSON_STRUCT=getFLF(data,"_literalStruct");
273                return data;
274                //this.allowLowerThan=allowLowerThan;
275                //this.fld = fld;
276                //this.cfml = cfml;
277        }
278        
279        /**
280         * Startpunkt zum transfomieren einer Expression, ohne dass das Objekt neu initialisiert wird, 
281         * dient vererbten Objekten als Einstiegspunkt.
282         * @return Element
283         * @throws TemplateException
284         */
285        protected Expression expression(ExprData data) throws TemplateException {
286                return assignOp(data);
287        }
288
289        /**
290        * Liest einen gelableten  Funktionsparamter ein
291        * <br />
292        * EBNF:<br />
293        * <code>assignOp [":" spaces assignOp];</code>
294        * @return CFXD Element
295        * @throws TemplateException 
296        */
297        private Argument functionArgument(ExprData data, boolean varKeyUpperCase) throws TemplateException {
298                return functionArgument(data,null,varKeyUpperCase);
299        }
300        
301        private Argument functionArgument(ExprData data,String type, boolean varKeyUpperCase) throws TemplateException {
302                Expression expr = assignOp(data);
303                try{
304                        if (data.cfml.forwardIfCurrent(":")) {
305                                comments(data);
306                                return new NamedArgument(expr,assignOp(data),type,varKeyUpperCase);
307                        }
308                        else if(expr instanceof DynAssign){
309                                DynAssign da=(DynAssign) expr;
310                                return new NamedArgument(da.getName(),da.getValue(),type,varKeyUpperCase);
311                        }
312                        else if(expr instanceof Assign && !(expr instanceof OpVariable)){
313                                Assign a=(Assign) expr;
314                                return new NamedArgument(a.getVariable(),a.getValue(),type,varKeyUpperCase);
315                        }
316                }
317                catch(BytecodeException be) {
318                        throw new TemplateException(data.cfml,be.getMessage());
319                }
320                return new Argument(expr,type);
321        }
322
323        
324        
325        
326        /**
327        * Transfomiert Zuweisungs Operation.
328        * <br />
329        * EBNF:<br />
330        * <code>eqvOp ["=" spaces assignOp];</code>
331        * @return CFXD Element
332        * @throws TemplateException 
333        */
334        protected Expression assignOp(ExprData data) throws TemplateException {
335        
336                Expression expr = conditionalOp(data);
337        if (data.cfml.forwardIfCurrent('=')) {
338                
339            comments(data);
340            if(data.mode==STATIC) expr=new DynAssign(expr,assignOp(data));
341                        else {
342                                if(expr instanceof Variable) {
343                                        Expression value = assignOp(data);
344                                        expr=new Assign((Variable)expr,value,data.cfml.getPosition());
345                                }
346                                else if(expr instanceof Null) {
347                                        Variable var = ((Null)expr).toVariable();
348                                        Expression value = assignOp(data);
349                                        expr=new Assign(var,value,data.cfml.getPosition());
350                                }
351                                else
352                                        throw new TemplateException(data.cfml,"invalid assignment left-hand side ("+expr.getClass().getName()+")");
353                        }
354                }
355                return expr;
356        }
357        
358        private Expression conditionalOp(ExprData data) throws TemplateException {
359        
360                Expression expr = impOp(data);
361        if (data.cfml.forwardIfCurrent('?')) {
362                comments(data);
363                // Elvis
364                if(data.cfml.forwardIfCurrent(':')) {
365
366                        comments(data);
367                Expression right = assignOp(data);
368
369                        if (expr instanceof ExprBoolean)
370                                return expr;
371                        
372                        if(!(expr instanceof Variable) )
373                                throw new TemplateException(data.cfml,"left operant of the Elvis operator has to be a variable or a function call");
374                        
375                        return OpElvis.toExpr((Variable)expr, right);
376                }
377                
378                Expression left = assignOp(data);
379                comments(data);
380                if(!data.cfml.forwardIfCurrent(':'))throw new TemplateException("invalid conditional operator");
381                comments(data); 
382                Expression right = assignOp(data);
383                
384            expr=OpContional.toExpr(expr, left, right);
385                }
386                return expr;
387        }
388
389        /**
390        * Transfomiert eine Implication (imp) Operation.
391        * <br />
392        * EBNF:<br />
393        * <code>eqvOp {"imp" spaces eqvOp};</code>
394        * @return CFXD Element
395        * @throws TemplateException 
396        */
397        private Expression impOp(ExprData data) throws TemplateException {
398                Expression expr = eqvOp(data);
399                while(data.cfml.forwardIfCurrentAndNoWordAfter("imp")) { 
400                        comments(data);
401            expr=OpBool.toExprBoolean(expr, eqvOp(data), OpBool.IMP);
402                }
403                return expr;
404        }
405
406        /**
407        * Transfomiert eine  Equivalence (eqv) Operation.
408        * <br />
409        * EBNF:<br />
410        * <code>xorOp {"eqv" spaces xorOp};</code>
411        * @return CFXD Element
412        * @throws TemplateException 
413        */
414        private Expression eqvOp(ExprData data) throws TemplateException {
415                Expression expr = xorOp(data);
416                while(data.cfml.forwardIfCurrentAndNoWordAfter("eqv")) {
417                        comments(data);
418            expr=OpBool.toExprBoolean(expr, xorOp(data), OpBool.EQV);
419                }
420                return expr;
421        }
422
423        /**
424        * Transfomiert eine  Xor (xor) Operation.
425        * <br />
426        * EBNF:<br />
427        * <code>orOp {"xor" spaces  orOp};</code>
428        * @return CFXD Element
429        * @throws TemplateException 
430        */
431        private Expression xorOp(ExprData data) throws TemplateException {
432                Expression expr = orOp(data);
433                while(data.cfml.forwardIfCurrentAndNoWordAfter("xor")) {
434                        comments(data);
435            expr=OpBool.toExprBoolean(expr, orOp(data), OpBool.XOR);
436                }
437                return expr;
438        }
439
440        /**
441        * Transfomiert eine  Or (or) Operation. Im Gegensatz zu CFMX ,
442        * werden "||" Zeichen auch als Or Operatoren anerkannt.
443        * <br />
444        * EBNF:<br />
445        * <code>andOp {("or" | "||") spaces andOp}; (* "||" Existiert in CFMX nicht *)</code>
446        * @return CFXD Element
447        * @throws TemplateException 
448        */
449        private Expression orOp(ExprData data) throws TemplateException {
450                Expression expr = andOp(data);
451                
452                while(data.cfml.forwardIfCurrent("||") || data.cfml.forwardIfCurrentAndNoWordAfter("or")) {
453                        comments(data);
454            expr=OpBool.toExprBoolean(expr, andOp(data), OpBool.OR);
455                }
456                return expr;
457        }
458
459        /**
460        * Transfomiert eine  And (and) Operation. Im Gegensatz zu CFMX ,
461        * werden "&&" Zeichen auch als And Operatoren anerkannt.
462        * <br />
463        * EBNF:<br />
464        * <code>notOp {("and" | "&&") spaces notOp}; (* "&&" Existiert in CFMX nicht *)</code>
465        * @return CFXD Element
466        * @throws TemplateException 
467        */
468        private Expression andOp(ExprData data) throws TemplateException {
469                Expression expr = notOp(data);
470                
471                while(data.cfml.forwardIfCurrent("&&") || data.cfml.forwardIfCurrentAndNoWordAfter("and")) {
472                        comments(data);
473                expr=OpBool.toExprBoolean(expr, notOp(data), OpBool.AND);
474                }
475                return expr;
476        }
477
478        /**
479        * Transfomiert eine  Not (not) Operation. Im Gegensatz zu CFMX ,
480        * wird das "!" Zeichen auch als Not Operator anerkannt.
481        * <br />
482        * EBNF:<br />
483        * <code>[("not"|"!") spaces] decsionOp; (* "!" Existiert in CFMX nicht *)</code>
484        * @return CFXD Element
485        * @throws TemplateException 
486        */
487        private Expression notOp(ExprData data) throws TemplateException {
488                // And Operation
489                Position line = data.cfml.getPosition();
490                if (data.cfml.isCurrent('!') && !data.cfml.isCurrent("!=")) {
491                        data.cfml.next();
492                        comments(data);
493                        return OpNegate.toExprBoolean(notOp(data),line,data.cfml.getPosition());
494                }
495                else if (data.cfml.forwardIfCurrentAndNoWordAfter("not")) {
496                        comments(data);
497                        return OpNegate.toExprBoolean(notOp(data),line,data.cfml.getPosition());
498                }
499                return decsionOp(data);
500        }
501
502        /**
503        * <font f>Transfomiert eine Vergleichs Operation.
504        * <br />
505        * EBNF:<br />
506        * <code>concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"|
507                         "contains"|"nct"|"does not contain") spaces concatOp}; 
508                        (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *)</code>
509        * @return CFXD Element
510        * @throws TemplateException 
511        */
512        private Expression decsionOp(ExprData data) throws TemplateException {
513
514                Expression expr = concatOp(data);
515                boolean hasChanged=false;
516                // ct, contains
517                do {
518                        hasChanged=false;
519                        if(data.cfml.isCurrent('c')) {
520                                        if (data.cfml.forwardIfCurrent("ct",false,true)) {expr = decisionOpCreate(data,OPDecision.CT,expr);hasChanged=true;} 
521                                        else if (data.cfml.forwardIfCurrent("contains",false,true)){ expr = decisionOpCreate(data,OPDecision.CT,expr);hasChanged=true;}
522                        }
523                        // does not contain
524                        else if (data.cfml.forwardIfCurrent("does","not","contain",false,true)){ expr = decisionOpCreate(data,OPDecision.NCT,expr); hasChanged=true;}
525
526                        // equal, eq
527                        else if (data.cfml.isCurrent("eq") && !data.cfml.isCurrent("eqv")) {
528                                int plus=2;
529                                data.cfml.setPos(data.cfml.getPos()+2);
530                                if(data.cfml.forwardIfCurrent("ual"))plus=5;
531                                
532                                if(data.cfml.isCurrentVariableCharacter()) {
533                                        data.cfml.setPos(data.cfml.getPos()-plus);
534                                }
535                                else {
536                                        expr = decisionOpCreate(data,OPDecision.EQ,expr);
537                                        hasChanged=true;
538                                }
539                                
540                        }
541                        // ==
542                        else if (data.cfml.forwardIfCurrent("==")) {
543                                if(data.cfml.forwardIfCurrent('='))             expr = decisionOpCreate(data,OPDecision.EEQ,expr);
544                                else expr = decisionOpCreate(data,OPDecision.EQ,expr);
545                                hasChanged=true;
546                        }
547                        // !=
548                        else if (data.cfml.forwardIfCurrent("!=")) {
549                                if(data.cfml.forwardIfCurrent('='))             expr = decisionOpCreate(data,OPDecision.NEEQ,expr);
550                                else expr = decisionOpCreate(data,OPDecision.NEQ,expr); 
551                                hasChanged=true;
552                        }
553                        // <=/</<>
554                        else if (data.cfml.isCurrent('<')) {
555                                hasChanged=true;
556                                if(data.cfml.isNext('='))       {
557                                        data.cfml.next();data.cfml.next();
558                                        expr = decisionOpCreate(data,OPDecision.LTE,expr);
559                                }
560                                else if(data.cfml.isNext('>')) {
561                                        data.cfml.next();data.cfml.next();
562                                        expr = decisionOpCreate(data,OPDecision.NEQ,expr);
563                                }
564                                else if(data.cfml.isNext('/')) {
565                                        hasChanged=false;
566                                }
567                                else    {
568                                        data.cfml.next();
569                                        expr = decisionOpCreate(data,OPDecision.LT,expr); 
570                                }
571                        }
572                        // >=/>
573                        else if (data.allowLowerThan && data.cfml.forwardIfCurrent('>')) {
574                                if(data.cfml.forwardIfCurrent('='))     expr = decisionOpCreate(data,OPDecision.GTE,expr);
575                                else                                                    expr = decisionOpCreate(data,OPDecision.GT,expr); 
576                                hasChanged=true;
577                        }
578                        
579                        // gt, gte, greater than or equal to, greater than
580                        else if (data.cfml.isCurrent('g')) {
581                                if (data.cfml.forwardIfCurrent("gt")) {
582                                        if(data.cfml.forwardIfCurrentAndNoWordAfter("e")) {
583                                                if(data.cfml.isCurrentVariableCharacter()) {
584                                                        data.cfml.setPos(data.cfml.getPos()-3);
585                                                }
586                                                else {
587                                                        expr = decisionOpCreate(data,OPDecision.GTE,expr);
588                                                        hasChanged=true;
589                                                }
590                                        }
591                                        else {
592                                                if(data.cfml.isCurrentVariableCharacter()) {
593                                                        data.cfml.setPos(data.cfml.getPos()-2);
594                                                }
595                                                else {
596                                                        expr = decisionOpCreate(data,OPDecision.GT,expr);
597                                                        hasChanged=true;
598                                                }
599                                        }
600                                } 
601                                else if (data.cfml.forwardIfCurrent("greater", "than",false,true)) {
602                                        if(data.cfml.forwardIfCurrent("or","equal", "to",true,true)) expr = decisionOpCreate(data,OPDecision.GTE,expr);
603                                        else expr = decisionOpCreate(data,OPDecision.GT,expr);
604                                        hasChanged=true;
605                                }       
606                                else if (data.cfml.forwardIfCurrent("ge",false,true)) {
607                                        expr = decisionOpCreate(data,OPDecision.GTE,expr);
608                                        hasChanged=true;
609                                }                               
610                        }
611                        
612                        // is, is not
613                        else if (data.cfml.forwardIfCurrent("is",false,true)) {
614                                if(data.cfml.forwardIfCurrent("not",true,true)) expr = decisionOpCreate(data,OPDecision.NEQ,expr);
615                                else expr = decisionOpCreate(data,OPDecision.EQ,expr);
616                                hasChanged=true;
617                        }
618                        
619                        // lt, lte, less than, less than or equal to
620                        else if (data.cfml.isCurrent('l')) {
621                                if (data.cfml.forwardIfCurrent("lt")) {
622                                        if(data.cfml.forwardIfCurrentAndNoWordAfter("e")) {
623                                                if(data.cfml.isCurrentVariableCharacter()) {
624                                                        data.cfml.setPos(data.cfml.getPos()-3);
625                                                }
626                                                else {
627                                                        expr = decisionOpCreate(data,OPDecision.LTE,expr);
628                                                        hasChanged=true;
629                                                }
630                                        }
631                                        else {
632                                                if(data.cfml.isCurrentVariableCharacter()) {
633                                                        data.cfml.setPos(data.cfml.getPos()-2);
634                                                }
635                                                else {
636                                                        expr = decisionOpCreate(data,OPDecision.LT,expr);
637                                                        hasChanged=true;
638                                                }
639                                        }
640                                } 
641                                else if (data.cfml.forwardIfCurrent("less","than",false,true)) {
642                                        if(data.cfml.forwardIfCurrent("or", "equal", "to",true,true)) expr = decisionOpCreate(data,OPDecision.LTE,expr);
643                                        else expr = decisionOpCreate(data,OPDecision.LT,expr);
644                                        hasChanged=true;
645                                }       
646                                else if (data.cfml.forwardIfCurrent("le",false,true)) {
647                                        expr = decisionOpCreate(data,OPDecision.LTE,expr);
648                                        hasChanged=true;
649                                }                               
650                        }
651                        
652                        // neq, not equal, nct
653                        else if (data.cfml.isCurrent('n')) {
654                                // Not Equal
655                                        if (data.cfml.forwardIfCurrent("neq",false,true)){ expr = decisionOpCreate(data,OPDecision.NEQ,expr); hasChanged=true;}
656                                // Not Equal (Alias)
657                                        else if (data.cfml.forwardIfCurrent("not","equal",false,true)){ expr = decisionOpCreate(data,OPDecision.NEQ,expr);hasChanged=true; }
658                                // nct
659                                        else if (data.cfml.forwardIfCurrent("nct",false,true)){ expr = decisionOpCreate(data,OPDecision.NCT,expr); hasChanged=true;}    
660                        }
661                        
662                }
663                while(hasChanged);
664                return expr;
665        }
666        private Expression decisionOpCreate(ExprData data,int operation, Expression left) throws TemplateException {
667        comments(data);
668        return OPDecision.toExprBoolean(left, concatOp(data), operation);
669        }
670
671        /**
672        * Transfomiert eine  Konkatinations-Operator (&) Operation. Im Gegensatz zu CFMX ,
673        * wird das "!" Zeichen auch als Not Operator anerkannt.
674        * <br />
675        * EBNF:<br />
676        * <code>plusMinusOp {"&" spaces concatOp};</code>
677        * @return CFXD Element
678        * @throws TemplateException 
679        */
680        private Expression concatOp(ExprData data) throws TemplateException {
681                Expression expr = plusMinusOp(data);
682                
683                while(data.cfml.isCurrent('&') && !data.cfml.isCurrent("&&")) {
684                        data.cfml.next();
685                        
686                        // &=
687                        if (data.cfml.isCurrent('=') && expr instanceof Variable) {
688                                data.cfml.next();
689                                comments(data);
690                                Expression value = assignOp(data);
691                                
692                                expr = new OPUnary((Variable)expr,value,OPUnary.PRE,OPUnary.CONCAT,expr.getStart(),data.cfml.getPosition());
693                                
694                                
695                                //ExprString res = OpString.toExprString(expr, right);
696                                //expr=new OpVariable((Variable)expr,res,data.cfml.getPosition());
697                        }
698                        else {
699                    comments(data);
700                    expr=OpString.toExprString(expr, plusMinusOp(data));
701                        }
702                        
703                }
704                return expr;
705        }
706
707        /**
708        * Transfomiert die mathematischen Operatoren Plus und Minus (1,-).
709        * <br />
710        * EBNF:<br />
711        * <code>modOp [("-"|"+") spaces plusMinusOp];</code>
712        * @return CFXD Element
713        * @throws TemplateException 
714        */
715        private Expression plusMinusOp(ExprData data) throws TemplateException {
716                Expression expr = modOp(data);
717                
718                while(!data.cfml.isLast()) {
719                        
720                        // Plus Operation
721                        if (data.cfml.forwardIfCurrent('+'))                    expr=_plusMinusOp(data,expr,OpDouble.PLUS);
722                        // Minus Operation
723                        else if (data.cfml.forwardIfCurrent('-'))       expr=_plusMinusOp(data,expr,OpDouble.MINUS);
724                        else break;
725                }
726                return expr;
727        }
728        
729        
730
731        private Expression _plusMinusOp(ExprData data,Expression expr,int opr) throws TemplateException {
732                // +=
733                // plus|Minus Assignment
734                if (data.cfml.isCurrent('=') && expr instanceof Variable) {
735                        data.cfml.next();
736                        comments(data);
737                        Expression value = assignOp(data);
738                        //if(opr==OpDouble.MINUS) value=OpNegateNumber.toExprDouble(value, null, null);
739                        
740                        expr = new OPUnary((Variable)expr,value,OPUnary.PRE,opr,expr.getStart(),data.cfml.getPosition());
741                        
742                        //ExprDouble res = OpDouble.toExprDouble(expr, right,opr);
743                        //expr=new OpVariable((Variable)expr,res,data.cfml.getPosition());
744                }
745                
746                else {
747                        comments(data);
748            expr=OpDouble.toExprDouble(expr, modOp(data), opr); 
749                }
750                return expr;
751        }
752        
753
754        /**
755        * Transfomiert eine Modulus Operation. Im Gegensatz zu CFMX ,
756        * wird das "%" Zeichen auch als Modulus Operator anerkannt.
757        * <br />
758        * EBNF:<br />
759        * <code>divMultiOp {("mod" | "%") spaces divMultiOp}; (* modulus operator , "%" Existiert in CFMX nicht *)</code>
760        * @return CFXD Element
761        * @throws TemplateException 
762        */
763        private Expression modOp(ExprData data) throws TemplateException {
764                Expression expr = divMultiOp(data);
765                
766                // Modulus Operation
767                while(data.cfml.forwardIfCurrent('%') || data.cfml.forwardIfCurrentAndNoWordAfter("mod")) {
768                        expr=_modOp(data,expr);
769                        //comments(data);
770            //expr=OpDouble.toExprDouble(expr, divMultiOp(), OpDouble.MODULUS);
771                }
772                return expr;
773        }
774        
775        private Expression _modOp(ExprData data,Expression expr) throws TemplateException {
776                if (data.cfml.isCurrent('=') && expr instanceof Variable) {
777                        data.cfml.next();
778                        comments(data);
779                        Expression right = assignOp(data);
780                        ExprDouble res = OpDouble.toExprDouble(expr, right,OpDouble.MODULUS);
781                        return new OpVariable((Variable)expr,res,data.cfml.getPosition());
782                }
783        comments(data);
784        return OpDouble.toExprDouble(expr, expoOp(data), OpDouble.MODULUS);
785        }
786
787        /**
788        * Transfomiert die mathematischen Operatoren Mal und Durch (*,/).
789        * <br />
790        * EBNF:<br />
791        * <code>expoOp {("*"|"/") spaces expoOp};</code>
792        * @return CFXD Element
793        * @throws TemplateException 
794        */
795        private Expression divMultiOp(ExprData data) throws TemplateException {
796                Expression expr = expoOp(data);
797
798                while (!data.cfml.isLast()) {
799                        
800                                // Multiply Operation
801                                if(data.cfml.forwardIfCurrent('*')) {
802                                        expr=_divMultiOp(data,expr,OpDouble.MULTIPLY);
803                                        //comments(data);
804                    //expr=OpDouble.toExprDouble(expr, expoOp(), OpDouble.MULTIPLY);
805                                }
806                                // Divide Operation
807                                else if (data.cfml.isCurrent('/') && (!data.cfml.isCurrent('/','>') )) {
808                                        data.cfml.next(); 
809                                        expr=_divMultiOp(data,expr,OpDouble.DIVIDE);
810                                        //comments(data);
811                    //expr=OpDouble.toExprDouble(expr, expoOp(), OpDouble.DIVIDE);
812                                }
813                                // Divide Operation
814                                else if (data.cfml.isCurrent('\\')) {
815                                        data.cfml.next(); 
816                                        expr=_divMultiOp(data,expr,OpDouble.INTDIV);
817                                        //comments(data);
818                    //expr=OpDouble.toExprDouble(expr, expoOp(), OpDouble.INTDIV);
819                                }
820                                else {
821                                        break;
822                                }
823                        
824                }
825                return expr;
826        }
827
828        private Expression _divMultiOp(ExprData data,Expression expr, int iOp) throws TemplateException {
829                if (data.cfml.isCurrent('=') && expr instanceof Variable) {
830                        data.cfml.next();
831                        comments(data);
832                        Expression value = assignOp(data);
833                        
834                        return new OPUnary((Variable)expr,value,OPUnary.PRE,iOp,expr.getStart(),data.cfml.getPosition());
835                        
836                        
837                        
838                        
839                        //ExprDouble res = OpDouble.toExprDouble(expr, right,iOp);
840                        //return new OpVariable((Variable)expr,res,data.cfml.getPosition());
841                }
842        comments(data);
843        return OpDouble.toExprDouble(expr, expoOp(data), iOp);
844        }
845
846        /**
847        * Transfomiert den Exponent Operator (^,exp). Im Gegensatz zu CFMX ,
848        * werden die Zeichen " exp " auch als Exponent anerkannt.
849        * <br />
850        * EBNF:<br />
851        * <code>clip {("exp"|"^") spaces clip};</code>
852        * @return CFXD Element
853        * @throws TemplateException 
854        */
855        private Expression expoOp(ExprData data) throws TemplateException {
856                Expression expr = unaryOp(data);
857
858                // Modulus Operation
859                while(data.cfml.forwardIfCurrent('^') || data.cfml.forwardIfCurrentAndNoWordAfter("exp")) {
860                        comments(data);
861            expr=OpDouble.toExprDouble(expr, unaryOp(data), OpDouble.EXP);
862                }
863                return expr;
864        }
865        
866        private Expression unaryOp(ExprData data) throws TemplateException {
867                Expression expr = negatePlusMinusOp(data);
868                
869                // Plus Operation
870                if (data.cfml.forwardIfCurrent("++") && expr instanceof Variable)                       
871                        expr=_unaryOp(data,expr,OpDouble.PLUS);
872                // Minus Operation
873                else if (data.cfml.forwardIfCurrent("--") && expr instanceof Variable)  
874                        expr=_unaryOp(data,expr,OpDouble.MINUS);
875                return expr;
876        }
877        
878        private Expression _unaryOp(ExprData data,Expression expr,int op) throws TemplateException {
879                Position leftEnd = expr.getEnd(),start=null,end=null;
880                comments(data);
881                if(leftEnd!=null){
882                        start=leftEnd;
883                        end=new Position(leftEnd.line, leftEnd.column+2, leftEnd.pos+2);
884                }
885                return new OPUnary((Variable)expr,LitDouble.ONE,OPUnary.POST,op,start,end);
886                
887                
888                
889                //ExprDouble res = OpDouble.toExprDouble(expr, LitDouble.toExprDouble(1D,start,end),opr);
890                //expr=new OpVariable((Variable)expr,res,data.cfml.getPosition());
891                //return OpDouble.toExprDouble(expr,LitDouble.toExprDouble(1D,start,end),opr==OpDouble.PLUS? OpDouble.MINUS:OpDouble.PLUS);
892        }
893        
894        
895        
896
897        /**
898        * Negate Numbers
899        * @return CFXD Element
900        * @throws TemplateException 
901        */
902        private Expression negatePlusMinusOp(ExprData data) throws TemplateException {
903                // And Operation
904                Position line=data.cfml.getPosition();
905                if (data.cfml.forwardIfCurrent('-')) {
906                        // pre increment
907                        if (data.cfml.forwardIfCurrent('-')) {
908                                comments(data);
909                                Expression expr = clip(data);
910                                return new OPUnary((Variable)expr,LitDouble.ONE,OPUnary.PRE,OpDouble.MINUS,line,data.cfml.getPosition());
911                                
912                                //ExprDouble res = OpDouble.toExprDouble(expr, LitDouble.toExprDouble(1D),OpDouble.MINUS);
913                                //return new OpVariable((Variable)expr,res,data.cfml.getPosition());
914                                
915                                
916                        }
917                        comments(data);
918                        return OpNegateNumber.toExprDouble(clip(data),OpNegateNumber.MINUS,line,data.cfml.getPosition());
919                        
920                }
921                else if (data.cfml.forwardIfCurrent('+')) {
922                        if (data.cfml.forwardIfCurrent('+')) {
923                                comments(data);
924                                Expression expr = clip(data);
925                                
926                                return new OPUnary((Variable)expr,LitDouble.ONE,OPUnary.PRE,OpDouble.PLUS,line,data.cfml.getPosition());
927                                
928                                //ExprDouble res = OpDouble.toExprDouble(expr, LitDouble.toExprDouble(1D),OpDouble.PLUS);
929                                //return new OpVariable((Variable)expr,res,data.cfml.getPosition());
930                        }
931                        comments(data);
932                        return CastDouble.toExprDouble(clip(data));//OpNegateNumber.toExprDouble(clip(),OpNegateNumber.PLUS,line);
933                }
934                return clip(data);
935        }
936
937        /**
938        * Verarbeitet Ausdruecke die inerhalb einer Klammer stehen.
939        * <br />
940        * EBNF:<br />
941        * <code>("(" spaces impOp ")" spaces) | checker;</code>
942        * @return CFXD Element
943        * @throws TemplateException 
944        */
945        private Expression clip(ExprData data) throws TemplateException {
946            return checker(data);
947        }
948        /**
949        * Hier werden die verschiedenen Moeglichen Werte erkannt 
950        * und jenachdem wird mit der passenden Methode weitergefahren
951        * <br />
952        * EBNF:<br />
953        * <code>string | number | dynamic | sharp;</code>
954        * @return CFXD Element
955        * @throws TemplateException 
956        */
957        private Expression checker(ExprData data) throws TemplateException {
958                Expression expr=null;
959                        // String
960                        if((expr=string(data))!=null) {
961                                expr = subDynamic(data,expr);
962                                data.mode=STATIC;//(expr instanceof Literal)?STATIC:DYNAMIC;// STATIC
963                                return expr;
964                        } 
965                // Number
966                        if((expr=number(data))!=null) {
967                                expr = subDynamic(data,expr);
968                                data.mode=STATIC;//(expr instanceof Literal)?STATIC:DYNAMIC;// STATIC
969                                return expr;
970                        }
971                        // closure
972                        if((expr=closure(data))!=null) {
973                                data.mode=DYNAMIC;
974                                return expr;
975                        } 
976                        
977                // Dynamic
978                        if((expr=dynamic(data))!=null) {
979                                expr = newOp(data, expr);
980                                expr = subDynamic(data,expr);
981                                data.mode=DYNAMIC;
982                                return expr;
983                        } 
984                // Sharp
985                        if((expr=sharp(data))!=null) {
986                                data.mode=DYNAMIC;
987                                return expr;
988                        } 
989                // JSON
990                        if((expr=json(data,JSON_ARRAY,'[',']'))!=null) {
991                                expr = subDynamic(data,expr);
992                                data.mode=DYNAMIC;
993                                return expr;
994                        } 
995                        if((expr=json(data,JSON_STRUCT,'{','}'))!=null) {
996                                expr = subDynamic(data,expr);
997                                data.mode=DYNAMIC;
998                                return expr;
999                        } 
1000                // else Error
1001                        throw new TemplateException(data.cfml,"Syntax Error, Invalid Construct");       
1002        }
1003        
1004        /*private Expression variable(Data data) throws TemplateException {
1005                Expression expr=null;
1006                
1007                // Dynamic
1008                if((expr=dynamic(data))!=null) {
1009                        expr = subDynamic(data,expr);
1010                        data.mode=DYNAMIC;
1011                        return expr;
1012                } 
1013                return null;
1014        }*/
1015        
1016        /**
1017        * Transfomiert einen lierale Zeichenkette.
1018        * <br />
1019        * EBNF:<br />
1020        * <code>("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") | 
1021                         (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """);</code>
1022         * @param data 
1023        * @return CFXD Element
1024        * @throws TemplateException 
1025        */
1026        protected Expression string(ExprData data) throws TemplateException {
1027                
1028                // check starting character for a string literal
1029                if(!data.cfml.isCurrent('"')&& !data.cfml.isCurrent('\''))
1030                        return null;
1031                Position line = data.cfml.getPosition();
1032                
1033                // Init Parameter
1034                char quoter = data.cfml.getCurrentLower();
1035                StringBuilder str=new StringBuilder();
1036                Expression expr=null;
1037                
1038                while(data.cfml.hasNext()) {
1039                        data.cfml.next();
1040                        // check sharp
1041                        if(data.cfml.isCurrent('#')) {
1042                                
1043                                // Ecaped sharp
1044                                if(data.cfml.isNext('#')){
1045                                        data.cfml.next();
1046                                        str.append('#');
1047                                }
1048                                // get Content of sharp
1049                                else {
1050                                        data.cfml.next();
1051                    comments(data);
1052                                        Expression inner=assignOp(data);
1053                    comments(data);
1054                                        if (!data.cfml.isCurrent('#'))
1055                                                throw new TemplateException(data.cfml,"Invalid Syntax Closing [#] not found");
1056                                        
1057                                        ExprString exprStr=null;
1058                                        if(str.length()!=0) {
1059                                                exprStr=LitString.toExprString(str.toString(),line,data.cfml.getPosition());
1060                                                if(expr!=null){
1061                                                        expr = OpString.toExprString(expr, exprStr);
1062                                                }
1063                                                else expr=exprStr;
1064                                                str=new StringBuilder();
1065                                        }
1066                                        if(expr==null) {
1067                                                expr=inner;
1068                                        }
1069                                        else  {
1070                                                expr = OpString.toExprString(expr, inner);
1071                                        }       
1072                                }
1073                        }
1074                        // check quoter
1075                        else if(data.cfml.isCurrent(quoter)) {
1076                                // Ecaped sharp
1077                                if(data.cfml.isNext(quoter)){
1078                                        data.cfml.next();
1079                                        str.append(quoter);
1080                                }
1081                                // finsish
1082                                else {
1083                                        break;
1084                                }                               
1085                        }
1086                        // all other character
1087                        else {
1088                                str.append(data.cfml.getCurrent());
1089                        }
1090                }
1091                if(!data.cfml.forwardIfCurrent(quoter))
1092                        throw new TemplateException(data.cfml,"Invalid Syntax Closing ["+quoter+"] not found");
1093                
1094                if(expr==null)
1095                        expr=LitString.toExprString(str.toString(),line,data.cfml.getPosition());
1096                else if(str.length()!=0) {
1097                        expr = OpString.toExprString(expr, LitString.toExprString(str.toString(),line,data.cfml.getPosition()));
1098                }
1099        comments(data);
1100        
1101        if(expr instanceof Variable) {
1102                Variable var=(Variable) expr;
1103                var.setFromHash(true);
1104        }
1105        
1106                return expr;
1107                
1108        }
1109
1110        /**
1111        * Transfomiert einen numerische Wert. 
1112        * Die Laenge des numerischen Wertes interessiert nicht zu Uebersetzungszeit, 
1113        * ein "Overflow" fuehrt zu einem Laufzeitfehler. 
1114        * Da die zu erstellende CFXD, bzw. dieser Transfomer, keine Vorwegnahme des Laufzeitsystems vornimmt. 
1115        * <br />
1116        * EBNF:<br />
1117        * <code>["+"|"-"] digit {digit} {"." digit {digit}};</code>
1118        * @return CFXD Element
1119        * @throws TemplateException 
1120        */
1121        private LitDouble number(ExprData data) throws TemplateException {
1122                // check first character is a number literal representation
1123                if(!(data.cfml.isCurrentBetween('0','9') || data.cfml.isCurrent('.'))) return null;
1124                
1125                Position line = data.cfml.getPosition();
1126                StringBuffer rtn=new StringBuffer();
1127                
1128                // get digit on the left site of the dot
1129                if(data.cfml.isCurrent('.')) rtn.append('0');
1130                else rtn.append(digit(data));
1131                // read dot if exist
1132                if(data.cfml.forwardIfCurrent('.')) {
1133                        rtn.append('.');
1134                        String rightSite=digit(data);
1135                        if(rightSite.length()> 0 && data.cfml.forwardIfCurrent('e')) {
1136                                Boolean expOp=null;
1137                                if(data.cfml.forwardIfCurrent('+')) expOp=Boolean.TRUE;
1138                                else if(data.cfml.forwardIfCurrent('-')) expOp=Boolean.FALSE;
1139                                
1140                                if(data.cfml.isCurrentBetween('0','9')) {
1141                                        if(expOp==Boolean.FALSE) rightSite+="e-";
1142                                        else if(expOp==Boolean.TRUE) rightSite+="e+";
1143                                        else rightSite+="e";
1144                                rightSite+=digit(data);
1145                            }
1146                            else {
1147                                if(expOp!=null) data.cfml.previous();
1148                                data.cfml.previous();
1149                            }
1150                        }
1151                        // read right side of the dot
1152                        if(rightSite.length()==0)
1153                                rightSite="0";//throw new TemplateException(cfml, "Number can't end with [.]"); // DIFF 23
1154                        rtn.append(rightSite);
1155                }
1156                else if(data.cfml.forwardIfCurrent('e')) {
1157                        Boolean expOp=null;
1158                        if(data.cfml.forwardIfCurrent('+')) expOp=Boolean.TRUE;
1159                        else if(data.cfml.forwardIfCurrent('-')) expOp=Boolean.FALSE;
1160                        
1161                        if(data.cfml.isCurrentBetween('0','9')) {
1162                                String rightSite = "e";
1163                                if(expOp==Boolean.FALSE) rightSite+="-";
1164                                else if(expOp==Boolean.TRUE) rightSite+="+";
1165                        rightSite+=digit(data);
1166                        rtn.append(rightSite);
1167                    }
1168                    else {
1169                        if(expOp!=null) data.cfml.previous();
1170                        data.cfml.previous();
1171                    }
1172
1173                }
1174        comments(data);
1175        
1176                try {
1177                        return LitDouble.toExprDouble(Caster.toDoubleValue(rtn.toString()),line,data.cfml.getPosition());
1178                } catch (CasterException e) {
1179                        throw new TemplateException(data.cfml,e.getMessage());
1180                }
1181                
1182        }
1183        
1184        
1185        
1186        /**
1187        * Liest die reinen Zahlen innerhalb des CFMLString aus und gibt diese als Zeichenkette zurueck. 
1188        * <br />
1189        * EBNF:<br />
1190        * <code>"0"|..|"9";</code>
1191        * @return digit Ausgelesene Zahlen als Zeichenkette.
1192        */
1193        private String digit(ExprData data) {
1194                String rtn="";
1195                while (data.cfml.isValidIndex()) {
1196                        if(!data.cfml.isCurrentBetween('0','9'))break;
1197                        rtn+=data.cfml.getCurrentLower();
1198                        data.cfml.next();
1199                }
1200                return rtn;
1201        }
1202
1203        /**
1204        * Liest den folgenden idetifier ein und prueft ob dieser ein boolscher Wert ist. 
1205        * Im Gegensatz zu CFMX wird auch "yes" und "no" als bolscher <wert akzeptiert, 
1206        * was bei CFMX nur beim Umwandeln einer Zeichenkette zu einem boolschen Wert der Fall ist.<br />
1207        * Wenn es sich um keinen bolschen Wert handelt wird der folgende Wert eingelesen mit seiner ganzen Hirarchie.
1208        * <br />
1209        * EBNF:<br />
1210        * <code>"true" | "false" | "yes" | "no" | startElement {("." identifier | "[" structElement "]" )[function] };</code>
1211        * @return CFXD Element
1212        * @throws TemplateException 
1213        */
1214        private Expression dynamic(ExprData data) throws TemplateException {
1215                // Die Implementation weicht ein wenig von der Grammatik ab, 
1216                // aber nicht in der Logik sondern rein wie es umgesetzt wurde.
1217                
1218            
1219            
1220                // get First Element of the Variable
1221                Position line = data.cfml.getPosition();
1222                Identifier id = identifier(data,false,true);
1223                if(id == null) {
1224                    if (!data.cfml.forwardIfCurrent('(')) return null;
1225                    
1226            comments(data);
1227                        Expression expr = assignOp(data);
1228
1229                        if (!data.cfml.forwardIfCurrent(')'))
1230                                throw new TemplateException(
1231                                        data.cfml,
1232                                        "Invalid Syntax Closing [)] not found");
1233            comments(data);
1234            return expr;//subDynamic(expr);
1235            
1236                }
1237                        
1238                Variable var;
1239        comments(data);
1240                
1241                // Boolean constant 
1242                if(id.getString().equalsIgnoreCase("TRUE"))     {// || name.equals("YES"))      {
1243                        comments(data);
1244                        return new LitBoolean(true,line,data.cfml.getPosition());
1245                }
1246                else if(id.getString().equalsIgnoreCase("FALSE"))       {// || name.equals("NO"))       {
1247                        comments(data);
1248                        return new LitBoolean(false,line,data.cfml.getPosition());
1249                }
1250                else if(NullSupportHelper.full() && id.getString().equalsIgnoreCase("NULL"))    {
1251                        comments(data);
1252                        return new Null(line,data.cfml.getPosition());
1253                }
1254                
1255                // Extract Scope from the Variable
1256                //int c=data.cfml.getColumn();
1257                //Position l=data.cfml.getPosition();
1258                var = startElement(data,id,line);
1259                var.setStart(line);
1260                var.setEnd(data.cfml.getPosition());
1261                return var;
1262        }
1263        
1264
1265        
1266        protected Expression json(ExprData data,FunctionLibFunction flf, char start, char end) throws TemplateException {
1267                if(!data.cfml.forwardIfCurrent(start))return null;
1268                
1269                Position line = data.cfml.getPosition();
1270                BIF bif=new BIF(flf.getName(),flf);
1271                bif.setArgType(flf.getArgType());
1272                bif.setClass(flf.getClazz());
1273                bif.setReturnType(flf.getReturnTypeAsString());
1274                
1275                do {
1276                        comments(data);
1277                        if (data.cfml.isCurrent(end))break;
1278                        
1279                        bif.addArgument(functionArgument(data,data.settings.dotNotationUpper));
1280                        comments(data);
1281                } 
1282                while (data.cfml.forwardIfCurrent(','));
1283                comments(data);
1284                        
1285                if (!data.cfml.forwardIfCurrent(end))
1286                        throw new TemplateException(data.cfml,"Invalid Syntax Closing ["+end+"] not found");
1287                comments(data);
1288                Variable var=new Variable(line,data.cfml.getPosition());
1289                var.addMember(bif);
1290                return var;
1291        }
1292        
1293        private Expression closure(ExprData data) throws TemplateException {
1294                if(!data.cfml.forwardIfCurrent("function",'('))return null;
1295                data.cfml.previous();
1296                return new ClosureAsExpression((Closure) closurePart(data, "closure_"+CreateUniqueId.invoke(), Component.ACCESS_PUBLIC, "any", data.cfml.getPosition(),true));
1297        }
1298        
1299        protected  abstract Function closurePart(ExprData data, String id, int access, String rtnType, Position line,boolean closure) throws TemplateException;
1300
1301        
1302        protected FunctionLibFunction getFLF(ExprData data,String name) {
1303                FunctionLibFunction flf=null;
1304                for (int i = 0; i < data.flibs.length; i++) {
1305                        flf = data.flibs[i].getFunction(name);
1306                        if (flf != null)
1307                                break;
1308                }
1309                return flf;
1310        }
1311
1312        private Expression subDynamic(ExprData data,Expression expr) throws TemplateException {
1313                
1314                
1315                
1316
1317            String name=null;
1318            Invoker invoker=null;
1319                // Loop over nested Variables
1320                while (data.cfml.isValidIndex()) {
1321                        ExprString nameProp = null,namePropUC = null;
1322                        // .
1323                        if (data.cfml.forwardIfCurrent('.')) {
1324                                // Extract next Var String
1325                comments(data);
1326                Position line=data.cfml.getPosition();
1327                name = identifier(data,true);
1328                                if(name==null) 
1329                                        throw new TemplateException(data.cfml, "Invalid identifier");
1330                comments(data);
1331                                nameProp=Identifier.toIdentifier(name,line,data.cfml.getPosition());
1332                                namePropUC=Identifier.toIdentifier(name,data.settings.dotNotationUpper?Identifier.CASE_UPPER:Identifier.CASE_ORIGNAL,line,data.cfml.getPosition());
1333                        }
1334                        // []
1335                        else if (data.cfml.forwardIfCurrent('[')) {
1336                                
1337                                // get Next Var
1338                                nameProp = structElement(data);
1339                                namePropUC=nameProp;
1340                                // Valid Syntax ???
1341                                if (!data.cfml.forwardIfCurrent(']'))
1342                                        throw new TemplateException(
1343                                                data.cfml,
1344                                                "Invalid Syntax Closing []] not found");
1345                        }
1346                        /* / :
1347                        else if (data.cfml.forwardIfCurrent(':')) {
1348                                // Extract next Var String
1349                comments(data);
1350                int line=data.cfml.getLine();
1351                                name = identifier(true,true);
1352                                if(name==null) 
1353                                        throw new TemplateException(cfml, "Invalid identifier");
1354                comments(data);
1355                
1356                                nameProp=LitString.toExprString(name,line);
1357                        }*/
1358                        // finish
1359                        else {
1360                                break;
1361                        }
1362
1363            comments(data);
1364            
1365            if(expr instanceof Invoker)  {
1366                invoker=(Invoker) expr;
1367            }
1368            else {
1369                invoker=new ExpressionInvoker(expr);
1370                expr=invoker;
1371            }
1372                        // Method
1373                        if (data.cfml.isCurrent('(')) {
1374                                if(nameProp==null && name!=null)nameProp=Identifier.toIdentifier(name, Identifier.CASE_ORIGNAL,null,null);// properly this is never used
1375                                invoker.addMember(getFunctionMember(data,nameProp, false));
1376                        }
1377                        
1378                        // property
1379                        else invoker.addMember(new DataMember(namePropUC));
1380                        
1381                }
1382                
1383                return expr;  
1384        }
1385        
1386        private Expression newOp(ExprData data,Expression expr) throws TemplateException {
1387                if(!(expr instanceof Variable)) return expr;
1388                Variable var=(Variable) expr;
1389                Member m= var.getFirstMember();
1390                if(!(m instanceof DataMember)) return expr;
1391                
1392                ExprString n = ((DataMember)m).getName();
1393                if(!(n instanceof LitString)) return expr;
1394                
1395                LitString ls=(LitString) n;
1396                
1397                
1398                if(!"new".equalsIgnoreCase(ls.getString())) return expr;
1399                
1400                int start=data.cfml.getPos();
1401            String name=null;
1402            
1403            
1404            // first identifier
1405            name = identifier(data,true);
1406            
1407                
1408                ExprString exprName;
1409                if(name!=null)  {
1410                        StringBuilder fullName=new StringBuilder();
1411                        fullName.append(name);
1412                        // Loop over addional identifier
1413                        while (data.cfml.isValidIndex()) {
1414                                if (data.cfml.forwardIfCurrent('.')) {
1415                                        comments(data);
1416                        name = identifier(data,true);
1417                                        if(name==null) {
1418                                                data.cfml.setPos(start);
1419                                                return expr;//throw new TemplateException(data.cfml,"invalid Component declaration ");
1420                                        }
1421                                        fullName.append('.');
1422                                        fullName.append(name);
1423                                        comments(data);
1424                                }
1425                                else break;
1426                        }
1427                        
1428                        exprName=LitString.toExprString(fullName.toString());
1429                }
1430                else {
1431                        
1432                        Expression str=string(data);
1433                        if(str!=null){
1434                                exprName=CastString.toExprString(str);
1435                        }
1436                        else {
1437                                data.cfml.setPos(start);
1438                                return expr;
1439                        }
1440                }
1441
1442        comments(data);
1443        
1444        if (data.cfml.isCurrent('(')) {
1445                        FunctionMember func = getFunctionMember(data,Identifier.toIdentifier("_createComponent",Identifier.CASE_ORIGNAL,null,null), true);
1446                        func.addArgument(new Argument(exprName,"string"));
1447                        Variable v=new Variable(expr.getStart(),expr.getEnd());
1448                        v.addMember(func);
1449            comments(data);
1450                        return v;
1451                } 
1452        data.cfml.setPos(start);
1453        return expr;//throw new TemplateException(data.cfml,"invalid Component declaration ");
1454                
1455        }
1456        
1457        
1458        
1459        
1460        
1461        /**
1462        * Extrahiert den Start Element einer Variale, 
1463        * dies ist entweder eine Funktion, eine Scope Definition oder eine undefinierte Variable. 
1464        * <br />
1465        * EBNF:<br />
1466        * <code>identifier "(" functionArg ")" | scope | identifier;</code>
1467        * @param name Einstiegsname
1468        * @return CFXD Element
1469        * @throws TemplateException 
1470        */
1471        private Variable startElement(ExprData data,Identifier name, Position line) throws TemplateException {
1472                
1473                
1474                
1475                
1476                // check function
1477                if (data.cfml.isCurrent('(')) {
1478                        FunctionMember func = getFunctionMember(data,name, true);
1479                        
1480                        Variable var=new Variable(line,data.cfml.getPosition());
1481                        var.addMember(func);
1482            comments(data);
1483                        return var;
1484                } 
1485                
1486                //check scope
1487                Variable var = scope(data,name,line);
1488                if(var!=null) return var;
1489                
1490                // undefined variable
1491                var=new Variable(line,data.cfml.getPosition());
1492                var.addMember(new DataMember(name));
1493
1494        comments(data);
1495                return var;
1496                
1497        }
1498        
1499        /**
1500        * Liest einen CFML Scope aus, 
1501        * falls der folgende identifier keinem Scope entspricht, 
1502        * gibt die Variable null zurueck.
1503        * <br />
1504        * EBNF:<br />
1505        * <code>"variable" | "cgi" | "url" | "form" | "session" | "application" | "arguments" | "cookie" | " client";</code>
1506         * @param id String identifier,
1507         * wird aus Optimierungszwechen nicht innerhalb dieser Funktion ausgelsen.
1508         * @return CFXD Variable Element oder null
1509         * @throws TemplateException 
1510        */
1511        private Variable scope(ExprData data,Identifier id, Position line) throws TemplateException {
1512                String idStr=id.getUpper();
1513                if(data.ignoreScopes)return null;
1514                if (idStr.equals("CGI"))                                return new Variable(Scope.SCOPE_CGI,line,data.cfml.getPosition());
1515                else if (idStr.equals("ARGUMENTS"))     return new Variable(Scope.SCOPE_ARGUMENTS,line,data.cfml.getPosition());
1516                else if (idStr.equals("REQUEST"))               return new Variable(Scope.SCOPE_REQUEST,line,data.cfml.getPosition());
1517                else if (idStr.equals("SESSION"))               return new Variable(Scope.SCOPE_SESSION,line,data.cfml.getPosition());
1518                else if (idStr.equals("APPLICATION"))   return new Variable(Scope.SCOPE_APPLICATION,line,data.cfml.getPosition());
1519                else if (idStr.equals("VARIABLES"))             return new Variable(Scope.SCOPE_VARIABLES,line,data.cfml.getPosition());
1520                else if (idStr.equals("FORM"))                  return new Variable(Scope.SCOPE_FORM,line,data.cfml.getPosition());
1521                else if (idStr.equals("URL"))                   return new Variable(Scope.SCOPE_URL,line,data.cfml.getPosition());
1522                else if (idStr.equals("SERVER"))                return new Variable(Scope.SCOPE_SERVER,line,data.cfml.getPosition());
1523                else if (idStr.equals("CLIENT"))                return new Variable(Scope.SCOPE_CLIENT,line,data.cfml.getPosition());
1524                else if (idStr.equals("COOKIE"))                return new Variable(Scope.SCOPE_COOKIE,line,data.cfml.getPosition());
1525                else if (idStr.equals("CLUSTER"))               return new Variable(Scope.SCOPE_CLUSTER,line,data.cfml.getPosition());
1526                else if (idStr.equals("LOCAL"))                 return new Variable(Scope.SCOPE_LOCAL,line,data.cfml.getPosition());
1527                else if (idStr.equals("VAR")) {
1528                        Identifier _id = identifier(data,false,true);
1529                        if(_id!=null){
1530                                comments(data);
1531                                Variable local = new Variable(ScopeSupport.SCOPE_VAR,line,data.cfml.getPosition());
1532                                if(!"LOCAL".equalsIgnoreCase(_id.getString()))local.addMember(new DataMember(_id));
1533                                else {
1534                                        local.ignoredFirstMember(true);
1535                                }
1536                                return local;
1537                        }
1538                } 
1539                return null;
1540        }
1541    
1542        /**
1543        * Liest einen Identifier aus und gibt diesen als String zurueck.
1544        * <br />
1545        * EBNF:<br />
1546        * <code>(letter | "_") {letter | "_"|digit};</code>
1547         * @param firstCanBeNumber 
1548         * @param upper
1549        * @return Identifier.
1550        */
1551        protected Identifier identifier(ExprData data,boolean firstCanBeNumber,boolean upper) {
1552                Position start = data.cfml.getPosition();
1553                if(!data.cfml.isCurrentLetter() && !data.cfml.isCurrentSpecial() ) {
1554                    if(!firstCanBeNumber) return null;
1555            else if(!data.cfml.isCurrentBetween('0','9'))return null;
1556        }
1557                do {
1558                        data.cfml.next();
1559                        if(!(data.cfml.isCurrentLetter()
1560                                || data.cfml.isCurrentBetween('0','9')
1561                                || data.cfml.isCurrentSpecial())) {
1562                                        break;
1563                                }
1564                }
1565                while (data.cfml.isValidIndex());
1566                return Identifier.toIdentifier(data.cfml.substring(start.pos,data.cfml.getPos()-start.pos), 
1567                                upper && data.settings.dotNotationUpper?Identifier.CASE_UPPER:Identifier.CASE_ORIGNAL, start,data.cfml.getPosition());
1568        }
1569        
1570        protected String identifier(ExprData data,boolean firstCanBeNumber) {
1571                int start = data.cfml.getPos();
1572                if(!data.cfml.isCurrentLetter() && !data.cfml.isCurrentSpecial() ) {
1573                    if(!firstCanBeNumber) return null;
1574            else if(!data.cfml.isCurrentBetween('0','9'))return null;
1575        }
1576                do {
1577                        data.cfml.next();
1578                        if(!(data.cfml.isCurrentLetter()
1579                                || data.cfml.isCurrentBetween('0','9')
1580                                || data.cfml.isCurrentSpecial())) {
1581                                        break;
1582                                }
1583                }
1584                while (data.cfml.isValidIndex());
1585                return data.cfml.substring(start,data.cfml.getPos()-start);
1586        }
1587
1588        /**
1589        * Transfomiert ein Collection Element das in eckigen Klammern aufgerufen wird. 
1590        * <br />
1591        * EBNF:<br />
1592        * <code>"[" impOp "]"</code>
1593        * @return CFXD Element
1594        * @throws TemplateException 
1595        */
1596        private ExprString structElement(ExprData data) throws TemplateException {
1597        comments(data);
1598        ExprString name = CastString.toExprString(assignOp(data));
1599                if(name instanceof LitString)((LitString)name).fromBracket(true);
1600        comments(data);
1601                return name;
1602        }
1603
1604        /**
1605        * Liest die Argumente eines Funktonsaufruf ein und prueft ob die Funktion 
1606        * innerhalb der FLD (Function Library Descriptor) definiert ist. 
1607        * Falls sie existiert wird die Funktion gegen diese geprueft und ein build-in-function CFXD Element generiert, 
1608        * ansonsten ein normales funcion-call Element.
1609        * <br />
1610        * EBNF:<br />
1611        * <code>[impOp{"," impOp}];</code>
1612        * @param name Identifier der Funktion als Zeichenkette
1613        * @param checkLibrary Soll geprueft werden ob die Funktion innerhalb der Library existiert.
1614        * @return CFXD Element
1615        * @throws TemplateException 
1616        */
1617        private FunctionMember getFunctionMember(ExprData data,
1618                        final ExprString name,
1619                boolean checkLibrary)
1620                throws TemplateException {
1621
1622                // get Function Library
1623                checkLibrary=checkLibrary && data.flibs!=null;
1624                FunctionLibFunction flf = null;
1625                if (checkLibrary) {
1626                        if(!(name instanceof Literal))
1627                                throw new TemplateException(data.cfml,"syntax error"); // should never happen!
1628                        
1629                        for (int i = 0; i < data.flibs.length; i++) {
1630                                flf = data.flibs[i].getFunction(((Literal)name).getString());
1631                                if (flf != null)break;
1632                        }
1633                        if (flf == null) {
1634                                checkLibrary = false;
1635                        }
1636                }
1637                // Element Function
1638                FunctionMember fm;
1639                if(checkLibrary) {
1640                        BIF bif=new BIF(name,flf);
1641                        bif.setArgType(flf.getArgType());
1642                        bif.setClass(flf.getClazz());
1643                        bif.setReturnType(flf.getReturnTypeAsString());
1644                        fm=bif;
1645                        
1646                        if(flf.getArgType()== FunctionLibFunction.ARG_DYNAMIC && flf.hasDefaultValues()){
1647                        ArrayList<FunctionLibFunctionArg> args = flf.getArg();
1648                                Iterator<FunctionLibFunctionArg> it = args.iterator();
1649                        FunctionLibFunctionArg arg;
1650                        while(it.hasNext()){
1651                                arg=it.next();
1652                                if(arg.getDefaultValue()!=null)
1653                                        bif.addArgument(
1654                                                        new NamedArgument(
1655                                                                        LitString.toExprString(arg.getName()),
1656                                                                        LitString.toExprString(arg.getDefaultValue()),
1657                                                                        arg.getTypeAsString(),false
1658                                                                        ));
1659                        }
1660                        }
1661                }
1662                else {
1663                        fm = new UDF(name);
1664                }
1665                
1666                
1667                
1668
1669                // Function Attributes
1670                ArrayList<FunctionLibFunctionArg> arrFuncLibAtt = null;
1671                int libLen = 0;
1672                if (checkLibrary) {
1673                        arrFuncLibAtt = flf.getArg();
1674                        libLen = arrFuncLibAtt.size();
1675                }
1676                int count = 0;
1677                do {
1678                        data.cfml.next();
1679            comments(data);
1680
1681                        // finish
1682                        if (count==0 && data.cfml.isCurrent(')'))
1683                                break;
1684
1685                        // too many Attributes
1686                        boolean isDynamic=false;
1687                        int max=-1;
1688                        if(checkLibrary) {
1689                                isDynamic=flf.getArgType()==FunctionLibFunction.ARG_DYNAMIC;
1690                                max=flf.getArgMax();
1691                        // Dynamic
1692                                if(isDynamic) {
1693                                        if(max!=-1 && max <= count)
1694                                                throw new TemplateException(
1695                                                        data.cfml,
1696                                                        "too many Attributes in function [" + ASMUtil.display(name) + "]");
1697                                }
1698                        // Fix
1699                                else {
1700                                        if(libLen <= count){
1701                                                
1702                                                TemplateException te = new TemplateException(
1703                                                        data.cfml,
1704                                                        "too many Attributes in function call [" + ASMUtil.display(name) + "]");
1705                                                UDFUtil.addFunctionDoc(te, flf);
1706                                                throw te;
1707                                        }
1708                                }
1709                                
1710                        }
1711                        
1712                        //Argument arg;
1713                        if (checkLibrary && !isDynamic) {
1714                                // current attribues from library
1715                                FunctionLibFunctionArg funcLibAtt =arrFuncLibAtt.get(count);
1716                                fm.addArgument(functionArgument(data,funcLibAtt.getTypeAsString(),false));      
1717                        } 
1718                        else {
1719                                fm.addArgument(functionArgument(data,false));
1720                        }
1721
1722            comments(data);
1723                        count++;
1724                        if (data.cfml.isCurrent(')'))
1725                                break;
1726                } 
1727                while (data.cfml.isCurrent(','));
1728
1729                // end with ) ??                
1730                if (!data.cfml.forwardIfCurrent(')'))
1731                        throw new TemplateException(
1732                                data.cfml,
1733                                "Invalid Syntax Closing [)] for function ["
1734                                        + ASMUtil.display(name)
1735                                        + "] not found");
1736
1737                // check min attributes
1738                if (checkLibrary && flf.getArgMin() > count){
1739                        TemplateException te = new TemplateException(
1740                                data.cfml,
1741                                "too few attributes in function [" + ASMUtil.display(name) + "]");
1742                        if(flf.getArgType()==FunctionLibFunction.ARG_FIX) UDFUtil.addFunctionDoc(te, flf);
1743                        throw te;
1744                }
1745
1746        comments(data);
1747        
1748        // evaluator
1749        if(checkLibrary && flf.hasTteClass()){
1750                flf.getEvaluator().evaluate((BIF) fm, flf);
1751        }
1752        
1753                return fm;
1754        }
1755        
1756        /**
1757         * Sharps (#) die innerhalb von Expressions auftauchen haben in CFML keine weitere Beteutung 
1758         * und werden durch diese Methode einfach entfernt.
1759         * <br />
1760         * Beispiel:<br />
1761         * <code>arrayLen(#arr#)</code> und <code>arrayLen(arr)</code> sind identisch.
1762         * EBNF:<br />
1763         * <code>"#" checker "#";</code>
1764         * @return CFXD Element
1765         * @throws TemplateException 
1766        */
1767        private Expression sharp(ExprData data) throws TemplateException {
1768                if(!data.cfml.forwardIfCurrent('#'))
1769                        return null;
1770                Expression expr;
1771        comments(data);
1772        boolean old=data.allowLowerThan;
1773        data.allowLowerThan=true;
1774                expr = assignOp(data);
1775                data.allowLowerThan=old;
1776        comments(data);
1777                if (!data.cfml.forwardIfCurrent('#'))
1778                        throw new TemplateException(
1779                                data.cfml,
1780                                "Syntax Error, Invalid Construct "+(data.cfml.length()<30?data.cfml.toString():""));
1781        comments(data);
1782                return expr;
1783        }
1784        
1785        /**
1786         * @param data 
1787         * @return parsed Element
1788         * @throws TemplateException
1789         */
1790        private Expression simple(ExprData data,String[] breakConditions) throws TemplateException {
1791                StringBuffer sb=new StringBuffer();
1792                Position line = data.cfml.getPosition();
1793                outer:while(data.cfml.isValidIndex()) {
1794                        for(int i=0;i<breakConditions.length;i++){
1795                                if(data.cfml.isCurrent(breakConditions[i]))break outer;
1796                        }
1797                        
1798                        //if(data.cfml.isCurrent(' ') || data.cfml.isCurrent('>') || data.cfml.isCurrent("/>")) break;
1799                        
1800                        if(data.cfml.isCurrent('"') || data.cfml.isCurrent('#') || data.cfml.isCurrent('\'')) {
1801                                throw new TemplateException(data.cfml,"simple attribute value can't contain ["+data.cfml.getCurrent()+"]");
1802                        }
1803                        sb.append(data.cfml.getCurrent());
1804                        data.cfml.next();
1805                }
1806        comments(data);
1807                
1808                return LitString.toExprString(sb.toString(),line,data.cfml.getPosition());
1809        }
1810    
1811
1812    /**
1813     *  Liest alle folgenden Komentare ein.
1814      * <br />
1815     * EBNF:<br />
1816     * <code>{?-"\n"} "\n";</code>
1817     * @param data 
1818     * @throws TemplateException
1819     */
1820    protected void comments(ExprData data) throws TemplateException {
1821        data.cfml.removeSpace();
1822        while(comment(data)){data.cfml.removeSpace();}
1823    }
1824    
1825    /**
1826     *  Liest einen Einzeiligen Kommentar ein.
1827      * <br />
1828     * EBNF:<br />
1829     * <code>{?-"\n"} "\n";</code>
1830     * @return bool Wurde ein Kommentar entfernt?
1831     * @throws TemplateException
1832     */
1833    private boolean comment(ExprData data) throws TemplateException {
1834        if(singleLineComment(data.cfml) || multiLineComment(data) || CFMLTransformer.comment(data.cfml)) return true;
1835        return false;
1836    }
1837
1838    /**
1839     * Liest einen Mehrzeiligen Kommentar ein.
1840     * <br />
1841     * EBNF:<br />
1842     * <code>?-"*<!-- -->/";</code>
1843     * @return bool Wurde ein Kommentar entfernt?
1844     * @throws TemplateException
1845     */
1846    private boolean multiLineComment(ExprData data) throws TemplateException {
1847       CFMLString cfml = data.cfml;
1848        if(!cfml.forwardIfCurrent("/*")) return false;
1849        int pos=cfml.getPos();
1850        boolean isDocComment=cfml.isCurrent('*');
1851        while(cfml.isValidIndex()) {
1852            if(cfml.isCurrent("*/")) break;
1853            cfml.next();
1854        }
1855        if(!cfml.forwardIfCurrent("*/")){
1856            cfml.setPos(pos);
1857            throw new TemplateException(cfml,"comment is not closed");
1858        }
1859        if(isDocComment) {
1860                String comment = cfml.substring(pos-2,cfml.getPos()-pos);
1861                data.docComment=docCommentTransformer.transform(comment);
1862        }
1863        return true;
1864    }
1865    
1866    
1867    
1868    /**
1869     *  Liest einen Einzeiligen Kommentar ein.
1870      * <br />
1871     * EBNF:<br />
1872     * <code>{?-"\n"} "\n";</code>
1873     * @return bool Wurde ein Kommentar entfernt?
1874     */
1875    private boolean singleLineComment(CFMLString cfml) {
1876        if(!cfml.forwardIfCurrent("//")) return false;
1877        return cfml.nextLine();
1878    }
1879
1880}