001    package railo.transformer.cfml.script;
002    
003    import java.lang.reflect.Constructor;
004    import java.util.ArrayList;
005    import java.util.HashMap;
006    import java.util.Iterator;
007    import java.util.Map;
008    
009    import railo.commons.lang.ClassUtil;
010    import railo.commons.lang.StringUtil;
011    import railo.commons.lang.types.RefBoolean;
012    import railo.commons.lang.types.RefBooleanImpl;
013    import railo.runtime.Component;
014    import railo.runtime.config.Config;
015    import railo.runtime.config.ConfigImpl;
016    import railo.runtime.engine.ThreadLocalPageContext;
017    import railo.runtime.exp.TemplateException;
018    import railo.runtime.functions.system.CFFunction;
019    import railo.runtime.op.Caster;
020    import railo.runtime.type.util.ArrayUtil;
021    import railo.runtime.type.util.ComponentUtil;
022    import railo.transformer.bytecode.Body;
023    import railo.transformer.bytecode.BodyBase;
024    import railo.transformer.bytecode.BytecodeException;
025    import railo.transformer.bytecode.FunctionBody;
026    import railo.transformer.bytecode.Page;
027    import railo.transformer.bytecode.ScriptBody;
028    import railo.transformer.bytecode.Statement;
029    import railo.transformer.bytecode.cast.Cast;
030    import railo.transformer.bytecode.cast.CastBoolean;
031    import railo.transformer.bytecode.cast.CastString;
032    import railo.transformer.bytecode.expression.ExprBoolean;
033    import railo.transformer.bytecode.expression.Expression;
034    import railo.transformer.bytecode.expression.var.Variable;
035    import railo.transformer.bytecode.literal.LitBoolean;
036    import railo.transformer.bytecode.literal.LitString;
037    import railo.transformer.bytecode.statement.Condition;
038    import railo.transformer.bytecode.statement.DoWhile;
039    import railo.transformer.bytecode.statement.ExpressionStatement;
040    import railo.transformer.bytecode.statement.For;
041    import railo.transformer.bytecode.statement.ForEach;
042    import railo.transformer.bytecode.statement.Function;
043    import railo.transformer.bytecode.statement.Return;
044    import railo.transformer.bytecode.statement.Switch;
045    import railo.transformer.bytecode.statement.TryCatchFinally;
046    import railo.transformer.bytecode.statement.While;
047    import railo.transformer.bytecode.statement.tag.Attribute;
048    import railo.transformer.bytecode.statement.tag.Tag;
049    import railo.transformer.bytecode.statement.tag.TagBase;
050    import railo.transformer.bytecode.statement.tag.TagParam;
051    import railo.transformer.bytecode.util.ASMUtil;
052    import railo.transformer.cfml.evaluator.EvaluatorException;
053    import railo.transformer.cfml.evaluator.EvaluatorPool;
054    import railo.transformer.cfml.evaluator.impl.ProcessingDirectiveException;
055    import railo.transformer.cfml.expression.CFMLExprTransformer;
056    import railo.transformer.cfml.tag.CFMLTransformer;
057    import railo.transformer.cfml.tag.TagDependentBodyTransformer;
058    import railo.transformer.library.function.FunctionLib;
059    import railo.transformer.library.function.FunctionLibFunction;
060    import railo.transformer.library.tag.TagLibTag;
061    import railo.transformer.library.tag.TagLibTagAttr;
062    import railo.transformer.library.tag.TagLibTagScript;
063    import railo.transformer.util.CFMLString;
064    
065    
066    /**     
067     * Innerhalb des Tag script kann in Cold Fusion eine eigene Scriptsprache verwendet werden, 
068     * welche sich an Javascript orientiert. 
069     * Da der data.cfml Transformer keine Spezialf�lle zul�sst, 
070     * also Tags einfach anhand der eingegeben TLD einliest und transformiert, 
071     * aus diesem Grund wird der Inhalt des Tag script einfach als Zeichenkette eingelesen.
072     * Erst durch den Evaluator (siehe 3.3), der f�r das Tag script definiert ist, 
073     * wird der Inhalt des Tag script �bersetzt.
074     * 
075     */
076    public final class CFMLScriptTransformer extends CFMLExprTransformer implements TagDependentBodyTransformer {
077    
078            private static final String[] IGNORE_LIST_COMPONENT = new String[]{
079                    "output","synchronized","extends","implements","displayname","style","persistent","accessors"};
080            private static final String[] IGNORE_LIST_INTERFACE = new String[]{
081                    "output","extends","displayname","style","persistent","accessors"};
082            private static final String[] IGNORE_LIST_PROPERTY = new String[]{
083                    "default","fieldtype","name","type","persistent","remotingFetch","column","generator","length",
084                    "ormtype","params","unSavedValue","dbdefault","formula","generated","insert","optimisticlock",
085                    "update","notnull","precision","scale","unique","uniquekey","source"
086            };
087     
088    
089            private static EndCondition SEMI_BLOCK=new EndCondition() {
090                    public boolean isEnd(Data data) {
091                            return data.cfml.isCurrent('{') || data.cfml.isCurrent(';');
092                    }
093            };
094            private static EndCondition SEMI=new EndCondition() {
095                    public boolean isEnd(Data data) {
096                            return data.cfml.isCurrent(';');
097                    }
098            };
099            private static EndCondition COMMA_ENDBRACKED=new EndCondition() {
100                    public boolean isEnd(Data data) {
101                            return data.cfml.isCurrent(',') || data.cfml.isCurrent(')');
102                    }
103            };
104            
105            
106            
107            
108    
109            private short ATTR_TYPE_NONE=TagLibTagAttr.SCRIPT_SUPPORT_NONE;
110            private short ATTR_TYPE_OPTIONAL=TagLibTagAttr.SCRIPT_SUPPORT_OPTIONAL;
111            private short ATTR_TYPE_REQUIRED=TagLibTagAttr.SCRIPT_SUPPORT_REQUIRED;
112            
113            public static class ComponentTemplateException extends TemplateException {
114                    private static final long serialVersionUID = -8103635220891288231L;
115                    
116                    private TemplateException te;
117    
118                    public ComponentTemplateException(TemplateException te){
119                            super(te.getPageSource(),te.getLine(),0,te.getMessage());
120                            this.te=te;
121                            
122                    }
123    
124                    /**
125                     * @return the te
126                     */
127                    public TemplateException getTemplateException() {
128                            return te;
129                    }
130            }
131    
132            private static final Expression NULL = LitString.toExprString("NULL"); 
133            private static final Attribute ANY = new Attribute(false,"type",LitString.toExprString("any"),"string"); 
134    
135            /**
136             * Einstiegsmethode f�r den CFScript Transformer, 
137             * die Methode erbt sich von der Transform Methode der data.cfmlExprTransformer Klasse.
138             * Der einzige Unterschied liegt darin, das der data.cfmlString der eingegeben wird als vererbte Klasse CFScriptString vorliegen muss.
139             * Der Parameter ist als data.cfmlString definiert, so dass er die transform Methode �berschreibt.
140             * @param fld Array von Function Libraries, 
141             * Mithilfe dieser Function Libraries kann der Transfomer buil-in Funktionen innerhalb des data.cfml Codes erkennen 
142             * und validieren.
143             * <br />
144             * EBNF:<br />
145             * <code>statements;</code>
146             * @param cfxdTag XML Document des aktuellen zu erstellenden CFXD
147             * @param libTag Definition des aktuellen Tag.
148             * @param data.cfml data.cfml Code 
149             * @param parentTransformer
150             * @throws TemplateException
151             */
152    
153            public void transform(Config config,CFMLTransformer parentTransformer,EvaluatorPool ep,FunctionLib[] fld, Tag tag,TagLibTag libTag, CFMLString cfml) throws TemplateException   {
154                    Page page = ASMUtil.getAncestorPage(tag);
155                    boolean isCFC= page.isComponent();
156                    boolean isInterface= page.isInterface();
157                    
158                    Data data = init(ep,fld,cfml,true);
159                    data.insideFunction=false; 
160                    data.tagName=libTag.getFullName();
161                    data.isCFC=isCFC;
162                    data.isInterface=isInterface;
163                    data.scriptTags=((ConfigImpl) config).getCoreTagLib().getScriptTags();
164                    
165                    tag.setBody(statements(data));
166            }
167    
168            /**
169             * @throws TemplateException 
170             * @see railo.transformer.data.cfml.expression.data.cfmlExprTransformer#transform(railo.transformer.library.function.FunctionLib[], org.w3c.dom.Document, railo.transformer.util.data.cfmlString)
171             */
172            public Expression transform(FunctionLib[] fld,CFMLString cfml) throws TemplateException {// FUTURE is this method needed anymore?
173                    throw new TemplateException(cfml,"you can't use Method transform on class CFMLScriptTransformer");
174            }
175            /**
176             * @see railo.transformer.data.cfml.expression.data.cfmlExprTransformer#transformAsString(railo.transformer.library.function.FunctionLib[], org.w3c.dom.Document, railo.transformer.util.data.cfmlString)
177             */
178            public Expression transformAsString(FunctionLib[] fld,CFMLString cfml, boolean allowLowerThan) throws TemplateException {// FUTURE is this method needed anymore?
179                    throw new TemplateException(cfml,"you can't use Method transformAsString on class CFMLScriptTransformer");
180            }
181            
182            
183            /** 
184             * Liest s�mtliche Statements des CFScriptString ein. 
185             * <br />
186             * EBNF:<br />
187             * <code>{statement spaces};</code>
188             * @return a statement
189             * @throws TemplateException
190             */
191            protected Body statements(Data data) throws TemplateException {
192                    ScriptBody body=new ScriptBody();
193                    
194                    statements(data,body,true);
195            return body;
196            }
197            
198            /**
199             * Liest s�mtliche Statements des CFScriptString ein. 
200             * <br />
201             * EBNF:<br />
202             * <code>{statement spaces};</code>
203             * @param parent �bergeornetes Element dem das Statement zugewiesen wird.
204             * @param isRoot befindet sich der Parser im root des data.cfml Docs
205             * @throws TemplateException
206             */
207            protected void statements(Data data,Body body, boolean isRoot) throws TemplateException {
208                    do {
209                            if(isRoot && isFinish(data))return;
210                            statement(data,body);
211                            comments(data);
212                    }
213                    while(data.cfml.isValidIndex() && !data.cfml.isCurrent('}'));
214            }
215            
216            /** 
217             * Liest ein einzelnes Statement ein (if,for,while usw.).
218             * <br />
219             * EBNF:<br />
220             * <code>";" | "if" spaces "(" ifStatement | "function " funcStatement |  "while" spaces "(" whileStatement  |  
221                              "do" spaces "{" doStatement  | "for" spaces "(" forStatement | "return" returnStatement | 
222                              "break" breakStatement | "continue" continueStatement | "/*" comment | expressionStatement;</code>
223             * @param parent �bergeornetes Element dem das Statement zugewiesen wird.
224             * @throws TemplateException
225             */
226            protected void statement(Data data,Body parent) throws TemplateException {
227                    statement(data, parent, data.context);
228            }
229            private void statement(Data data,Body parent,short context) throws TemplateException {
230                    short prior=data.context;
231                    data.context=context;
232                    comments(data);
233                    Statement child=null;
234                    if(data.cfml.forwardIfCurrent(';')){}
235                    else if((child=ifStatement(data))!=null)                                parent.addStatement(child);
236                    else if((child=propertyStatement(data,parent))!=null)   parent.addStatement(child);
237                    else if((child=paramStatement(data,parent))!=null)      parent.addStatement(child);
238                    else if((child=funcStatement(data,parent))!=null)               parent.addStatement(child);
239                    else if((child=whileStatement(data))!=null)                     parent.addStatement(child);
240                    else if((child=doStatement(data))!=null)                                parent.addStatement(child);
241                    else if((child=forStatement(data))!=null)                               parent.addStatement(child);
242                    else if((child=returnStatement(data))!=null)                    parent.addStatement(child);
243                    else if((child=switchStatement(data))!=null)                    parent.addStatement(child);
244                    else if((child=tryStatement(data))!=null)                               parent.addStatement(child);
245                    else if((child=tagStatement(data,parent))!=null)        parent.addStatement(child);
246                    else if(block(data,parent)){}
247                    else parent.addStatement(expressionStatement(data));
248                    data.docComment=null;
249                    data.context=prior;
250            }
251            
252            /**
253             * Liest ein if Statement ein.
254             * <br />
255             * EBNF:<br />
256             * <code>spaces condition spaces ")" spaces block {"else if" spaces "(" elseifStatement spaces }
257                             [("else"  spaces "(" | "else ") elseStatement spaces];</code>
258             * @return if Statement
259             * @throws TemplateException
260             */
261            protected Statement ifStatement(Data data) throws TemplateException {
262                    if(!data.cfml.forwardIfCurrent("if",'(')) return null;
263                    
264                    
265                    int line=data.cfml.getLine();
266                    
267                    Body body=new BodyBase();
268                    Condition cont=new Condition(condition(data),body,line);
269                    
270                    if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"if statement must end with a [)]");
271                    // ex block
272                    statement(data,body,CTX_IF);
273                    // else if
274                    comments(data);
275                    while(elseifStatement(data,cont)) {
276                            comments(data);
277                    }
278                    // else
279                     if(elseStatement(data,cont)) {
280                            comments(data);
281                     }
282                    
283                    return cont;
284            }
285            
286            /**
287             * Liest ein else if Statement ein.
288             * <br />
289             * EBNF:<br />
290             * <code>spaces condition spaces ")" spaces block;</code>
291             * @return else if Statement
292             * @throws TemplateException
293             */
294            protected boolean elseifStatement(Data data,Condition cont) throws TemplateException {
295                    int pos=data.cfml.getPos();
296                    if(!data.cfml.forwardIfCurrent("else")) return false;
297                    
298                    comments(data);
299                    if(!data.cfml.forwardIfCurrent("if",'(')) {
300                            data.cfml.setPos(pos);
301                            return false;
302                    }
303                            
304                    int line=data.cfml.getLine();
305                    Body body=new BodyBase();
306                    cont.addElseIf(condition(data), body, line);
307    
308                    if(!data.cfml.forwardIfCurrent(')'))
309                            throw new TemplateException(data.cfml,"else if statement must end with a [)]");
310                    // ex block
311                    statement(data,body,CTX_ELSE_IF);
312                    
313                    return true;
314            }
315            
316            /**
317             * Liest ein else Statement ein.
318             * <br />
319             * EBNF:<br />
320             * <code>block;</code>
321             * @return else Statement
322             * @throws TemplateException
323             * 
324             */
325            protected boolean elseStatement(Data data,Condition cont) throws TemplateException {
326                    if(!data.cfml.forwardIfCurrent("else",'{') && !data.cfml.forwardIfCurrent("else ") && !data.cfml.forwardIfCurrent("else",'/')) 
327                            return false;
328    
329                    // start (
330                    data.cfml.previous();
331                    // ex block
332                    Body body=new BodyBase();
333                    cont.setElse(body, data.cfml.getLine());
334                    statement(data,body,CTX_ELSE);
335                    
336                    return true;
337            }
338            
339    
340            protected boolean finallyStatement(Data data,TryCatchFinally tcf) throws TemplateException {
341                    if(!data.cfml.forwardIfCurrent("finally",'{') && !data.cfml.forwardIfCurrent("finally ") && !data.cfml.forwardIfCurrent("finally",'/')) 
342                            return false;
343    
344                    // start (
345                    data.cfml.previous();
346                    // ex block
347                    Body body=new BodyBase();
348                    tcf.setFinally(body, data.cfml.getLine());
349                    statement(data,body,CTX_FINALLY);
350                    
351                    return true;
352            }
353            
354            /**
355             * Liest ein while Statement ein.
356             * <br />
357             * EBNF:<br />
358             * <code>spaces condition spaces ")" spaces block;</code>
359             * @return while Statement
360             * @throws TemplateException
361             */
362            public While whileStatement(Data data) throws TemplateException {
363                    if(!data.cfml.forwardIfCurrent("while",'('))
364                            return null;
365                    
366                    int line=data.cfml.getLine();
367                    Body body=new BodyBase();
368                    While whil=new While(condition(data),body,line,-1);
369                    
370                    if(!data.cfml.forwardIfCurrent(')'))
371                            throw new TemplateException(data.cfml,"while statement must end with a [)]");
372                    
373                    statement(data,body,CTX_WHILE);
374                    whil.setEndLine(data.cfml.getLine());
375                    return whil;
376            }
377            
378            /**
379             * Liest ein switch Statment ein
380             * @return switch Statement
381             * @throws TemplateException
382             */
383            public Switch switchStatement(Data data) throws TemplateException {
384                    if(!data.cfml.forwardIfCurrent("switch",'('))
385                            return null;
386                    
387                    int line=data.cfml.getLine();
388                    
389                    comments(data);
390                    Expression expr = super.expression(data);
391                    comments(data);
392                    // end )
393                    if(!data.cfml.forwardIfCurrent(')'))
394                            throw new TemplateException(data.cfml,"switch statement must end with a [)]");
395                    comments(data);
396    
397                    if(!data.cfml.forwardIfCurrent('{'))
398                            throw new TemplateException(data.cfml,"switch statement must have a starting  [{]");
399    
400                    Switch swit=new Switch(expr,line,-1);
401                    
402                    //      cases
403                     //Node child=null;
404                     comments(data);
405                     while(caseStatement(data,swit)) {
406                             comments(data);
407                     }
408                     // default
409                      if(defaultStatement(data,swit)) {
410                            comments(data);
411                      }
412                      
413                      while(caseStatement(data,swit)) {
414                                     comments(data);
415                             }
416                      
417                      
418                    // }
419                    if(!data.cfml.forwardIfCurrent('}'))
420                            throw new TemplateException(data.cfml,"invalid construct in switch statement");
421                    swit.setEndLine(data.cfml.getLine());
422                    return swit;
423            }
424            
425            /**
426             * Liest ein Case Statement ein
427             * @return case Statement
428             * @throws TemplateException
429             */
430            public boolean caseStatement(Data data,Switch swit) throws TemplateException {
431                    if(!data.cfml.forwardIfCurrentAndNoWordAfter("case"))
432                            return false;
433                    
434                    //int line=data.cfml.getLine();         
435                    comments(data);
436                    Expression expr = super.expression(data);
437                    comments(data);
438                    
439                    if(!data.cfml.forwardIfCurrent(':'))
440                            throw new TemplateException(data.cfml,"case body must start with [:]");
441                    
442                    Body body=new BodyBase();
443                    switchBlock(data,body);
444                    swit.addCase(expr, body);
445                    return true;
446            }
447            
448            /**
449             * Liest ein default Statement ein
450             * @return default Statement
451             * @throws TemplateException
452             */
453            public boolean defaultStatement(Data data,Switch swit) throws TemplateException {
454                    if(!data.cfml.forwardIfCurrent("default",':'))
455                            return false;
456                    
457                    //int line=data.cfml.getLine();
458                    
459                    Body body=new BodyBase();
460                    swit.setDefaultCase(body);
461                    switchBlock(data,body);
462                    return true;
463            }
464            
465            /**
466             * Liest ein Switch Block ein
467             * @param block
468             * @throws TemplateException
469             */
470            public void switchBlock(Data data,Body body) throws TemplateException {
471                    while(data.cfml.isValidIndex()) {
472                            comments(data);
473                            if(data.cfml.isCurrent("case ") || data.cfml.isCurrent("default",':') || data.cfml.isCurrent('}')) 
474                                    return;
475                            statement(data,body,CTX_SWITCH);
476                    }
477            }
478            
479            
480            /**
481             * Liest ein do Statement ein.
482             * <br />
483             * EBNF:<br />
484             * <code>block spaces "while" spaces "(" spaces condition spaces ")";</code>
485             * @return do Statement
486             * @throws TemplateException
487             */
488            public DoWhile doStatement(Data data) throws TemplateException {
489                    if(!data.cfml.forwardIfCurrent("do",'{') && !data.cfml.forwardIfCurrent("do ") && !data.cfml.forwardIfCurrent("do",'/'))
490                            return null;
491                    
492                    int line=data.cfml.getLine();
493                    Body body=new BodyBase();
494                    
495                    data.cfml.previous();
496                    statement(data,body,CTX_DO_WHILE);
497                    
498                    comments(data);
499                    if(!data.cfml.forwardIfCurrent("while",'('))
500                            throw new TemplateException(data.cfml,"do statement must have a while at the end");
501                    
502                    DoWhile doWhile=new DoWhile(condition(data),body,line,data.cfml.getLine());
503                    
504                    if(!data.cfml.forwardIfCurrent(')'))
505                            throw new TemplateException(data.cfml,"do statement must end with a [)]");
506                    
507                    
508                    return doWhile;
509            }
510            
511            /**
512             * Liest ein for Statement ein.
513             * <br />
514             * EBNF:<br />
515             * <code>expression spaces ";" spaces condition spaces ";" spaces expression spaces ")" spaces block;</code>
516             * @return for Statement
517             * @throws TemplateException
518             */
519            public Statement forStatement(Data data) throws TemplateException {
520                    if(!data.cfml.forwardIfCurrent("for",'(')) 
521                            return null;
522                    Expression left=null;
523                    Body body=new BodyBase();
524                    int line=data.cfml.getLine();
525                    comments(data);
526                    if(!data.cfml.isCurrent(';')) {
527                            // left
528                            left=expression(data);
529                            comments(data);
530                    }
531                    // middle for
532                            if(data.cfml.forwardIfCurrent(';')) {
533    
534                                    Expression cont=null;
535                                    Expression update=null;
536                                    // condition
537                                            comments(data);
538                                            if(!data.cfml.isCurrent(';')) {
539                                                    cont=condition(data);
540                                                    comments(data);
541                                            }
542                                    // middle
543                                    if(!data.cfml.forwardIfCurrent(';'))
544                                            throw new TemplateException(data.cfml,"invalid syntax in for statement");
545                                    // update
546                                            comments(data);
547                                            if(!data.cfml.isCurrent(')')) {
548                                                    update=expression(data);
549                                                    comments(data);
550                                            }
551                                    // start )
552                                    if(!data.cfml.forwardIfCurrent(')'))
553                                            throw new TemplateException(data.cfml,"invalid syntax in for statement, for statement must end with a [)]");
554                                    // ex block
555                                    statement(data,body,CTX_FOR);
556                    
557                                    return new For(left,cont,update,body,line,data.cfml.getLine());                                 
558                            }
559                    // middle foreach
560                            else if(data.cfml.forwardIfCurrent("in")) {
561                                    // condition
562                                            comments(data);
563                                            Expression value = expression(data);
564                                            comments(data);
565                                    if(!data.cfml.forwardIfCurrent(')'))
566                                            throw new TemplateException(data.cfml,"invalid syntax in for statement, for statement must end with a [)]");
567                                    
568                                    // ex block
569                                    statement(data,body,CTX_FOR);
570                                    if(!(left instanceof Variable))
571                                            throw new TemplateException(data.cfml,"invalid syntax in for statment, left value is invalid");
572                                    
573                                    if(!(value instanceof Variable))
574                                            throw new TemplateException(data.cfml,"invalid syntax in for statment, right value is invalid");
575                                    return new ForEach((Variable)left,(Variable)value,body,line,data.cfml.getLine());       
576                            }
577                            else 
578                                    throw new TemplateException(data.cfml,"invalid syntax in for statement");
579            }
580            
581            /**
582             * Liest ein function Statement ein.
583             * <br />
584             * EBNF:<br />
585             * <code>identifier spaces "(" spaces identifier spaces {"," spaces identifier spaces} ")" spaces block;</code>
586             * @return function Statement
587             * @throws TemplateException
588             */
589            public Function funcStatement(Data data,Body parent) throws TemplateException {
590                    int pos=data.cfml.getPos();
591                    
592                    // access modifier
593                    String strAccess=variableDeclaration(data, false, false);
594                    if(strAccess==null) {
595                            data.cfml.setPos(pos);
596                            return null;
597                    }
598                    
599                    String rtnType=null;
600                    
601                    if(strAccess.equalsIgnoreCase("FUNCTION")){
602                            strAccess=null;
603                    }
604                    else{
605                            comments(data);
606                            rtnType=variableDeclaration(data, false, false);
607                            
608                            if(rtnType==null){
609                                    data.cfml.setPos(pos);
610                                    return null;
611                            }
612                            if(rtnType.equalsIgnoreCase("FUNCTION")){
613                                    rtnType=null;
614                            }
615                            comments(data);
616                            
617                            if(rtnType!=null && !data.cfml.forwardIfCurrent("function ")){
618                                    data.cfml.setPos(pos);
619                                    return null;
620                            }
621                            comments(data);
622                    }
623                    
624                    
625                    // check access returntype
626                    int access=Component.ACCESS_PUBLIC;
627                    if(strAccess!=null && rtnType!=null){
628                            access = ComponentUtil.toIntAccess(strAccess,-1);
629                            if(access==-1)
630                                    throw new TemplateException(data.cfml,"invalid access type ["+strAccess+"], access types are remote, public, package, private");
631                    }
632                    if(strAccess!=null && rtnType==null){
633                            access = ComponentUtil.toIntAccess(strAccess,-1);
634                            if(access==-1){
635                                    rtnType=strAccess;
636                                    strAccess=null;
637                                    access=Component.ACCESS_PUBLIC;
638                            }
639                    }
640                    
641                    
642                    
643                    int line=data.cfml.getLine();
644                    
645                    comments(data);
646                    
647                    // Name
648                            String id=identifier(data,false,false);
649                            if(id==null) throw new TemplateException(data.cfml,"invalid name for a function");
650                            if(!data.isCFC && !data.isInterface){
651                                    FunctionLibFunction flf = getFLF(data,id);
652                                    if(flf!=null && flf.getCazz()!=CFFunction.class)throw new TemplateException(data.cfml,"The name ["+id+"] is already used by a built in Function");
653                            }
654                                    
655                            Body body=new FunctionBody();
656                            Function func=new Function(id,access,rtnType,body,line,-1);
657                            
658                    // start (
659                            comments(data);
660                            if(!data.cfml.forwardIfCurrent('('))
661                                    throw new TemplateException(data.cfml,"invalid syntax in function head, missing begin [(]");
662                    
663                            // arguments
664                            LitBoolean passByRef;
665                            Expression displayName;
666                            Expression hint;
667                            Map<String,Attribute> meta;
668                            String _name;
669                            do      {
670                                    comments(data);
671                                    // finish
672                                    if(data.cfml.isCurrent(')'))break;
673                                    
674                                    // attribute
675                                    
676                                    // name
677                                    //String idName=identifier(data,false,true);
678                                    boolean required=false;
679                                    
680                                    String idName=variableDeclaration(data, false, false);
681                                    // required
682                                    if("required".equalsIgnoreCase(idName)){
683                                            comments(data);
684                                            String idName2=variableDeclaration(data, false, false);
685                                            if(idName2!=null){
686                                                    idName=idName2;
687                                                    required=true;
688                                            }
689                                    }
690                                    
691                                    
692                                    String typeName="any";
693                                    if(idName==null) throw new TemplateException(data.cfml,"invalid argument definition");
694                                    comments(data);
695                                    if(!data.cfml.isCurrent(')') && !data.cfml.isCurrent('=') && !data.cfml.isCurrent(':') && !data.cfml.isCurrent(',')) {
696                                            typeName=idName.toLowerCase();
697                                            idName=identifier(data,false,true);
698                                    }
699                                    else if(idName.indexOf('.')!=-1 || idName.indexOf('[')!=-1) {
700                                            throw new TemplateException(data.cfml,"invalid argument name ["+idName+"] definition");
701                                    }
702                                    
703                                    comments(data);
704                                    Expression defaultValue;
705                                    if(data.cfml.isCurrent('=') || data.cfml.isCurrent(':')) {
706                                            data.cfml.next();
707                                            comments(data);
708                                            defaultValue=expression(data);
709                                    }
710                                    else defaultValue=null;
711                                    
712                                    // assign meta data defined in doc comment
713                                    passByRef = LitBoolean.TRUE;
714                                    displayName=LitString.EMPTY;
715                                    hint=LitString.EMPTY;
716                                    meta=null;
717                                    if(data.docComment!=null){
718                                            Map<String, Attribute> params = data.docComment.getParams();
719                                            Attribute[] attrs = params.values().toArray(new Attribute[params.size()]);
720                                            Attribute attr;
721                                            String name;
722                                            
723                                            for(int i=0;i<attrs.length;i++){
724                                                    attr=attrs[i];
725                                                    name=attr.getName();
726                                                    // hint
727                                                    if(idName.equalsIgnoreCase(name) || name.equalsIgnoreCase(idName+".hint")) {
728                                                            hint=CastString.toExprString(attr.getValue());
729                                                            params.remove(name);
730                                                    }
731                                                    //meta
732                                                    if(StringUtil.startsWithIgnoreCase(name, idName+".")) {
733                                                            if(name.length()>idName.length()+1){
734                                                                    if(meta==null) meta=new HashMap<String, Attribute>();
735                                                                    _name=name.substring(idName.length()+1);
736                                                                    meta.put(_name, new Attribute(attr.isDynamicType(), _name,attr.getValue(), attr.getType()));
737                                                            }
738                                                            params.remove(name);
739                                                    }
740                                            }
741                                            
742                                    }
743                                    
744                                    // argument attributes
745                                    Attribute[] _attrs = attributes(null,null,data,COMMA_ENDBRACKED,LitString.EMPTY,Boolean.TRUE,null,false);
746                                    Attribute _attr;
747                                    if(!ArrayUtil.isEmpty(_attrs)){
748                                            if(meta==null) meta=new HashMap<String, Attribute>();
749                                            for(int i=0;i<_attrs.length;i++){
750                                                    _attr=_attrs[i];
751                                                    meta.put(_attr.getName(), _attr);
752                                            }
753                                    }
754                                    
755                                    func.addArgument(
756                                                    LitString.toExprString(idName),
757                                                    LitString.toExprString(typeName),
758                                                    LitBoolean.toExprBoolean(required),
759                                                    defaultValue,passByRef,displayName,hint,meta);
760                                    
761                                    comments(data);
762                            }
763                            while(data.cfml.forwardIfCurrent(','));
764    
765                    
766                    // end )
767                            comments(data);
768                            if(!data.cfml.forwardIfCurrent(')'))
769                                    throw new TemplateException(data.cfml,"invalid syntax in function head, missing ending [)]");
770                    
771                    //TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,"function");
772                    
773                    // doc comment
774                    if(data.docComment!=null){
775                            func.setHint(data.docComment.getHint());
776                            
777                            
778                            // params
779                            Map<String, Attribute> params = data.docComment.getParams();
780                            Iterator<Attribute> it = params.values().iterator();
781                            Attribute attr;
782                            String name;
783                            while(it.hasNext()){
784                                    attr=it.next();
785                                    name=attr.getName();
786                            }
787                            
788                            func.setMetaData(data.docComment.getParams());
789                            data.docComment=null;
790                    }
791    
792                    comments(data);
793                            
794                    // attributes
795                    Attribute[] attrs = attributes(null,null,data,SEMI_BLOCK,LitString.EMPTY,Boolean.TRUE,null,false);
796                    for(int i=0;i<attrs.length;i++){
797                            func.addAttribute(attrs[i]);
798                    }
799                            
800                    // body
801                    boolean oldInsideFunction=data.insideFunction;
802                    data.insideFunction=true;
803                    try {
804                    // ex block
805                    statement(data,body,CTX_FUNCTION);
806                    }
807                    finally{
808                            data.insideFunction=oldInsideFunction;
809                    }
810                    func.setEndLine(data.cfml.getLine());
811                    //eval(tlt,data,func);
812                    return func;
813            }
814            
815    
816            
817            private Statement tagStatement(Data data, Body parent) throws TemplateException {
818                    Statement child;
819                    
820                    //TagLibTag[] tags = getScriptTags(data);
821                    for(int i=0;i<data.scriptTags.length;i++){
822                            // single
823                            if(data.scriptTags[i].getScript().getType()==TagLibTagScript.TYPE_SINGLE) { 
824                                    if((child=_singleAttrStatement(parent,data,data.scriptTags[i]))!=null)return child;
825                            }
826                            // multiple
827                            else {//if(tags[i].getScript().getType()==TagLibTagScript.TYPE_MULTIPLE) { 
828                                    if((child=_multiAttrStatement(parent,data,data.scriptTags[i]))!=null)return child;
829                            }
830                    }
831                    
832                    //if((child=_singleAttrStatement(parent,data,"abort","showerror",ATTR_TYPE_OPTIONAL,true))!=null)               return child;
833                    //if((child=_multiAttrStatement(parent,data,"admin",CTX_OTHER,false,true))!=null)                               return child;
834                    //else if((child=_multiAttrStatement(parent,data,"application",CTX_OTHER,false,true))!=null)                    return child;
835                    //else if((child=_multiAttrStatement(parent,data,"associate",CTX_OTHER,false,true))!=null)                      return child;
836                    //else if((child=_singleAttrStatement(parent,data,"break",null,ATTR_TYPE_NONE,false))!=null)                    return child;
837                    //else if((child=_multiAttrStatement(parent,data,"cache",CTX_OTHER,true,true))!=null)                           return child;
838                    //else if((child=_multiAttrStatement(parent,data,"content",CTX_OTHER,true,true))!=null)                         return child;
839                    //else if((child=_multiAttrStatement(parent,data,"collection",CTX_OTHER,true,true))!=null)                      return child;
840                    //else if((child=_multiAttrStatement(parent,data,"cookie",CTX_OTHER,false,true))!=null)                         return child;
841                    //else if((child=_multiAttrStatement(parent,data,"component",CTX_CFC,true,false))!=null)                                return child;
842                    //else if((child=_singleAttrStatement(parent,data,"continue",null,ATTR_TYPE_NONE,false))!=null)         return child;
843                    //else if((child=_multiAttrStatement(parent,data,"dbinfo",CTX_OTHER,false,true))!=null)                         return child;
844                    //else if((child=_multiAttrStatement(parent,data,"execute",CTX_OTHER,true,true))!=null)                         return child;
845                    //else if((child=_singleAttrStatement(parent,data,"exit","method",ATTR_TYPE_OPTIONAL,true))!=null)      return child;
846                    //else if((child=_multiAttrStatement(parent,data,"feed",CTX_OTHER,false,true))!=null)                                   return child;
847                    //else if((child=_multiAttrStatement(parent,data,"file",CTX_OTHER,false,true))!=null)                                   return child;
848                    //else if((child=_singleAttrStatement(parent,data,"flush","interval",ATTR_TYPE_OPTIONAL,true))!=null)   return child;
849                    //else if((child=_multiAttrStatement(parent,data,"ftp",CTX_OTHER,false,true))!=null)                                    return child;
850                    //else if((child=_multiAttrStatement(parent,data,"http",CTX_OTHER,true,true))!=null)                                    return child;
851                    //else if((child=_multiAttrStatement(parent,data,"httpparam",CTX_OTHER,false,true))!=null)                      return child;
852                    //else if((child=_multiAttrStatement(parent,data,"imap",CTX_OTHER,false,true))!=null)                                   return child;
853                    //else if((child=_singleAttrStatement(parent,data,"import","path",ATTR_TYPE_REQUIRED,false))!=null)     return child;
854                    //else if((child=_multiAttrStatement(parent,data,"index",CTX_OTHER,false,true))!=null)                          return child;
855                    //else if((child=_singleAttrStatement(parent,data,"include","template",ATTR_TYPE_REQUIRED,true))!=null)return child;
856                    //else if((child=_multiAttrStatement(parent,data,"interface",CTX_INTERFACE,true,false))!=null)          return child;
857                    //else if((child=_multiAttrStatement(parent,data,"ldap",CTX_OTHER,true,true))!=null)                                    return child;
858                    //else if((child=_multiAttrStatement(parent,data,"lock",CTX_LOCK,true,true))!=null)                                     return child;
859                    //else if((child=_multiAttrStatement(parent,data,"loop",CTX_LOOP,true,true))!=null)                                     return child;
860                    //else if((child=_multiAttrStatement(parent,data,"login",CTX_OTHER,true,true))!=null)                                   return child;
861                    //else if((child=_multiAttrStatement(parent,data,"loginuser",CTX_OTHER,false,true))!=null)                      return child;
862                    //else if((child=_singleAttrStatement(parent,data,"logout",null,ATTR_TYPE_NONE,false))!=null)                   return child;
863                    //else if((child=_multiAttrStatement(parent,data,"mail",CTX_OTHER,true,true))!=null)                                    return child;
864                    //else if((child=_multiAttrStatement(parent,data,"mailpart",CTX_OTHER,true,true))!=null)                                return child;
865                    //else if((child=_multiAttrStatement(parent,data,"mailparam",CTX_OTHER,false,true))!=null)                      return child;
866                    //else if((child=_multiAttrStatement(parent,data,"module",CTX_OTHER,true,true))!=null)                          return child;
867                    //else if((child=_singleAttrStatement(parent,data,"pageencoding","charset",ATTR_TYPE_OPTIONAL,true))!=null)     return child;
868                    //else if((child=_multiAttrStatement(parent,data,"param",CTX_OTHER,false,true))!=null)                          return child;
869                    //else if((child=_multiAttrStatement(parent,data,"pdf",CTX_OTHER,true,true))!=null)                                     return child;
870                    //else if((child=_multiAttrStatement(parent,data,"pdfparam",CTX_OTHER,false,true))!=null)                               return child;
871                    //else if((child=_multiAttrStatement(parent,data,"procparam",CTX_OTHER,false,true))!=null)                      return child;
872                    //else if((child=_multiAttrStatement(parent,data,"procresult",CTX_OTHER,false,true))!=null)                     return child;
873                    //else if((child=_multiAttrStatement(parent,data,"query",CTX_QUERY,true,true))!=null)                                   return child;
874                    //else if((child=_multiAttrStatement(parent,data,"queryparam",CTX_OTHER,false,true))!=null)                     return child;
875                    //else if((child=_singleAttrStatement(parent,data,"rethrow",null,ATTR_TYPE_NONE,false))!=null)          return child;
876                    //else if((child=_multiAttrStatement(parent,data,"savecontent",CTX_SAVECONTENT,true,true))!=null)               return child;
877                    //else if((child=_multiAttrStatement(parent,data,"schedule",CTX_OTHER,false,true))!=null)                               return child;
878                    //else if((child=_multiAttrStatement(parent,data,"search",CTX_OTHER,false,true))!=null)                         return child;
879                    //else if((child=_multiAttrStatement(parent,data,"setting",CTX_OTHER,false,true))!=null)                                return child;
880                    //else if((child=_multiAttrStatement(parent,data,"stopwatch",CTX_OTHER,true,true))!=null)                               return child;
881                    //else if((child=_multiAttrStatement(parent,data,"storedproc",CTX_OTHER,true,true))!=null)                      return child;
882                    //else if((child=_multiAttrStatement(parent,data,"thread",CTX_THREAD,true,true))!=null)                         return child;
883                    //else if((child=_multiAttrStatement(parent,data,"trace",CTX_OTHER,true,true))!=null)                                   return child;
884                    //else if((child=_singleAttrStatement(parent,data,"throw","message",ATTR_TYPE_OPTIONAL,true))!=null)    return child;
885                    //else if((child=_multiAttrStatement(parent,data,"transaction",CTX_TRANSACTION,true,true))!=null)               return child;
886                    //else if((child=_multiAttrStatement(parent,data,"wddx",CTX_OTHER,false,true))!=null)                                   return child;
887                    //else if((child=_multiAttrStatement(parent,data,"zip",CTX_ZIP,true,true))!=null)                                               return child;
888                    //else if((child=_multiAttrStatement(parent,data,"zipparam",CTX_ZIP,false,true))!=null)                         return child;
889                    
890                    
891                    return null;
892            }
893            
894            
895    
896            
897            
898            public Statement _multiAttrStatement(Body parent, Data data,TagLibTag tlt) throws TemplateException  {
899                    int pos = data.cfml.getPos();
900                    try {
901                            return __multiAttrStatement(parent,data,tlt);
902                    } 
903                    catch (ProcessingDirectiveException e) {
904                            throw e;
905                    }
906                    catch (TemplateException e) {
907                            try {
908                                    data.cfml.setPos(pos);
909                                    return expressionStatement(data);
910                            } catch (TemplateException e1) {
911                                    if(tlt.getScript().getContext()==CTX_CFC) throw new ComponentTemplateException(e);
912                                    throw e;
913                            }
914                    }
915            }
916    
917            /*public Statement _multiAttrStatement(Body parent, Data data,String type,short context,boolean hasBody,boolean allowExpression) throws TemplateException  {
918                    int pos = data.cfml.getPos();
919                    try {
920                            return __multiAttrStatement(parent,data,type,context,hasBody,allowExpression);
921                    } 
922                    catch (ProcessingDirectiveException e) {
923                            throw e;
924                    }
925                    catch (TemplateException e) {
926                            try {
927                                    data.cfml.setPos(pos);
928                                    return expressionStatement(data);
929                            } catch (TemplateException e1) {
930                                    if(context==CTX_CFC) throw new ComponentBodyException(e);
931                                    throw e;
932                            }
933                    }
934            }*/
935            
936            public Tag __multiAttrStatement(Body parent, Data data,TagLibTag tlt) throws TemplateException  {
937                    if(data.ep==null) return null;
938                    String type=tlt.getName();
939                    if(data.cfml.forwardIfCurrent(type)) {
940                            boolean isValid=(data.cfml.isCurrent(' ') || (tlt.getHasBody() && data.cfml.isCurrent('{')));
941                            if(!isValid){
942                                    data.cfml.setPos(data.cfml.getPos()-type.length());
943                                    return null;
944                            }
945                    }
946                    else return null;
947                    int line=data.cfml.getLine();
948                    
949                    TagLibTagScript script = tlt.getScript();
950                    //TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,type);
951                    if(script.getContext()==CTX_CFC)data.isCFC=true;
952                    else if(script.getContext()==CTX_INTERFACE)data.isInterface=true;
953                    //Tag tag=new TagComponent(line);
954                    Tag tag=getTag(parent,tlt, line);
955                    tag.setTagLibTag(tlt);
956                    tag.setScriptBase(true);
957                    
958                    // add component meta data
959                    if(data.isCFC) {
960                            addMetaData(data,tag,IGNORE_LIST_COMPONENT);
961                    }
962                    if(data.isInterface) {
963                            addMetaData(data,tag,IGNORE_LIST_INTERFACE);
964                    }
965                    //EvaluatorPool.getPool();
966                    comments(data);
967                    
968                    // attributes
969                    //attributes(func,data);
970                    Attribute[] attrs = attributes(tag,tlt,data,SEMI_BLOCK,LitString.EMPTY,script.getRtexpr()?Boolean.TRUE:Boolean.FALSE,null,false);
971                    
972                    for(int i=0;i<attrs.length;i++){
973                            tag.addAttribute(attrs[i]);
974                    }
975                    
976                    comments(data);
977            
978                    // body
979                    if(tlt.getHasBody()){
980                            Body body=new BodyBase();
981                            statement(data,body,script.getContext());
982                            tag.setBody(body);
983                    }
984                    else checkSemiColonLineFeed(data,true);
985                    
986                    eval(tlt,data,tag);
987                    return tag;
988            }
989            
990            
991            
992            private void addMetaData(Data data, Tag tag, String[] ignoreList) {
993                    if(data.docComment==null) return;
994                    
995    
996                    tag.addMetaData(data.docComment.getHintAsAttribute());
997                    
998                    Map<String, Attribute> params = data.docComment.getParams();
999                    Iterator<Attribute> it = params.values().iterator();
1000                    Attribute attr;
1001                    outer:while(it.hasNext()){
1002                            attr = it.next();
1003                            // ignore list
1004                            if(!ArrayUtil.isEmpty(ignoreList)) {
1005                                    for(int i=0;i<ignoreList.length;i++){
1006                                            if(ignoreList[i].equalsIgnoreCase(attr.getName())) continue outer;
1007                                    }
1008                            }
1009                            tag.addMetaData(attr);  
1010                    }
1011                    data.docComment=null;
1012            }
1013    
1014            /*private void addMetaData(Data data, Tag tag, String[] ignoreList) {
1015                    if(data.docComment==null) return ;
1016                    
1017                    tag.addAttribute(new Attribute(false, "hint", LitString.toExprString(data.docComment.getHint()), "string"));
1018                    Map<String, Attribute> params = data.docComment.getParams();
1019                    
1020                    Iterator<Entry<String, Attribute>> it = params.entrySet().iterator();
1021                    Entry<String, Attribute> entry;
1022                    outer:while(it.hasNext()){
1023                            entry = it.next();
1024    
1025                            // ignore list
1026                            if(!ArrayUtil.isEmpty(ignoreList)) {
1027                                    for(int i=0;i<ignoreList.length;i++){
1028                                            if(ignoreList[i].equalsIgnoreCase(entry.getKey())) continue outer;
1029                                    }
1030                            }
1031                            tag.addAttribute(entry.getValue());
1032                    }
1033                    
1034    
1035                    data.docComment=null;
1036                    
1037            }*/
1038    
1039            /*public Tag __multiAttrStatement(Body parent, Data data,String type,short context,boolean hasBody,boolean allowExpression) throws TemplateException  {
1040                    if(data.ep==null) return null;
1041                    
1042                    if(data.cfml.forwardIfCurrent(type)){
1043                            boolean isValid=(data.cfml.isCurrent(' ') || (hasBody && data.cfml.isCurrent('{')));
1044                            if(!isValid){
1045                                    data.cfml.setPos(data.cfml.getPos()-type.length());
1046                                    return null;
1047                            }
1048                    }
1049                    else return null;
1050                    int line=data.cfml.getLine();
1051                    
1052                    
1053                    TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,type);
1054                    if(context==CTX_CFC)data.isCFC=true;
1055                    else if(context==CTX_INTERFACE)data.isInterface=true;
1056                    //Tag tag=new TagComponent(line);
1057                    Tag tag=getTag(parent,tlt, line);
1058                    tag.setTagLibTag(tlt);
1059                    tag.setScriptBase(true);
1060                    //EvaluatorPool.getPool();
1061                    comments(data);
1062                    
1063                    // attributes
1064                    //attributes(func,data);
1065                    Attribute[] attrs = attributes(tag,tlt,data,true,EMPTY_STRING,allowExpression,null,false);
1066                    
1067                    for(int i=0;i<attrs.length;i++){
1068                            tag.addAttribute(attrs[i]);
1069                    }
1070                    
1071                    comments(data);
1072            
1073                    // body
1074                    if(hasBody){
1075                            Body body=new BodyBase();
1076                            statement(data,body,context);
1077                            tag.setBody(body);
1078                    }
1079                    else checkSemiColonLineFeed(data,true);
1080                    
1081                    eval(tlt,data,tag);
1082                    return tag;
1083            }*/
1084            
1085            
1086            
1087            public Statement propertyStatement(Data data,Body parent) throws TemplateException  {
1088                    int pos = data.cfml.getPos();
1089                    try {
1090                            return _propertyStatement(data, parent);
1091                    } catch (TemplateException e) {
1092                            try {
1093                                    data.cfml.setPos(pos);
1094                                    return expressionStatement(data);
1095                            } catch (TemplateException e1) {
1096                                    throw e;
1097                            }
1098                    }
1099            }
1100            
1101            private Tag _propertyStatement(Data data,Body parent) throws TemplateException  {
1102                    if(data.context!=CTX_CFC || !data.cfml.forwardIfCurrent("property "))
1103                            return null;
1104                    int line=data.cfml.getLine();
1105                    
1106                    TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,"property");
1107                    Tag property=new TagBase(line);
1108                    addMetaData(data, property,IGNORE_LIST_PROPERTY);
1109                    
1110    
1111                    boolean hasName=false,hasType=false;
1112    
1113                    // TODO allow the following pattern property "a.b.C" d;
1114                    //Expression t = string(data);
1115                    // print.o("name:"+t.getClass().getName());
1116                    
1117                    int pos = data.cfml.getPos();
1118                    String tmp=variableDeclaration(data, true, false);
1119                    if(!StringUtil.isEmpty(tmp)) {
1120                            if(tmp.indexOf('.')!=-1) {
1121                                    property.addAttribute(new Attribute(false,"type",LitString.toExprString(tmp),"string"));
1122                                    hasType=true;
1123                            }
1124                            else {
1125                                    data.cfml.setPos(pos);
1126                            }
1127                    }
1128                    else data.cfml.setPos(pos);
1129                    
1130                    
1131                    
1132                    // folgend wird tlt extra nicht �bergeben, sonst findet pr�fung statt
1133                    Attribute[] attrs = attributes(property,tlt,data,SEMI,  NULL,Boolean.FALSE,"name",true);
1134                    
1135                    checkSemiColonLineFeed(data,true);
1136    
1137                    property.setTagLibTag(tlt);
1138                    property.setScriptBase(true);
1139                    
1140                    
1141                    Attribute attr;
1142                    
1143                    // first fill all regular attribute -> name="value"
1144                    for(int i=attrs.length-1;i>=0;i--){
1145                            attr=attrs[i];
1146                            if(!attr.getValue().equals(NULL)){
1147                                    if(attr.getName().equalsIgnoreCase("name")){
1148                                            hasName=true;
1149                                            //attr=new Attribute(attr.isDynamicType(),attr.getName(),CastString.toExprString(attr.getValue()),"string");
1150                                    }
1151                                    else if(attr.getName().equalsIgnoreCase("type")){
1152                                            hasType=true;
1153                                            //attr=new Attribute(attr.isDynamicType(),attr.getName(),CastString.toExprString(attr.getValue()),"string");
1154                                    }
1155                                    property.addAttribute(attr);
1156                            }
1157                    }
1158                    
1159                    // now fill name named attributes -> attr1 attr2
1160                    
1161                    String first=null,second=null;
1162                    for(int i=0;i<attrs.length;i++){
1163                            attr=attrs[i];
1164                            
1165                            if(attr.getValue().equals(NULL)){
1166                                    // type
1167                                    if(first==null && (!hasName || !hasType)){
1168                                            first=attr.getName();
1169                                            //type=new Attribute(false,"type",LitString.toExprString(attr.getName()),"string");
1170                                            //property.addAttribute(type);
1171                                    }
1172                                    // name
1173                                    else if(second==null && !hasName && !hasType){
1174                                            second=attr.getName();
1175                                            //name=new Attribute(false,"name",LitString.toExprString(attr.getName()),"string");
1176                                            //property.addAttribute(name);
1177                                    }
1178                                    // attr with no value
1179                                    else {
1180                                            attr=new Attribute(true,attr.getName(),LitString.EMPTY,"string");
1181                                            property.addAttribute(attr);
1182                                    }
1183                            }
1184                    }
1185    
1186                    
1187                    
1188                    if(first!=null) {
1189                                    hasName=true;
1190                            if(second!=null){
1191                                    hasType=true;
1192                                    property.addAttribute(new Attribute(false,"name",LitString.toExprString(second),"string"));
1193                                    property.addAttribute(new Attribute(false,"type",LitString.toExprString(first),"string"));
1194                            }
1195                            else {
1196                                    property.addAttribute(new Attribute(false,"name",LitString.toExprString(first),"string"));
1197                            }
1198                    }
1199                    
1200                    if(!hasType)
1201                            property.addAttribute(ANY);
1202                    
1203                    if(!hasName)
1204                            throw new TemplateException(data.cfml,"missing name declaration for property");
1205    
1206                    /*Tag property=new TagBase(line);
1207                    property.setTagLibTag(tlt);
1208                    property.addAttribute(new Attribute(false,"name",LitString.toExprString(name),"string"));
1209                    property.addAttribute(new Attribute(false,"type",LitString.toExprString(type),"string"));
1210                    */
1211                    
1212                    
1213                    return property;
1214            }
1215            
1216    
1217            public Statement paramStatement(Data data,Body parent) throws TemplateException  {
1218                    int pos = data.cfml.getPos();
1219                    try {
1220                            return _paramStatement(data, parent);
1221                    } catch (TemplateException e) {
1222                            try {
1223                                    data.cfml.setPos(pos);
1224                                    return expressionStatement(data);
1225                            } catch (TemplateException e1) {
1226                                    throw e;
1227                            }
1228                    }
1229            }
1230            
1231            private Tag _paramStatement(Data data,Body parent) throws TemplateException  {
1232                    if(!data.cfml.forwardIfCurrent("param "))
1233                            return null;
1234                    int line=data.cfml.getLine();
1235                    
1236                    TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,"param");
1237                    TagParam param=new TagParam(line);
1238                    
1239                    // type
1240                    boolean hasType=false;
1241                    int pos = data.cfml.getPos();
1242                    String tmp=variableDeclaration(data, true, false);
1243                    if(!StringUtil.isEmpty(tmp)) {
1244                            if(tmp.indexOf('.')!=-1) {
1245                                    param.addAttribute(new Attribute(false,"type",LitString.toExprString(tmp),"string"));
1246                                    hasType=true;
1247                            }
1248                            else data.cfml.setPos(pos);
1249                    }
1250                    else data.cfml.setPos(pos);
1251                    
1252                    
1253                    
1254                    // folgend wird tlt extra nicht �bergeben, sonst findet pr�fung statt
1255                    Attribute[] attrs = attributes(param,tlt,data,SEMI,     NULL,Boolean.TRUE,"name",true);
1256                    checkSemiColonLineFeed(data,true);
1257    
1258                    param.setTagLibTag(tlt);
1259                    param.setScriptBase(true);
1260                    
1261                    
1262                    Attribute attr;
1263                    
1264                    // first fill all regular attribute -> name="value"
1265                    boolean hasDynamic=false;
1266                    boolean hasName=false;
1267                    for(int i=attrs.length-1;i>=0;i--){
1268                            attr=attrs[i];
1269                            if(!attr.getValue().equals(NULL)){
1270                                    if(attr.getName().equalsIgnoreCase("name")){
1271                                            hasName=true;
1272                                            param.addAttribute(attr);
1273                                    }
1274                                    else if(attr.getName().equalsIgnoreCase("type")){
1275                                            hasType=true;
1276                                            param.addAttribute(attr);
1277                                    }
1278                                    else if(attr.isDynamicType()){
1279                                            hasName=true;
1280                                            if(hasDynamic) throw attrNotSupported(data.cfml,tlt,attr.getName());
1281                                            hasDynamic=true;
1282                                            param.addAttribute(new Attribute(false,"name",LitString.toExprString(attr.getName()),"string"));
1283                                            param.addAttribute(new Attribute(false,"default",attr.getValue(),"any"));
1284                                    }
1285                                    else 
1286                                            param.addAttribute(attr);
1287                            }
1288                    }
1289                    
1290                    // now fill name named attributes -> attr1 attr2
1291                    String first=null,second=null;
1292                    for(int i=0;i<attrs.length;i++){
1293                            attr=attrs[i];
1294                            
1295                            if(attr.getValue().equals(NULL)){
1296                                    // type
1297                                    if(first==null && (!hasName || !hasType)){
1298                                            first=attr.getName();
1299                                    }
1300                                    // name
1301                                    else if(second==null && !hasName && !hasType){
1302                                            second=attr.getName();
1303                                    }
1304                                    // attr with no value
1305                                    else {
1306                                            attr=new Attribute(true,attr.getName(),LitString.EMPTY,"string");
1307                                            param.addAttribute(attr);
1308                                    }
1309                            }
1310                    }
1311    
1312                    
1313                    if(first!=null) {
1314                            if(second!=null){
1315                                    hasName=true;
1316                                    hasType=true;
1317                                    if(hasDynamic) throw attrNotSupported(data.cfml,tlt,first);
1318                                    hasDynamic=true;
1319                                    param.addAttribute(new Attribute(false,"name",LitString.toExprString(second),"string"));
1320                                    param.addAttribute(new Attribute(false,"type",LitString.toExprString(first),"string"));
1321                            }
1322                            else {
1323                                    param.addAttribute(new Attribute(false,hasName?"type":"name",LitString.toExprString(first),"string"));
1324                                    hasName=true;
1325                            }
1326                    }
1327                    
1328                    //if(!hasType)
1329                    //      param.addAttribute(ANY);
1330                    
1331                    if(!hasName)
1332                            throw new TemplateException(data.cfml,"missing name declaration for param");
1333    
1334                    return param;
1335            }
1336    
1337    
1338            private TemplateException attrNotSupported(CFMLString cfml, TagLibTag tag, String id) {
1339                    String names=tag.getAttributeNames();
1340                    if(StringUtil.isEmpty(names))
1341                            return new TemplateException(cfml,"Attribute "+id+" is not allowed for tag "+tag.getFullName());
1342                    
1343                    return new TemplateException(cfml,
1344                            "Attribute "+id+" is not allowed for statement "+tag.getName(),
1345                            "valid attribute names are ["+names+"]");
1346            }
1347    
1348            protected String variableDeclaration(Data data,boolean firstCanBeNumber,boolean upper) {
1349                    
1350                    String id=identifier(data, firstCanBeNumber, upper);
1351                    if(id==null) return null;
1352                    
1353                    StringBuffer rtn=new StringBuffer(id);
1354                    data.cfml.removeSpace();
1355                    
1356                    while(data.cfml.forwardIfCurrent('.')){
1357                            data.cfml.removeSpace();
1358                            rtn.append('.');
1359                            id=identifier(data, firstCanBeNumber, upper);
1360                            if(id==null)return null;
1361                            rtn.append(id);
1362                            data.cfml.removeSpace();
1363                    }
1364                    
1365                    while(data.cfml.forwardIfCurrent("[]")){
1366                            data.cfml.removeSpace();
1367                            rtn.append("[]");
1368                    }
1369                    return rtn.toString();
1370            }
1371            
1372            /**
1373             * Liest ein return Statement ein.
1374             * <br />
1375             * EBNF:<br />
1376             * <code>spaces expressionStatement spaces;</code>
1377             * @return return Statement
1378             * @throws TemplateException
1379             */
1380            protected Return returnStatement(Data data) throws TemplateException {
1381                if(!data.cfml.forwardIfCurrentAndNoVarExt("return")) return null;
1382                
1383                int line=data.cfml.getLine();
1384                Return rtn;
1385                
1386                comments(data);
1387                if(data.cfml.forwardIfCurrent(';')) rtn=new Return(line);
1388                else {
1389                    Expression expr = expression(data);
1390                    
1391                    if(!data.cfml.forwardIfCurrent(';'))
1392                                    throw new TemplateException(data.cfml,"Missing [;] after expression");
1393                            
1394                    
1395                    rtn=new Return(expr,line);
1396                }
1397                    comments(data);
1398    
1399                    return rtn;
1400            }
1401    
1402            
1403            protected Statement _singleAttrStatement(Body parent, Data data, TagLibTag tlt) throws TemplateException   {
1404                    int pos = data.cfml.getPos();
1405                    try {
1406                            return __singleAttrStatement(parent,data,tlt, false);
1407                    } 
1408                    catch (ProcessingDirectiveException e) {
1409                            throw e;
1410                    } 
1411                    catch (TemplateException e) {
1412                            data.cfml.setPos(pos);
1413                            try {
1414                                    return expressionStatement(data);
1415                            } catch (TemplateException e1) {
1416                                    throw e;
1417                            }
1418                    }
1419            }
1420            
1421            /*protected Statement _singleAttrStatement(Body parent, Data data, String tagName,String attrName,int attrType, boolean allowExpression) throws TemplateException   {
1422                    int pos = data.cfml.getPos();
1423                    try {
1424                            return __singleAttrStatement(parent,data,tagName,attrName,attrType,allowExpression, false);
1425                    } 
1426                    catch (ProcessingDirectiveException e) {
1427                            throw e;
1428                    } 
1429                    catch (TemplateException e) {
1430                            data.cfml.setPos(pos);
1431                            try {
1432                                    return expressionStatement(data);
1433                            } catch (TemplateException e1) {
1434                                    throw e;
1435                            }
1436                    }
1437            }*/
1438            
1439            protected Statement __singleAttrStatement(Body parent, Data data, TagLibTag tlt, boolean allowTwiceAttr) throws TemplateException {
1440                    String tagName = tlt.getName();
1441                    if(data.cfml.forwardIfCurrent(tagName)){
1442                            if(!data.cfml.isCurrent(' ') && !data.cfml.isCurrent(';')){
1443                                    data.cfml.setPos(data.cfml.getPos()-tagName.length());
1444                                    return null;
1445                            }
1446                    }
1447                    else return null;
1448                    
1449                    
1450                    int pos=data.cfml.getPos()-tagName.length();
1451                    int line=data.cfml.getLine();
1452                    //TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,tagName.equals("pageencoding")?"processingdirective":tagName);
1453                    
1454                    Tag tag=getTag(parent,tlt,line);
1455                    tag.setScriptBase(true);
1456                    tag.setTagLibTag(tlt);
1457                    
1458                    comments(data);
1459                    
1460                    // attribute
1461                    TagLibTagAttr attr = tlt.getScript().getSingleAttr();
1462                    String attrName=null;
1463                    Expression attrValue=null;
1464                    short attrType=ATTR_TYPE_NONE;
1465                    if(attr!=null){
1466                            attrType = attr.getScriptSupport();
1467                            if(ATTR_TYPE_REQUIRED==attrType || (!data.cfml.isCurrent(';') && ATTR_TYPE_OPTIONAL==attrType))
1468                                    attrValue =attributeValue(data, tlt.getScript().getRtexpr());
1469                    }
1470                    
1471                    if(attrValue!=null){
1472                            attrName=attr.getName();
1473                            TagLibTagAttr tlta = tlt.getAttribute(attr.getName());
1474                            tag.addAttribute(new Attribute(false,attrName,Cast.toExpression(attrValue,tlta.getType()),tlta.getType()));
1475                    }
1476                    else if(ATTR_TYPE_REQUIRED==attrType){
1477                            data.cfml.setPos(pos);
1478                            return null;
1479                    }
1480                    
1481                    checkSemiColonLineFeed(data,true);
1482                    if(!StringUtil.isEmpty(tlt.getTteClassName()))data.ep.add(tlt, tag, data.fld, data.cfml);
1483                    
1484                    if(!StringUtil.isEmpty(attrName))validateAttributeName(attrName, data.cfml, new ArrayList<String>(), tlt, new RefBooleanImpl(false), new StringBuffer(), allowTwiceAttr);
1485                    
1486                    eval(tlt,data,tag);
1487                    return tag;
1488            }
1489    
1490            /*protected Statement __singleAttrStatement(Body parent, Data data, String tagName,String attrName,int attrType, boolean allowExpression, boolean allowTwiceAttr) throws TemplateException {
1491                    
1492                    if(data.cfml.forwardIfCurrent(tagName)){
1493                            if(!data.cfml.isCurrent(' ') && !data.cfml.isCurrent(';')){
1494                                    data.cfml.setPos(data.cfml.getPos()-tagName.length());
1495                                    return null;
1496                            }
1497                    }
1498                    else return null;
1499                    
1500                    
1501                    int pos=data.cfml.getPos()-tagName.length();
1502                    int line=data.cfml.getLine();
1503                    TagLibTag tlt = CFMLTransformer.getTLT(data.cfml,tagName.equals("pageencoding")?"processingdirective":tagName);
1504                    
1505                    Tag tag=getTag(parent,tlt,line);
1506                    tag.setScriptBase(true);
1507                    tag.setTagLibTag(tlt);
1508                    
1509                    comments(data);
1510                    
1511                    // attribute
1512                    Expression attrValue=null;
1513                    if(ATTR_TYPE_REQUIRED==attrType || (!data.cfml.isCurrent(';') && ATTR_TYPE_OPTIONAL==attrType))
1514                            attrValue =attributeValue(data, allowExpression);
1515                                    //allowExpression?super.expression(data):string(data);
1516                    
1517                    if(attrValue!=null){
1518                            TagLibTagAttr tlta = tlt.getAttribute(attrName);
1519                            tag.addAttribute(new Attribute(false,attrName,Cast.toExpression(attrValue,tlta.getType()),tlta.getType()));
1520                    }
1521                    else if(ATTR_TYPE_REQUIRED==attrType){
1522                            data.cfml.setPos(pos);
1523                            return null;
1524                    }
1525                    
1526                    checkSemiColonLineFeed(data,true);
1527                    if(!StringUtil.isEmpty(tlt.getTteClassName()))data.ep.add(tlt, tag, data.fld, data.cfml);
1528                    
1529                    if(!StringUtil.isEmpty(attrName))validateAttributeName(attrName, data.cfml, new ArrayList<String>(), tlt, new RefBooleanImpl(false), new StringBuffer(), allowTwiceAttr);
1530                    
1531                    eval(tlt,data,tag);
1532                    return tag;
1533            }*/
1534            
1535            
1536    
1537            private void eval(TagLibTag tlt, railo.transformer.cfml.expression.CFMLExprTransformer.Data data, Tag tag) throws TemplateException {
1538                    if(!StringUtil.isEmpty(tlt.getTteClassName())){
1539                            try {
1540                                    tlt.getEvaluator().execute(ThreadLocalPageContext.getConfig(), tag, tlt,data.fld, data.cfml);
1541                            } catch (EvaluatorException e) {
1542                                    throw new TemplateException(e.getMessage());
1543                            }
1544                            data.ep.add(tlt, tag, data.fld, data.cfml);
1545                    }
1546            }
1547    
1548            private Tag getTag(Body parent, TagLibTag tlt, int line) {
1549                    Tag tag =null;
1550                    if(StringUtil.isEmpty(tlt.getTttClassName()))tag= new TagBase(line);
1551                    else {
1552                            try {
1553                                    Class<Tag> clazz = ClassUtil.loadClass(tlt.getTttClassName());
1554                                    Constructor<Tag> constr = clazz.getConstructor(new Class[]{int.class});
1555                                    tag = constr.newInstance(new Object[]{Caster.toInteger(line)});
1556                                    
1557                            } 
1558                            catch (Exception e) {
1559                                    e.printStackTrace();
1560                                    tag= new TagBase(line);
1561                            }
1562                    }
1563                    tag.setParent(parent);
1564                    return tag;
1565            }
1566            
1567            
1568            
1569            /**
1570             * List mithilfe des data.cfmlExprTransformer einen Ausruck ein.
1571             * <br />
1572             * EBNF:<br />
1573             * <code>expression ";";</code>
1574             * @return Ausdruck
1575             * @throws TemplateException
1576             */
1577            public ExpressionStatement expressionStatement(Data data) throws TemplateException {
1578                    Expression expr=expression(data);
1579                    checkSemiColonLineFeed(data,true);
1580                    
1581                    return new ExpressionStatement(expr);
1582            }
1583            
1584            private boolean checkSemiColonLineFeed(Data data,boolean throwError) throws TemplateException {
1585                    comments(data);
1586                    if(!data.cfml.forwardIfCurrent(';')){
1587                            if(!data.cfml.hasNLBefore() && !data.cfml.isCurrent("</",data.tagName) && !data.cfml.isCurrent('}')){
1588                                    if(!throwError) return false;
1589                                    throw new TemplateException(data.cfml,"Missing [;] or [line feed] after expression");
1590                            }
1591                    }
1592                    return true;
1593            }
1594    
1595            /**
1596             * @see railo.transformer.data.cfml.expression.data.cfmlExprTransformer#expression()
1597             */
1598            public Expression expression(Data data) throws TemplateException {
1599                    Expression expr;
1600                    expr = super.expression(data);
1601                    comments(data);
1602                    return expr;
1603            }
1604            
1605            /**
1606             * Ruft die Methode expression der zu vererbenten Klasse auf 
1607             * und pr�ft ob der R�ckgabewert einen boolschen Wert repr�sentiert und castet den Wert allenfalls.
1608             * <br />
1609             * EBNF:<br />
1610             * <code>TemplateException::expression;</code>
1611             * @return condition
1612             * @throws TemplateException
1613             */
1614            public ExprBoolean condition(Data data) throws TemplateException {
1615                    ExprBoolean condition=null;
1616                    comments(data);
1617                    condition=CastBoolean.toExprBoolean(super.expression(data));
1618                    comments(data);
1619                    return condition;
1620            }
1621            
1622            /**
1623             * Liest eine try Block ein
1624             * <br />
1625             * EBNF:<br />
1626             * <code>;</code>
1627             * @return Try Block
1628             * @throws TemplateException
1629            */
1630            public TryCatchFinally tryStatement(Data data) throws TemplateException {
1631                    if(!data.cfml.forwardIfCurrent("try",'{') && !data.cfml.forwardIfCurrent("try ") && !data.cfml.forwardIfCurrent("try",'/'))
1632                            return null;
1633                    data.cfml.previous();
1634    
1635                    Body body=new BodyBase();
1636                    TryCatchFinally tryCatchFinally=new TryCatchFinally(body,data.cfml.getLine(),-1);
1637                    
1638                    statement(data,body,CTX_TRY);
1639                    comments(data);
1640                    
1641                    // catches
1642                    short catchCount=0;
1643                    while(data.cfml.forwardIfCurrent("catch",'(')) {
1644                            catchCount++;
1645                            comments(data);
1646                            
1647                            // type
1648                            int pos=data.cfml.getPos();
1649                            int line=data.cfml.getLine();
1650                            Expression name = null,type = null;
1651                            
1652                            StringBuffer sbType=new StringBuffer();
1653                String tmp;
1654                while(true) {
1655                    tmp=identifier(data,false,false);
1656                    if(tmp==null)break;
1657                    sbType.append(tmp);
1658                    data.cfml.removeSpace();
1659                    if(!data.cfml.forwardIfCurrent('.'))break;
1660                    sbType.append('.');
1661                    data.cfml.removeSpace();
1662                }
1663                                    
1664                
1665                            if(sbType.length()==0) {
1666                                type=string(data);
1667                                if(type==null)                          
1668                                    throw new TemplateException(data.cfml,"a catch statement must begin with the throwing type (query, application ...).");
1669                            }
1670                            else {
1671                                    type=LitString.toExprString(sbType.toString());
1672                            } 
1673                
1674                
1675                            //name = expression();
1676                            comments(data);
1677                            
1678                            // name
1679                            if(!data.cfml.isCurrent(')')) {
1680                                    name=expression(data);
1681                            }
1682                            else {
1683                                    data.cfml.setPos(pos);
1684                                    name=expression(data);
1685                            }
1686                            comments(data);
1687    
1688                Body b=new BodyBase();
1689                            try {
1690                                    tryCatchFinally.addCatch(type,name,b,line);
1691                            } 
1692                            catch (BytecodeException e) {
1693                                    throw new TemplateException(data.cfml,e.getMessage());
1694                            }
1695                            comments(data);
1696                            
1697                            if(!data.cfml.forwardIfCurrent(')')) throw new TemplateException(data.cfml,"invalid catch statement, missing closing )");
1698                            
1699                statement(data,b,CTX_CATCH);
1700                            comments(data); 
1701                    }
1702            
1703                    
1704    // finally
1705                     if(finallyStatement(data,tryCatchFinally)) {
1706                            comments(data);
1707                     }
1708                     else if(catchCount==0)
1709                            throw new TemplateException(data.cfml,"a try statement must have at least one catch statement");
1710                    
1711            //if(body.isEmpty()) return null;
1712                    tryCatchFinally.setEndLine(data.cfml.getLine());
1713                    return tryCatchFinally;
1714            }
1715            
1716            /**
1717             * Pr�ft ob sich der Zeiger am Ende eines Script Blockes befindet
1718             * @return Ende ScriptBlock?
1719             * @throws TemplateException
1720             */
1721            public boolean isFinish(Data data) throws TemplateException {
1722                    comments(data);
1723                    return data.cfml.isCurrent("</",data.tagName);               
1724            }
1725            
1726            
1727            /**
1728             * Liest den Block mit Statements ein.
1729             * <br />
1730             * EBNF:<br />
1731             * <code>"{" spaces {statements} "}" | statement;</code>
1732             * @param block
1733             * @return was a block
1734             * @throws TemplateException
1735             */
1736            private boolean block(Data data,Body body) throws TemplateException {
1737                    if(!data.cfml.forwardIfCurrent('{'))
1738                            return false;
1739                    comments(data);
1740                    if(data.cfml.forwardIfCurrent('}')) {
1741                            
1742                            return true;
1743                    }
1744                    statements(data,body,false);
1745                    
1746                    if(!data.cfml.forwardIfCurrent('}'))
1747                            throw new TemplateException(data.cfml,"Missing ending [}]");
1748                    return true;
1749            }       
1750            
1751            
1752            
1753            
1754            
1755            
1756            
1757            
1758            
1759            
1760            
1761            
1762            
1763            
1764            
1765            public Attribute[] attributes(Tag tag,TagLibTag tlt, Data data, EndCondition endCond,Expression defaultValue,Object  oAllowExpression, 
1766                            String ignoreAttrReqFor, boolean allowTwiceAttr) throws TemplateException {
1767                    ArrayList<Attribute> attrs=new ArrayList<Attribute>();
1768                    ArrayList<String> ids=new ArrayList<String>();
1769                    
1770                    while(data.cfml.isValidIndex()) {
1771                            data.cfml.removeSpace();
1772                            // if no more attributes break
1773                            if(endCond.isEnd(data)) break;
1774                            //if((allowBlock && data.cfml.isCurrent('{')) || data.cfml.isCurrent(';')) break;
1775                            Attribute attr = attribute(tlt,data,ids,defaultValue,oAllowExpression, allowTwiceAttr);
1776                            attrs.add(attr);
1777                    }
1778                    
1779                    // not defined attributes
1780                    if(tlt!=null){
1781                            boolean hasAttributeCollection=attrs.contains("attributecollection");
1782                            int type=tlt.getAttributeType();
1783                            if(type==TagLibTag.ATTRIBUTE_TYPE_FIXED || type==TagLibTag.ATTRIBUTE_TYPE_MIXED)        {
1784                                    Map<String, TagLibTagAttr> hash = tlt.getAttributes();
1785                                    Iterator<String> it = hash.keySet().iterator();
1786                                    
1787                                    while(it.hasNext())     {
1788                                            TagLibTagAttr att=(TagLibTagAttr) hash.get(it.next());
1789                                            if(att.isRequired() && !contains(attrs,att.getName()) && att.getDefaultValue()==null && !att.getName().equals(ignoreAttrReqFor))        {
1790                                                    if(!hasAttributeCollection)throw new TemplateException(data.cfml,"attribute "+att.getName()+" is required for statement "+tlt.getName());
1791                                                    if(tag!=null)tag.addMissingAttribute(att.getName(),att.getType());
1792                                            }
1793                                    }
1794                            }
1795                    }
1796                    return attrs.toArray(new Attribute[attrs.size()]);
1797            }
1798            
1799            private boolean contains(ArrayList<Attribute> attrs, String name) {
1800                    Iterator<Attribute> it = attrs.iterator();
1801                    while(it.hasNext()){
1802                            if(it.next().getName().equals(name)) return true;
1803                    }
1804                    return false;
1805            }
1806    
1807            private Attribute attribute(TagLibTag tlt, Data data, ArrayList<String> args, Expression defaultValue,Object oAllowExpression, boolean allowTwiceAttr) throws TemplateException {
1808                    StringBuffer sbType=new StringBuffer();
1809            RefBoolean dynamic=new RefBooleanImpl(false);
1810            
1811                    // Name
1812            String name=attributeName(data.cfml,args,tlt,dynamic,sbType, allowTwiceAttr);
1813            boolean allowExpression=false;
1814            if(oAllowExpression instanceof Boolean)allowExpression=((Boolean)oAllowExpression).booleanValue();
1815            else if(oAllowExpression instanceof String)allowExpression=((String)oAllowExpression).equalsIgnoreCase(name);
1816            Expression value=null;
1817            
1818            CFMLTransformer.comment(data.cfml,true);
1819            
1820            // value
1821            if(data.cfml.forwardIfCurrent('='))     {
1822                    CFMLTransformer.comment(data.cfml,true);
1823                    value=attributeValue(data,allowExpression);     
1824            }
1825            else {
1826                    value=defaultValue;
1827            }               
1828            CFMLTransformer.comment(data.cfml,true);
1829            
1830            
1831            // Type
1832            TagLibTagAttr tlta=null;
1833                    if(tlt!=null){
1834                            tlta = tlt.getAttribute(name);
1835                    }
1836                    return new Attribute(dynamic.toBooleanValue(),name,tlta!=null?Cast.toExpression(value, tlta.getType()):value,sbType.toString());
1837        }
1838            
1839            /*private String attributeName(CFMLString cfml, ArrayList<String> args,TagLibTag tag, RefBoolean dynamic, StringBuffer sbType) throws TemplateException {
1840                    String id=StringUtil.toLowerCase(CFMLTransformer.identifier(cfml,true));
1841            if(args.contains(id)) throw new TemplateException(cfml,"you can't use the same attribute ["+id+"] twice");
1842                    args.add(id);
1843                    
1844                    
1845                    
1846                    int typeDef=tag.getAttributeType();
1847                    if("attributecollection".equals(id)){
1848                            dynamic.setValue(tag.getAttribute(id)==null);
1849                            sbType.append("struct");
1850                    }
1851                    else if(typeDef==TagLibTag.ATTRIBUTE_TYPE_FIXED || typeDef==TagLibTag.ATTRIBUTE_TYPE_MIXED) {
1852                            TagLibTagAttr attr=tag.getAttribute(id);
1853                            if(attr==null) {
1854                                    if(typeDef==TagLibTag.ATTRIBUTE_TYPE_FIXED) {
1855                                            String names=tag.getAttributeNames();
1856                                            if(StringUtil.isEmpty(names))
1857                                                    throw new TemplateException(cfml,"Attribute "+id+" is not allowed for tag "+tag.getFullName());
1858                                            
1859                                                    throw new TemplateException(cfml,
1860                                                            "Attribute "+id+" is not allowed for statement "+tag.getName(),
1861                                                            "valid attribute names are ["+names+"]");
1862                                    }
1863                            }
1864                            else {
1865                                    sbType.append(attr.getType());
1866                                    //parseExpression[0]=attr.getRtexpr();
1867                            }
1868                    }
1869                    else if(typeDef==TagLibTag.ATTRIBUTE_TYPE_DYNAMIC){
1870                            dynamic.setValue(true);
1871                    }
1872                    return id;
1873            }*/
1874            
1875            private String attributeName(CFMLString cfml, ArrayList<String> args,TagLibTag tag, RefBoolean dynamic, StringBuffer sbType, boolean allowTwiceAttr) throws TemplateException {
1876                    String id=StringUtil.toLowerCase(CFMLTransformer.identifier(cfml,true));
1877                    return validateAttributeName(id, cfml, args, tag, dynamic, sbType,allowTwiceAttr);
1878            }
1879            
1880            
1881            
1882            private String validateAttributeName(String id,CFMLString cfml, ArrayList<String> args,TagLibTag tag, RefBoolean dynamic, StringBuffer sbType, boolean allowTwiceAttr) throws TemplateException {
1883                    if(args.contains(id) && !allowTwiceAttr) throw new TemplateException(cfml,"you can't use the same attribute ["+id+"] twice");
1884                    args.add(id);
1885                    
1886                    
1887                    if(tag==null) return id;
1888                    int typeDef=tag.getAttributeType();
1889                    if("attributecollection".equals(id)){
1890                            dynamic.setValue(tag.getAttribute(id)==null);
1891                            sbType.append("struct");
1892                    }
1893                    else if(typeDef==TagLibTag.ATTRIBUTE_TYPE_FIXED || typeDef==TagLibTag.ATTRIBUTE_TYPE_MIXED) {
1894                            TagLibTagAttr attr=tag.getAttribute(id);
1895                            if(attr==null) {
1896                                    if(typeDef==TagLibTag.ATTRIBUTE_TYPE_FIXED) {
1897                                            String names=tag.getAttributeNames();
1898                                            if(StringUtil.isEmpty(names))
1899                                                    throw new TemplateException(cfml,"Attribute "+id+" is not allowed for tag "+tag.getFullName());
1900                                            
1901                                            throw new TemplateException(cfml,
1902                                                    "Attribute "+id+" is not allowed for statement "+tag.getName(),
1903                                                    "valid attribute names are ["+names+"]");
1904                                    }
1905                                    else dynamic.setValue(true);
1906                                    
1907                            }
1908                            else {
1909                                    sbType.append(attr.getType());
1910                                    //parseExpression[0]=attr.getRtexpr();
1911                            }
1912                    }
1913                    else if(typeDef==TagLibTag.ATTRIBUTE_TYPE_DYNAMIC){
1914                            dynamic.setValue(true);
1915                    }
1916                    return id;
1917            }
1918            
1919                    
1920            private Expression attributeValue(Data data, boolean allowExpression) throws TemplateException {
1921                    return allowExpression?super.expression(data):transformAsString(data,new String[]{" ", ";", "{"});
1922                    //return transformAsString(data);
1923            }
1924            
1925            /*public static Expression attributeValue(Data data,TagLibTag tag, String type,boolean isNonName, Expression noExpression) throws TemplateException {
1926                    Expression expr;
1927                    try {
1928                            
1929                            if(isNonName) {
1930                                int pos=data.cfml.getPos();
1931                                try {
1932                                expr=transfomer.transform(data.ep,data.flibs,data.cfml);
1933                                }
1934                                catch(TemplateException ete) {
1935                                   if(data.cfml.getPos()==pos)expr=noExpression;
1936                                   else throw ete;
1937                                }
1938                            }
1939                            else expr=transfomer.transformAsString(data.ep,data.flibs,data.cfml,true);
1940                            if(type.length()>0) {
1941                                    expr=Cast.toExpression(expr, type);
1942                            }
1943                    } catch (TagLibException e) {
1944                            throw new TemplateException(data.cfml,e);
1945                    } 
1946                    return expr;
1947            }*/
1948            
1949            public static interface EndCondition {
1950                    public boolean isEnd(Data data);
1951            }
1952    }