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