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 }