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