001 package railo.runtime.interpreter; 002 003 import java.util.ArrayList; 004 import java.util.Map; 005 import java.util.WeakHashMap; 006 007 import org.apache.commons.collections.map.ReferenceMap; 008 009 import railo.commons.lang.CFTypes; 010 import railo.commons.lang.ParserString; 011 import railo.runtime.PageContext; 012 import railo.runtime.config.ConfigImpl; 013 import railo.runtime.exp.ExpressionException; 014 import railo.runtime.exp.PageException; 015 import railo.runtime.interpreter.ref.Ref; 016 import railo.runtime.interpreter.ref.Set; 017 import railo.runtime.interpreter.ref.cast.Casting; 018 import railo.runtime.interpreter.ref.func.BIFCall; 019 import railo.runtime.interpreter.ref.func.UDFCall; 020 import railo.runtime.interpreter.ref.literal.LBoolean; 021 import railo.runtime.interpreter.ref.literal.LFunctionValue; 022 import railo.runtime.interpreter.ref.literal.LNumber; 023 import railo.runtime.interpreter.ref.literal.LString; 024 import railo.runtime.interpreter.ref.literal.LStringBuffer; 025 import railo.runtime.interpreter.ref.literal.Literal; 026 import railo.runtime.interpreter.ref.op.And; 027 import railo.runtime.interpreter.ref.op.BigDiv; 028 import railo.runtime.interpreter.ref.op.BigIntDiv; 029 import railo.runtime.interpreter.ref.op.BigMinus; 030 import railo.runtime.interpreter.ref.op.BigMod; 031 import railo.runtime.interpreter.ref.op.BigMulti; 032 import railo.runtime.interpreter.ref.op.BigPlus; 033 import railo.runtime.interpreter.ref.op.CT; 034 import railo.runtime.interpreter.ref.op.Concat; 035 import railo.runtime.interpreter.ref.op.Cont; 036 import railo.runtime.interpreter.ref.op.Div; 037 import railo.runtime.interpreter.ref.op.EEQ; 038 import railo.runtime.interpreter.ref.op.EQ; 039 import railo.runtime.interpreter.ref.op.EQV; 040 import railo.runtime.interpreter.ref.op.Exp; 041 import railo.runtime.interpreter.ref.op.GT; 042 import railo.runtime.interpreter.ref.op.GTE; 043 import railo.runtime.interpreter.ref.op.Imp; 044 import railo.runtime.interpreter.ref.op.IntDiv; 045 import railo.runtime.interpreter.ref.op.LT; 046 import railo.runtime.interpreter.ref.op.LTE; 047 import railo.runtime.interpreter.ref.op.Minus; 048 import railo.runtime.interpreter.ref.op.Mod; 049 import railo.runtime.interpreter.ref.op.Multi; 050 import railo.runtime.interpreter.ref.op.NCT; 051 import railo.runtime.interpreter.ref.op.NEEQ; 052 import railo.runtime.interpreter.ref.op.NEQ; 053 import railo.runtime.interpreter.ref.op.Negate; 054 import railo.runtime.interpreter.ref.op.Not; 055 import railo.runtime.interpreter.ref.op.Or; 056 import railo.runtime.interpreter.ref.op.Plus; 057 import railo.runtime.interpreter.ref.op.Xor; 058 import railo.runtime.interpreter.ref.var.Assign; 059 import railo.runtime.interpreter.ref.var.Bind; 060 import railo.runtime.interpreter.ref.var.DynAssign; 061 import railo.runtime.interpreter.ref.var.Variable; 062 import railo.runtime.type.Scope; 063 import railo.runtime.type.scope.ScopeSupport; 064 import railo.transformer.library.function.FunctionLib; 065 import railo.transformer.library.function.FunctionLibFunction; 066 import railo.transformer.library.function.FunctionLibFunctionArg; 067 068 /** 069 * 070 * 071 Der CFMLExprTransfomer implementiert das Interface ExprTransfomer, 072 er bildet die Parser Grammatik ab, die unten definiert ist. 073 Er erh¦lt als Eingabe CFML Code, als String oder CFMLString, 074 der einen CFML Expression erh¦lt und liefert ein CFXD Element zurck, 075 das diesen Ausdruck abbildet. 076 Mithilfe der FunctionLibメs, kann er Funktionsaufrufe, 077 die Teil eines Ausdruck sein knnen, erkennen und validieren. 078 Dies geschieht innerhalb der Methode function. 079 Falls ein Funktionsaufruf, einer Funktion innerhalb einer FunctionLib entspricht, 080 werden diese gegeneinander verglichen und der Aufruf wird als Build-In-Funktion bernommen, 081 andernfalls wird der Funktionsaufruf als User-Defined-Funktion interpretiert. 082 Die Klasse Cast, Operator und ElementFactory (siehe 3.2) helfen ihm beim erstellen des Ausgabedokument CFXD. 083 084 * <pre> 085 * Parser Grammatik EBNF (Extended Backus-Naur Form) 086 087 transform = spaces impOp; 088 impOp = eqvOp {"imp" spaces eqvOp}; 089 eqvOp = xorOp {"eqv" spaces xorOp}; 090 xorOp = orOp {"xor" spaces orOp}; 091 orOp = andOp {("or" | "||") spaces andOp}; 092 (* "||" Existiert in CFMX nicht *) 093 andOp = notOp {("and" | "&&") spaces notOp}; 094 (* "&&" Existiert in CFMX nicht *) 095 notOp = [("not"|"!") spaces] decsionOp; 096 (* "!" Existiert in CFMX nicht *) 097 decsionOp = concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"| 098 "contains"|"nct"|"does not contain") spaces concatOp}; 099 (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *) 100 concatOp = plusMinusOp {"&" spaces plusMinusOp}; 101 plusMinusOp = modOp {("-"|"+") spaces modOp}; 102 103 modOp = divMultiOp {("mod" | "%") spaces divMultiOp}; 104 (* modulus operator , "%" Existiert in CFMX nicht *) 105 divMultiOp = expoOp {("*"|"/") spaces expoOp}; 106 expoOp = clip {("exp"|"^") spaces clip}; 107 (*exponent operator, " exp " Existiert in CFMX nicht *) 108 clip = ("(" spaces impOp ")" spaces) | checker; 109 checker = string | number | dynamic | sharp; 110 string = ("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") | 111 (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """); 112 number = ["+"|"-"] digit {digit} {"." digit {digit}}; 113 digit = "0"|..|"9"; 114 dynamic = "true" | "false" | "yes" | "no" | startElement 115 {("." identifier | "[" structElement "]")[function] }; 116 startElement = identifier "(" functionArg ")" | scope | identifier; 117 scope = "variable" | "cgi" | "url" | "form" | "session" | "application" | 118 "arguments" | "cookie" | " client"; 119 identifier = (letter | "_") {letter | "_"|digit}; 120 structElement = "[" impOp "]"; 121 functionArg = [impOp{"," impOp}]; 122 sharp = "#" checker "#"; 123 spaces = {space}; 124 space = "\s"|"\t"|"\f"|"\t"|"\n"; 125 letter = "a"|..|"z"|"A"|..|"Z"; 126 127 {"x"}= 0 bis n mal "x" 128 ["x"]= 0 bis 1 mal "x" 129 ("x" | "y")"z" = "xz" oder "yz" 130 131 </pre> 132 * 133 */ 134 public class CFMLExpressionInterpreter { 135 136 137 private static final LNumber PLUS_ONE = new LNumber(new Double(1)); 138 private static final LNumber MINUS_ONE = new LNumber(new Double(-1)); 139 140 protected static final short STATIC=0; 141 private static final short DYNAMIC=1; 142 private static FunctionLibFunction JSON_ARRAY = null; 143 private static FunctionLibFunction JSON_STRUCT = null; 144 145 146 //private static final int CASE_TYPE_UPPER = 0; 147 //private static final int CASE_TYPE_LOWER = 1; 148 //private static final int CASE_TYPE_ORIGINAL = 2; 149 150 protected short mode=0; 151 152 protected ParserString cfml; 153 //protected Document doc; 154 //protected FunctionLib[] fld; 155 protected PageContext pc; 156 private FunctionLib fld; 157 protected boolean allowNullConstant=false; 158 private boolean preciseMath; 159 160 private final static Map<String,Ref> data=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT); 161 162 163 164 public Object interpret(PageContext pc,String str) throws PageException { 165 return interpret(pc,str,false); 166 } 167 168 169 public Object interpret(PageContext pc,String str, boolean preciseMath) throws PageException { 170 //Ref ref = data.get(str+":"+preciseMath); 171 //if(ref!=null)return ref.getValue(); 172 173 this.cfml=new ParserString(str); 174 this.preciseMath = preciseMath; 175 this.pc=pc; 176 if(pc!=null)fld=((ConfigImpl)pc.getConfig()).getCombinedFLDs(); 177 178 if(JSON_ARRAY==null)JSON_ARRAY=fld.getFunction("_jsonArray"); 179 if(JSON_STRUCT==null)JSON_STRUCT=fld.getFunction("_jsonStruct"); 180 181 cfml.removeSpace(); 182 Ref ref = assignOp(); 183 cfml.removeSpace(); 184 185 if(cfml.isAfterLast()) { 186 //data.put(str+":"+preciseMath,ref); 187 return ref.getValue(); 188 } 189 throw new ExpressionException("Syntax Error, invalid Expression ["+cfml.toString()+"]"); 190 } 191 192 193 /*private FunctionLibFunction getFLF(String name) { 194 FunctionLibFunction flf=null; 195 for (int i = 0; i < flds.length; i++) { 196 flf = flds[i].getFunction(name); 197 if (flf != null) 198 break; 199 } 200 return flf; 201 }*/ 202 203 204 protected Object interpretPart(PageContext pc,ParserString cfml) throws PageException { 205 this.cfml = cfml; 206 this.pc=pc; 207 if(pc!=null)fld=((ConfigImpl)pc.getConfig()).getCombinedFLDs(); 208 209 cfml.removeSpace(); 210 return assignOp().getValue(); 211 } 212 213 /** 214 * Liest einen gelableten Funktionsparamter ein 215 * <br /> 216 * EBNF:<br /> 217 * <code>assignOp [":" spaces assignOp];</code> 218 * @return CFXD Element 219 * @throws PageException 220 */ 221 private Ref functionArgDeclarationVarString() throws PageException { 222 223 cfml.removeSpace(); 224 StringBuffer str=new StringBuffer(); 225 String id=null; 226 while((id=identifier(false))!=null) { 227 if(str.length()>0)str.append('.'); 228 str.append(id); 229 cfml.removeSpace(); 230 if(!cfml.forwardIfCurrent('.')) break; 231 cfml.removeSpace(); 232 } 233 cfml.removeSpace(); 234 if(str.length()>0 && cfml.charAt(cfml.getPos()-1)!='.') 235 return new LString(str.toString()); 236 237 throw new ExpressionException("invalid variable name definition"); 238 } 239 240 /** 241 * Liest einen gelableten Funktionsparamter ein 242 * <br /> 243 * EBNF:<br /> 244 * <code>assignOp [":" spaces assignOp];</code> 245 * @return CFXD Element 246 * @throws PageException 247 */ 248 private Ref functionArgDeclaration() throws PageException { 249 Ref ref = impOp(); 250 if (cfml.forwardIfCurrent(':') || cfml.forwardIfCurrent('=')) { 251 cfml.removeSpace(); 252 ref=new LFunctionValue(ref,assignOp()); 253 } 254 return ref; 255 } 256 257 /** 258 * Transfomiert Zuweisungs Operation. 259 * <br /> 260 * EBNF:<br /> 261 * <code>eqvOp ["=" spaces assignOp];</code> 262 * @return CFXD Element 263 * @throws PageException 264 */ 265 protected Ref assignOp() throws PageException { 266 Ref ref = contOp(); 267 268 if (cfml.forwardIfCurrent('=')) { 269 cfml.removeSpace(); 270 if(mode==STATIC || ref instanceof Literal) { 271 ref=new DynAssign(pc,ref,assignOp()); 272 } 273 else { 274 ref=new Assign(ref,assignOp()); 275 } 276 } 277 return ref; 278 } 279 280 281 private Ref contOp() throws PageException { 282 Ref ref = impOp(); 283 while(cfml.forwardIfCurrent('?')) { 284 cfml.removeSpace(); 285 Ref left = assignOp(); 286 if(!cfml.forwardIfCurrent(':')) 287 throw new ExpressionException("Syntax Error, invalid conditional operator ["+cfml.toString()+"]"); 288 cfml.removeSpace(); 289 Ref right = assignOp(); 290 ref=new Cont(ref,left,right); 291 } 292 return ref; 293 } 294 295 /** 296 * Transfomiert eine Implication (imp) Operation. 297 * <br /> 298 * EBNF:<br /> 299 * <code>eqvOp {"imp" spaces eqvOp};</code> 300 * @return CFXD Element 301 * @throws PageException 302 */ 303 private Ref impOp() throws PageException { 304 Ref ref = eqvOp(); 305 while(cfml.forwardIfCurrentAndNoWordAfter("imp")) { 306 cfml.removeSpace(); 307 ref=new Imp(ref,eqvOp()); 308 } 309 return ref; 310 } 311 312 /** 313 * Transfomiert eine Equivalence (eqv) Operation. 314 * <br /> 315 * EBNF:<br /> 316 * <code>xorOp {"eqv" spaces xorOp};</code> 317 * @return CFXD Element 318 * @throws PageException 319 */ 320 private Ref eqvOp() throws PageException { 321 Ref ref = xorOp(); 322 while(cfml.forwardIfCurrent("eqv")) { 323 cfml.removeSpace(); 324 ref=new EQV(ref,xorOp()); 325 } 326 return ref; 327 } 328 329 /** 330 * Transfomiert eine Xor (xor) Operation. 331 * <br /> 332 * EBNF:<br /> 333 * <code>orOp {"xor" spaces orOp};</code> 334 * @return CFXD Element 335 * @throws PageException 336 */ 337 private Ref xorOp() throws PageException { 338 Ref ref = orOp(); 339 while(cfml.forwardIfCurrent("xor")) { 340 cfml.removeSpace(); 341 ref=new Xor(ref,orOp()); 342 } 343 return ref; 344 } 345 346 /** 347 * Transfomiert eine Or (or) Operation. Im Gegensatz zu CFMX , 348 * werden "||" Zeichen auch als Or Operatoren anerkannt. 349 * <br /> 350 * EBNF:<br /> 351 * <code>andOp {("or" | "||") spaces andOp}; (* "||" Existiert in CFMX nicht *)</code> 352 * @return CFXD Element 353 * @throws PageException 354 */ 355 private Ref orOp() throws PageException { 356 Ref ref = andOp(); 357 while(cfml.isValidIndex() && (cfml.forwardIfCurrent("||") || cfml.forwardIfCurrent("or"))) { 358 cfml.removeSpace(); 359 ref=new Or(ref,andOp()); 360 } 361 return ref; 362 } 363 364 /** 365 * Transfomiert eine And (and) Operation. Im Gegensatz zu CFMX , 366 * werden "&&" Zeichen auch als And Operatoren anerkannt. 367 * <br /> 368 * EBNF:<br /> 369 * <code>notOp {("and" | "&&") spaces notOp}; (* "&&" Existiert in CFMX nicht *)</code> 370 * @return CFXD Element 371 * @throws PageException 372 */ 373 private Ref andOp() throws PageException { 374 Ref ref = notOp(); 375 while(cfml.isValidIndex() && (cfml.forwardIfCurrent("&&") || cfml.forwardIfCurrent("and"))) { 376 cfml.removeSpace(); 377 ref=new And(ref,notOp()); 378 } 379 return ref; 380 } 381 382 /** 383 * Transfomiert eine Not (not) Operation. Im Gegensatz zu CFMX , 384 * wird das "!" Zeichen auch als Not Operator anerkannt. 385 * <br /> 386 * EBNF:<br /> 387 * <code>[("not"|"!") spaces] decsionOp; (* "!" Existiert in CFMX nicht *)</code> 388 * @return CFXD Element 389 * @throws PageException 390 */ 391 private Ref notOp() throws PageException { 392 if(cfml.isValidIndex()) { 393 if (cfml.isCurrent('!') && !cfml.isCurrent("!=")) { 394 cfml.next(); 395 cfml.removeSpace(); 396 return new Not(decsionOp()); 397 } 398 else if (cfml.forwardIfCurrentAndNoWordAfter("not")) { 399 cfml.removeSpace(); 400 return new Not(decsionOp()); 401 } 402 } 403 return decsionOp(); 404 } 405 406 /** 407 * <font f>Transfomiert eine Vergleichs Operation. 408 * <br /> 409 * EBNF:<br /> 410 * <code>concatOp {("neq"|"eq"|"gte"|"gt"|"lte"|"lt"|"ct"| 411 "contains"|"nct"|"does not contain") spaces concatOp}; 412 (* "ct"=conatains und "nct"=does not contain; Existiert in CFMX nicht *)</code> 413 * @return CFXD Element 414 * @throws PageException 415 */ 416 private Ref decsionOp() throws PageException { 417 418 Ref ref = concatOp(); 419 boolean hasChanged=false; 420 // ct, contains 421 if(cfml.isValidIndex()){ 422 do { 423 hasChanged=false; 424 if(cfml.isCurrent('c')) { 425 if (cfml.forwardIfCurrent("ct")) { 426 cfml.removeSpace(); 427 ref=new CT(ref,concatOp()); 428 hasChanged=true; 429 } 430 else if (cfml.forwardIfCurrent("contains")){ 431 cfml.removeSpace(); 432 ref=new CT(ref,concatOp()); 433 hasChanged=true; 434 } 435 } 436 // does not contain 437 else if (cfml.forwardIfCurrent("does","not","contain")){ 438 cfml.removeSpace(); 439 ref=new NCT(ref,concatOp()); 440 hasChanged=true; 441 } 442 443 // equal, eq 444 else if (cfml.isCurrent("eq") && !cfml.isCurrent("eqv")) { 445 cfml.setPos(cfml.getPos()+2); 446 cfml.forwardIfCurrent("ual"); 447 cfml.removeSpace(); 448 ref=new EQ(ref,concatOp()); 449 hasChanged=true; 450 } 451 // == 452 else if (cfml.forwardIfCurrent("==")) { 453 if(cfml.forwardIfCurrent('=')) { 454 cfml.removeSpace(); 455 ref = new EEQ(ref,concatOp()); 456 } 457 else { 458 cfml.removeSpace(); 459 ref=new EQ(ref,concatOp()); 460 } 461 hasChanged=true; 462 } 463 464 // != 465 else if (cfml.forwardIfCurrent("!=")) { 466 if(cfml.forwardIfCurrent('=')) { 467 cfml.removeSpace(); 468 ref = new NEEQ(ref,concatOp()); 469 } 470 else { 471 cfml.removeSpace(); 472 ref=new NEQ(ref,concatOp()); 473 } 474 hasChanged=true; 475 } 476 477 // <=/</<> 478 else if (cfml.forwardIfCurrent('<')) { 479 if(cfml.forwardIfCurrent('=')) { 480 cfml.removeSpace(); 481 ref = new LTE(ref,concatOp()); 482 } 483 else if(cfml.forwardIfCurrent('>')) { 484 cfml.removeSpace(); 485 ref = new NEQ(ref,concatOp()); 486 } 487 else { 488 cfml.removeSpace(); 489 ref = new LT(ref,concatOp()); 490 } 491 hasChanged=true; 492 } 493 // >/>= 494 else if (cfml.forwardIfCurrent('>')) { 495 if(cfml.forwardIfCurrent('=')) { 496 cfml.removeSpace(); 497 ref = new GTE(ref,concatOp()); 498 } 499 else { 500 cfml.removeSpace(); 501 ref = new GT(ref,concatOp()); 502 } 503 hasChanged=true; 504 } 505 506 // gt, gte, greater than or equal to, greater than 507 else if (cfml.isCurrent('g')) { 508 if (cfml.forwardIfCurrent("gt")) { 509 if(cfml.forwardIfCurrent('e')) { 510 cfml.removeSpace(); 511 ref=new GTE(ref,concatOp()); 512 } 513 else { 514 cfml.removeSpace(); 515 ref=new GT(ref,concatOp()); 516 } 517 hasChanged=true; 518 } 519 else if (cfml.forwardIfCurrent("greater","than")) { 520 if(cfml.forwardIfCurrent("or" ,"equal", "to",true)) { 521 cfml.removeSpace(); 522 ref=new GTE(ref,concatOp()); 523 } 524 else { 525 cfml.removeSpace(); 526 ref=new GT(ref,concatOp()); 527 } 528 hasChanged=true; 529 } 530 else if (cfml.forwardIfCurrent("ge")) { 531 cfml.removeSpace(); 532 ref=new GTE(ref,concatOp()); 533 hasChanged=true; 534 } 535 } 536 537 // is, is not 538 else if (cfml.forwardIfCurrent("is")) { 539 if(cfml.forwardIfCurrent("not",true)) { 540 cfml.removeSpace(); 541 ref=new NEQ(ref,concatOp()); 542 } 543 else { 544 cfml.removeSpace(); 545 ref=new EQ(ref,concatOp()); 546 } 547 hasChanged=true; 548 } 549 550 // lt, lte, less than, less than or equal to 551 else if (cfml.isCurrent('l')) { 552 if (cfml.forwardIfCurrent("lt")) { 553 if(cfml.forwardIfCurrent('e')) { 554 cfml.removeSpace(); 555 ref=new LTE(ref,concatOp()); 556 } 557 else { 558 cfml.removeSpace(); 559 ref=new LT(ref,concatOp()); 560 } 561 hasChanged=true; 562 } 563 else if (cfml.forwardIfCurrent("less","than")) { 564 if(cfml.forwardIfCurrent("or", "equal", "to",true)) { 565 cfml.removeSpace(); 566 ref=new LTE(ref,concatOp()); 567 } 568 else { 569 cfml.removeSpace(); 570 ref=new LT(ref,concatOp()); 571 } 572 hasChanged=true; 573 } 574 else if (cfml.forwardIfCurrent("le")) { 575 cfml.removeSpace(); 576 ref=new LTE(ref,concatOp()); 577 hasChanged=true; 578 } 579 } 580 581 // neq, not equal, nct 582 else if (cfml.isCurrent('n')) { 583 // Not Equal 584 if (cfml.forwardIfCurrent("neq")) { 585 cfml.removeSpace(); 586 ref=new NEQ(ref,concatOp()); 587 hasChanged=true; 588 } 589 // Not Equal (Alias) 590 else if (cfml.forwardIfCurrent("not","equal")){ 591 cfml.removeSpace(); 592 ref=new NEQ(ref,concatOp()); 593 hasChanged=true; 594 } 595 // nct 596 else if (cfml.forwardIfCurrent("nct")) { 597 cfml.removeSpace(); 598 ref=new NCT(ref,concatOp()); 599 hasChanged=true; 600 } 601 } 602 }while(hasChanged); 603 } 604 return ref; 605 } 606 607 /** 608 * Transfomiert eine Konkatinations-Operator (&) Operation. Im Gegensatz zu CFMX , 609 * wird das "!" Zeichen auch als Not Operator anerkannt. 610 * <br /> 611 * EBNF:<br /> 612 * <code>plusMinusOp {"&" spaces concatOp};</code> 613 * @return CFXD Element 614 * @throws PageException 615 */ 616 private Ref concatOp() throws PageException { 617 Ref ref = plusMinusOp(); 618 619 while(cfml.isCurrent('&') && !cfml.isNext('&')) { 620 cfml.next(); 621 ref=_concat(ref); 622 //cfml.removeSpace(); 623 //ref=new Concat(pc,ref,plusMinusOp()); 624 } 625 return ref; 626 } 627 628 /** 629 * Transfomiert die mathematischen Operatoren Plus und Minus (1,-). 630 * <br /> 631 * EBNF:<br /> 632 * <code>modOp [("-"|"+") spaces plusMinusOp];</code> 633 * @return CFXD Element 634 * @throws PageException 635 */ 636 private Ref plusMinusOp() throws PageException { 637 Ref ref = modOp(); 638 639 while(!cfml.isLast()) { 640 // Plus Operation 641 if (cfml.forwardIfCurrent('+')) { 642 ref=_plus(ref); 643 //cfml.removeSpace(); 644 //ref=new Plus(ref,modOp()); 645 } 646 // Minus Operation 647 else if (cfml.forwardIfCurrent('-')) { 648 ref=_minus(ref); 649 //cfml.removeSpace(); 650 //ref=new Minus(ref,modOp()); 651 } 652 else break; 653 } 654 return ref; 655 } 656 657 private Ref _plus(Ref ref) throws PageException { 658 // += 659 if (cfml.isCurrent('=')) { 660 cfml.next(); 661 cfml.removeSpace(); 662 Ref right = assignOp(); 663 Ref res = preciseMath?new BigPlus(ref,right):new Plus(ref,right); 664 ref=new Assign(ref,res); 665 } 666 /*/ ++ 667 else if (cfml.isCurrent('+')) { 668 cfml.next(); 669 cfml.removeSpace(); 670 Ref res = new Plus(ref,new LNumber(new Double(1))); 671 ref=new Assign(ref,res); 672 ref=new Minus(ref,new LNumber(new Double(1))); 673 }*/ 674 else { 675 cfml.removeSpace(); 676 ref=preciseMath?new BigPlus(ref,modOp()):new Plus(ref,modOp()); 677 } 678 return ref; 679 } 680 681 private Ref _minus(Ref ref) throws PageException { 682 // -= 683 if (cfml.isCurrent('=')) { 684 cfml.next(); 685 cfml.removeSpace(); 686 Ref right = assignOp(); 687 Ref res = preciseMath?new BigMinus(ref,right):new Minus(ref,right); 688 ref=new Assign(ref,res); 689 } 690 /*/ -- 691 else if (cfml.isCurrent('-')) { 692 cfml.next(); 693 cfml.removeSpace(); 694 Ref res = new Minus(ref,new LNumber(new Double(1))); 695 ref=new Assign(ref,res); 696 ref=new Plus(ref,new LNumber(new Double(1))); 697 }*/ 698 else { 699 cfml.removeSpace(); 700 ref=preciseMath?new BigMinus(ref,modOp()):new Minus(ref,modOp()); 701 } 702 return ref; 703 } 704 705 706 private Ref _div(Ref ref) throws PageException { 707 // /= 708 if (cfml.forwardIfCurrent('=')) { 709 cfml.removeSpace(); 710 Ref right = assignOp(); 711 Ref res = preciseMath?new BigDiv(ref, right):new Div(ref,right); 712 ref=new Assign(ref,res); 713 } 714 else { 715 cfml.removeSpace(); 716 ref=preciseMath?new BigDiv(ref,expoOp()):new Div(ref,expoOp()); 717 } 718 return ref; 719 } 720 721 private Ref _intdiv(Ref ref) throws PageException { 722 // \= 723 if (cfml.forwardIfCurrent('=')) { 724 cfml.removeSpace(); 725 Ref right = assignOp(); 726 Ref res = preciseMath?new BigIntDiv(ref,right):new IntDiv(ref,right); 727 ref=new Assign(ref,res); 728 } 729 else { 730 cfml.removeSpace(); 731 ref=preciseMath?new BigIntDiv(ref,expoOp()):new IntDiv(ref,expoOp()); 732 } 733 return ref; 734 } 735 736 private Ref _mod(Ref ref) throws PageException { 737 // %= 738 if (cfml.forwardIfCurrent('=')) { 739 cfml.removeSpace(); 740 Ref right = assignOp(); 741 Ref res = preciseMath?new BigMod(ref,right):new Mod(ref,right); 742 ref=new Assign(ref,res); 743 } 744 else { 745 cfml.removeSpace(); 746 ref=preciseMath?new BigMod(ref,divMultiOp()):new Mod(ref,divMultiOp()); 747 } 748 return ref; 749 } 750 private Ref _concat(Ref ref) throws PageException { 751 // &= 752 if (cfml.forwardIfCurrent('=')) { 753 cfml.removeSpace(); 754 Ref right = assignOp(); 755 Ref res = new Concat(pc,ref,right); 756 ref=new Assign(ref,res); 757 } 758 else { 759 cfml.removeSpace(); 760 ref=new Concat(pc,ref,plusMinusOp()); 761 } 762 return ref; 763 } 764 765 private Ref _multi(Ref ref) throws PageException { 766 // \= 767 if (cfml.forwardIfCurrent('=')) { 768 cfml.removeSpace(); 769 Ref right = assignOp(); 770 Ref res = preciseMath?new BigMulti(ref,right):new Multi(ref,right); 771 ref=new Assign(ref,res); 772 } 773 else { 774 cfml.removeSpace(); 775 ref=preciseMath?new BigMulti(ref,expoOp()):new Multi(ref,expoOp()); 776 } 777 return ref; 778 } 779 780 781 782 783 784 /** 785 * Transfomiert eine Modulus Operation. Im Gegensatz zu CFMX , 786 * wird das "%" Zeichen auch als Modulus Operator anerkannt. 787 * <br /> 788 * EBNF:<br /> 789 * <code>divMultiOp {("mod" | "%") spaces divMultiOp}; (* modulus operator , "%" Existiert in CFMX nicht *)</code> 790 * @return CFXD Element 791 * @throws PageException 792 */ 793 private Ref modOp() throws PageException { 794 Ref ref = divMultiOp(); 795 796 while(cfml.isValidIndex() && (cfml.forwardIfCurrent('%') || cfml.forwardIfCurrent("mod"))) { 797 ref=_mod(ref); 798 799 //cfml.removeSpace(); 800 //ref=new Mod(ref,divMultiOp()); 801 } 802 return ref; 803 } 804 805 /** 806 * Transfomiert die mathematischen Operatoren Mal und Durch (*,/). 807 * <br /> 808 * EBNF:<br /> 809 * <code>expoOp {("*"|"/") spaces expoOp};</code> 810 * @return CFXD Element 811 * @throws PageException 812 */ 813 private Ref divMultiOp() throws PageException { 814 Ref ref = expoOp(); 815 816 while (!cfml.isLast()) { 817 // Multiply Operation 818 if(cfml.forwardIfCurrent('*')) { 819 ref=_multi(ref); 820 //cfml.removeSpace(); 821 //ref=new Multi(ref,expoOp()); 822 } 823 // Divide Operation 824 else if (cfml.isCurrent('/') && (!cfml.isCurrent("/>") )) { 825 cfml.next(); 826 ref=_div(ref); 827 //cfml.removeSpace(); 828 //ref=new Div(ref,expoOp()); 829 } 830 // Divide Operation 831 else if (cfml.isCurrent('\\')) { 832 cfml.next(); 833 ref=_intdiv(ref); 834 //cfml.removeSpace(); 835 //ref=new IntDiv(ref,expoOp()); 836 } 837 else { 838 break; 839 } 840 } 841 return ref; 842 } 843 844 /** 845 * Transfomiert den Exponent Operator (^,exp). Im Gegensatz zu CFMX , 846 * werden die Zeichen " exp " auch als Exponent anerkannt. 847 * <br /> 848 * EBNF:<br /> 849 * <code>clip {("exp"|"^") spaces clip};</code> 850 * @return CFXD Element 851 * @throws PageException 852 */ 853 private Ref expoOp() throws PageException { 854 Ref ref = unaryOp(); 855 856 while(cfml.isValidIndex() && (cfml.forwardIfCurrent('^') || cfml.forwardIfCurrent("exp"))) { 857 cfml.removeSpace(); 858 ref=new Exp(ref,unaryOp()); 859 } 860 return ref; 861 } 862 863 864 private Ref unaryOp() throws PageException { 865 Ref ref = negateMinusOp(); 866 867 if (cfml.forwardIfCurrent("--")) 868 ref=_unaryOp(ref, false); 869 870 else if (cfml.forwardIfCurrent("++")) 871 ref=_unaryOp(ref, true); 872 return ref; 873 } 874 875 private Ref _unaryOp(Ref ref,boolean isPlus) throws PageException { 876 cfml.removeSpace(); 877 Ref res = preciseMath?new BigPlus(ref,isPlus?PLUS_ONE:MINUS_ONE):new Plus(ref,isPlus?PLUS_ONE:MINUS_ONE); 878 ref=new Assign(ref,res); 879 return preciseMath?new BigPlus(ref,isPlus?MINUS_ONE:PLUS_ONE):new Plus(ref,isPlus?MINUS_ONE:PLUS_ONE); 880 } 881 882 883 /** 884 * Liest die Vordlobe einer Zahl ein 885 * @return CFXD Element 886 * @throws PageException 887 */ 888 private Ref negateMinusOp() throws PageException { 889 // And Operation 890 if (cfml.forwardIfCurrent('-')) { 891 if (cfml.forwardIfCurrent('-')) { 892 cfml.removeSpace(); 893 Ref expr = clip(); 894 Ref res = preciseMath?new BigMinus(expr,new LNumber(new Double(1))):new Minus(expr,new LNumber(new Double(1))); 895 return new Assign(expr,res); 896 } 897 cfml.removeSpace(); 898 return new Negate(clip()); 899 900 } 901 if (cfml.forwardIfCurrent('+')) { 902 if (cfml.forwardIfCurrent('+')) { 903 cfml.removeSpace(); 904 Ref expr = clip(); 905 Ref res = preciseMath?new BigPlus(expr,new LNumber(new Double(1))):new Plus(expr,new LNumber(new Double(1))); 906 return new Assign(expr,res); 907 } 908 cfml.removeSpace(); 909 return new Casting(pc,"numeric",CFTypes.TYPE_NUMERIC,clip()); 910 911 } 912 return clip(); 913 } 914 915 /** 916 * Verarbeitet Ausdrcke die inerhalb einer Klammer stehen. 917 * <br /> 918 * EBNF:<br /> 919 * <code>("(" spaces impOp ")" spaces) | checker;</code> 920 * @return CFXD Element 921 * @throws PageException 922 */ 923 private Ref clip() throws PageException { 924 return checker(); 925 } 926 927 /** 928 * Hier werden die verschiedenen Mglichen Werte erkannt 929 * und jenachdem wird mit der passenden Methode weitergefahren 930 * <br /> 931 * EBNF:<br /> 932 * <code>string | number | dynamic | sharp;</code> 933 * @return CFXD Element 934 * @throws PageException 935 */ 936 private Ref checker() throws PageException { 937 938 Ref ref=null; 939 // String 940 if(cfml.isCurrentQuoter()) { 941 // mode=STATIC; is at the end of the string function because must set after execution 942 return string(); 943 } 944 // Number 945 if(cfml.isCurrentDigit() || cfml.isCurrent('.')) { 946 // mode=STATIC; is at the end of the string function because must set after execution 947 return number(); 948 } 949 // Dynamic 950 if((ref=dynamic())!=null) { 951 mode=DYNAMIC; 952 return ref; 953 } 954 // Sharp 955 if((ref=sharp())!=null) { 956 mode=DYNAMIC; 957 return ref; 958 } 959 // JSON 960 if((ref=json(JSON_ARRAY,'[',']'))!=null) { 961 mode=DYNAMIC; 962 return ref; 963 } 964 if((ref=json(JSON_STRUCT,'{','}'))!=null) { 965 mode=DYNAMIC; 966 return ref; 967 } 968 969 if(cfml.isAfterLast() && cfml.toString().trim().length()==0) 970 return new LString(""); 971 972 // else Error 973 throw new ExpressionException("Syntax Error, Invalid Construct","at position "+cfml.getPos()+" in ["+cfml.toString()+"]"); 974 } 975 976 977 protected Ref json(FunctionLibFunction flf, char start, char end) throws PageException { 978 //print.out("start:"+start+":"+cfml.getCurrent()); 979 if(!cfml.isCurrent(start))return null; 980 981 Ref[] args = functionArg(flf.getName(), false, flf,end); 982 983 //if (!cfml.forwardIfCurrent(end)) 984 // throw new ExpressionException("Invalid Syntax Closing ["+end+"] not found"); 985 986 return new BIFCall(pc,flf,args); 987 } 988 989 /** 990 * Transfomiert einen lierale Zeichenkette. 991 * <br /> 992 * EBNF:<br /> 993 * <code>("'" {"##"|"''"|"#" impOp "#"| ?-"#"-"'" } "'") | 994 (""" {"##"|""""|"#" impOp "#"| ?-"#"-""" } """);</code> 995 * @return CFXD Element 996 * @throws PageException 997 */ 998 protected Ref string() throws PageException { 999 1000 // Init Parameter 1001 char quoter = cfml.getCurrentLower(); 1002 //String str=""; 1003 LStringBuffer str=new LStringBuffer(); 1004 Ref value=null; 1005 1006 while(cfml.hasNext()) { 1007 cfml.next(); 1008 // check sharp 1009 if(cfml.isCurrent('#')) { 1010 if(cfml.isNext('#')){ 1011 cfml.next(); 1012 str.append('#'); 1013 } 1014 else { 1015 cfml.next(); 1016 cfml.removeSpace(); 1017 if(!str.isEmpty() || value!=null) str.append(assignOp()); 1018 else value=assignOp(); 1019 cfml.removeSpace(); 1020 if (!cfml.isCurrent('#')) throw new ExpressionException("Invalid Syntax Closing [#] not found"); 1021 } 1022 } 1023 else if(cfml.isCurrent(quoter)) { 1024 if(cfml.isNext(quoter)){ 1025 cfml.next(); 1026 str.append(quoter); 1027 } 1028 else { 1029 break; 1030 } 1031 } 1032 // all other character 1033 else { 1034 str.append(cfml.getCurrent()); 1035 } 1036 } 1037 if(!cfml.forwardIfCurrent(quoter)) 1038 throw new ExpressionException("Invalid String Literal Syntax Closing ["+quoter+"] not found"); 1039 1040 cfml.removeSpace(); 1041 mode=STATIC; 1042 if(value!=null) { 1043 if(str.isEmpty()) return value; 1044 return new Concat(pc,value,str); 1045 } 1046 return str; 1047 } 1048 1049 /** 1050 * Transfomiert einen numerische Wert. 1051 * Die L¦nge des numerischen Wertes interessiert nicht zu ᅵbersetzungszeit, 1052 * ein "Overflow" fhrt zu einem Laufzeitfehler. 1053 * Da die zu erstellende CFXD, bzw. dieser Transfomer, keine Vorwegnahme des Laufzeitsystems vornimmt. 1054 * <br /> 1055 * EBNF:<br /> 1056 * <code>["+"|"-"] digit {digit} {"." digit {digit}};</code> 1057 * @return CFXD Element 1058 * @throws PageException 1059 */ 1060 private Ref number() throws PageException { 1061 // check first character is a number literal representation 1062 //if(!cfml.isCurrentDigit()) return null; 1063 1064 StringBuilder rtn=new StringBuilder(6); 1065 1066 // get digit on the left site of the dot 1067 if(cfml.isCurrent('.')) rtn.append('0'); 1068 else digit(rtn); 1069 // read dot if exist 1070 if(cfml.forwardIfCurrent('.')) { 1071 rtn.append('.'); 1072 int before=cfml.getPos(); 1073 digit(rtn); 1074 1075 if(before<cfml.getPos() && cfml.forwardIfCurrent('e')) { 1076 Boolean expOp=null; 1077 if(cfml.forwardIfCurrent('+')) expOp=Boolean.TRUE; 1078 else if(cfml.forwardIfCurrent('-')) expOp=Boolean.FALSE; 1079 1080 1081 if(cfml.isCurrentDigit()) { 1082 if(expOp==Boolean.FALSE) rtn.append("e-"); 1083 else if(expOp==Boolean.TRUE) rtn.append("e+"); 1084 else rtn.append('e'); 1085 digit(rtn); 1086 } 1087 else { 1088 if(expOp!=null) cfml.previous(); 1089 cfml.previous(); 1090 } 1091 } 1092 1093 1094 // read right side of the dot 1095 if(before==cfml.getPos()) 1096 throw new ExpressionException("Number can't end with [.]"); 1097 //rtn.append(rightSite); 1098 } 1099 cfml.removeSpace(); 1100 mode=STATIC; 1101 return new LNumber(rtn.toString()); 1102 1103 } 1104 1105 /** 1106 * Liest die reinen Zahlen innerhalb des CFMLString aus und gibt diese als Zeichenkette zurck. 1107 * <br /> 1108 * EBNF:<br /> 1109 * <code>"0"|..|"9";</code> 1110 * @param rtn 1111 */ 1112 private void digit(StringBuilder rtn) { 1113 1114 while (cfml.isValidIndex()) { 1115 if(!cfml.isCurrentDigit())break; 1116 rtn.append(cfml.getCurrentLower()); 1117 cfml.next(); 1118 } 1119 } 1120 1121 /** 1122 * Liest den folgenden idetifier ein und prft ob dieser ein boolscher Wert ist. 1123 * Im Gegensatz zu CFMX wird auch "yes" und "no" als bolscher <wert akzeptiert, 1124 * was bei CFMX nur beim Umwandeln einer Zeichenkette zu einem boolschen Wert der Fall ist.<br /> 1125 * Wenn es sich um keinen bolschen Wert handelt wird der folgende Wert eingelesen mit seiner ganzen Hirarchie. 1126 * <br /> 1127 * EBNF:<br /> 1128 * <code>"true" | "false" | "yes" | "no" | startElement 1129 {("." identifier | "[" structElement "]" )[function] };</code> 1130 * @return CFXD Element 1131 * @throws PageException 1132 */ 1133 private Ref dynamic() throws PageException { 1134 // Die Implementation weicht ein wenig von der Grammatik ab, 1135 // aber nicht in der Logik sondern rein wie es umgesetzt wurde. 1136 1137 // get First Element of the Variable 1138 String name = identifier(false); 1139 if(name == null) { 1140 if (!cfml.forwardIfCurrent('('))return null; 1141 cfml.removeSpace(); 1142 Ref ref = assignOp(); 1143 1144 if (!cfml.forwardIfCurrent(')')) 1145 throw new ExpressionException("Invalid Syntax Closing [)] not found"); 1146 cfml.removeSpace(); 1147 return subDynamic(ref); 1148 } 1149 1150 //Element el; 1151 cfml.removeSpace(); 1152 char first=name.charAt(0); 1153 1154 // Boolean constant 1155 if(first=='T' && name.equals("TRUE")) { 1156 cfml.removeSpace(); 1157 return LBoolean.TRUE; 1158 } 1159 else if(first=='F' && name.equals("FALSE")) { 1160 cfml.removeSpace(); 1161 return LBoolean.FALSE; 1162 } 1163 else if(first=='Y' && name.equals("YES")) { 1164 cfml.removeSpace(); 1165 return LBoolean.TRUE; 1166 } 1167 else if(first=='N') { 1168 if(name.equals("NO")){ 1169 cfml.removeSpace(); 1170 return LBoolean.FALSE; 1171 } 1172 else if(allowNullConstant && name.equals("NULL")){ 1173 cfml.removeSpace(); 1174 return new LString(null); 1175 } 1176 else if(name.equals("NEW")){ 1177 Ref res = newOp(); 1178 if(res!=null) return res; 1179 } 1180 } 1181 1182 1183 1184 // Extract Scope from the Variable 1185 1186 //Object value = startElement(name); 1187 return subDynamic(startElement(name)); 1188 1189 } 1190 1191 private Ref subDynamic(Ref ref) throws PageException { 1192 String name=null; 1193 1194 // Loop over nested Variables 1195 while (cfml.isValidIndex()) { 1196 // . 1197 if (cfml.forwardIfCurrent('.')) { 1198 // Extract next Var String 1199 cfml.removeSpace(); 1200 name = identifier(true); 1201 if(name==null) throw new ExpressionException("Invalid identifier"); 1202 cfml.removeSpace(); 1203 ref=new Variable(pc,ref,name); 1204 } 1205 // [] 1206 else if (cfml.forwardIfCurrent('[')) { 1207 cfml.removeSpace(); 1208 ref=new Variable(pc,ref,assignOp()); 1209 cfml.removeSpace(); 1210 if (!cfml.forwardIfCurrent(']')) 1211 throw new ExpressionException("Invalid Syntax Closing []] not found"); 1212 } 1213 // finish 1214 else { 1215 break; 1216 } 1217 1218 cfml.removeSpace(); 1219 1220 if (cfml.isCurrent('(')) { 1221 if(!(ref instanceof Set)) throw new ExpressionException("invalid syntax "+ref.getTypeName()+" can't called as function"); 1222 Set set=(Set) ref; 1223 ref=new UDFCall(pc,set.getParent(),set.getKey(),functionArg(name,false, null,')')); 1224 } 1225 } 1226 if(ref instanceof railo.runtime.interpreter.ref.var.Scope) { 1227 railo.runtime.interpreter.ref.var.Scope s=(railo.runtime.interpreter.ref.var.Scope)ref; 1228 if(s.getScope()==Scope.SCOPE_ARGUMENTS || s.getScope()==Scope.SCOPE_LOCAL || s.getScope()==ScopeSupport.SCOPE_VAR) { 1229 ref=new Bind(s); 1230 } 1231 } 1232 return ref; 1233 } 1234 1235 /** 1236 * Extrahiert den Start Element einer Variale, 1237 * dies ist entweder eine Funktion, eine Scope Definition oder eine undefinierte Variable. 1238 * <br /> 1239 * EBNF:<br /> 1240 * <code>identifier "(" functionArg ")" | scope | identifier;</code> 1241 * @param name Einstiegsname 1242 * @return CFXD Element 1243 * @throws PageException 1244 */ 1245 private Ref startElement(String name) throws PageException { 1246 1247 // check function 1248 if (cfml.isCurrent('(')) { 1249 FunctionLibFunction function = fld.getFunction(name); 1250 Ref[] arguments = functionArg(name,true, function,')'); 1251 //print.out(name+":"+(function!=null)); 1252 if(function!=null) return new BIFCall(pc,function,arguments); 1253 1254 Ref ref = new railo.runtime.interpreter.ref.var.Scope(pc,Scope.SCOPE_UNDEFINED); 1255 return new UDFCall(pc,ref,name,arguments); 1256 } 1257 //check scope 1258 return scope(name); 1259 } 1260 1261 private Ref newOp() throws PageException { 1262 1263 int start=cfml.getPos(); 1264 String name=null; 1265 cfml.removeSpace(); 1266 1267 // first identifier 1268 name = identifier(true); 1269 Ref refName=null; 1270 if(name!=null) { 1271 StringBuilder fullName=new StringBuilder(); 1272 fullName.append(name); 1273 // Loop over addional identifier 1274 while (cfml.isValidIndex()) { 1275 if (cfml.forwardIfCurrent('.')) { 1276 cfml.removeSpace(); 1277 name = identifier(true); 1278 if(name==null) throw new ExpressionException("invalid Component declaration"); 1279 cfml.removeSpace(); 1280 fullName.append('.'); 1281 fullName.append(name); 1282 } 1283 else break; 1284 } 1285 refName=new LString(fullName.toString()); 1286 } 1287 else { 1288 if(cfml.isCurrentQuoter())refName=string(); 1289 if(refName==null){ 1290 cfml.setPos(start); 1291 return null; 1292 } 1293 } 1294 cfml.removeSpace(); 1295 1296 if (cfml.isCurrent('(')) { 1297 FunctionLibFunction function = fld.getFunction("_createComponent"); 1298 Ref[] arguments = functionArg("_createComponent",true, function,')'); 1299 Ref[] args=new Ref[arguments.length+1]; 1300 for(int i=0;i<arguments.length;i++){ 1301 args[i]=arguments[i]; 1302 } 1303 args[args.length-1]=refName; 1304 BIFCall bif = new BIFCall(pc,function,args); 1305 cfml.removeSpace(); 1306 return bif; 1307 1308 1309 1310 } 1311 throw new ExpressionException("invalid Component declaration "); 1312 1313 } 1314 1315 1316 1317 1318 /** 1319 * Liest einen CFML Scope aus, 1320 * falls der folgende identifier keinem Scope entspricht, 1321 * gibt die Variable null zurck. 1322 * <br /> 1323 * EBNF:<br /> 1324 * <code>"variable" | "cgi" | "url" | "form" | "session" | "application" | "arguments" | "cookie" | " client";</code> 1325 * @param idStr String identifier, 1326 * wird aus Optimierungszwechen nicht innerhalb dieser Funktion ausgelsen. 1327 * @return CFXD Variable Element oder null 1328 */ 1329 private Ref scope(String idStr) { 1330 if (idStr.equals("var")) { 1331 String name=identifier(false); 1332 if(name!=null){ 1333 cfml.removeSpace(); 1334 return new Variable(pc,new railo.runtime.interpreter.ref.var.Scope(pc,ScopeSupport.SCOPE_VAR),name); 1335 } 1336 } 1337 int scope = VariableInterpreter.scopeString2Int(idStr); 1338 if(scope==Scope.SCOPE_UNDEFINED) { 1339 return new Variable(pc,new railo.runtime.interpreter.ref.var.Scope(pc,Scope.SCOPE_UNDEFINED),idStr); 1340 } 1341 return new railo.runtime.interpreter.ref.var.Scope(pc,scope); 1342 1343 } 1344 1345 /** 1346 * Liest einen Identifier aus und gibt diesen als String zurck. 1347 * <br /> 1348 * EBNF:<br /> 1349 * <code>(letter | "_") {letter | "_"|digit};</code> 1350 * @param firstCanBeNumber 1351 * @return Identifier. 1352 */ 1353 private String identifier(boolean firstCanBeNumber) { 1354 //int start = cfml.getPos(); 1355 if(!cfml.isCurrentLetter() && !cfml.isCurrentSpecial()) { 1356 if(!firstCanBeNumber)return null; 1357 else if(!cfml.isCurrentDigit())return null; 1358 } 1359 1360 StringBuffer sb=new StringBuffer(); 1361 //if(CASE_TYPE_UPPER==caseType) 1362 sb.append(cfml.getCurrentUpper()); 1363 /*else if(CASE_TYPE_ORIGINAL==caseType) 1364 sb.append(cfml.getCurrent()); 1365 else 1366 sb.append(cfml.getCurrentLower());*/ 1367 do { 1368 cfml.next(); 1369 if(!(cfml.isCurrentLetter() 1370 || cfml.isCurrentDigit() 1371 || cfml.isCurrentSpecial())) { 1372 break; 1373 } 1374 1375 //if(CASE_TYPE_UPPER==caseType) 1376 sb.append(cfml.getCurrentUpper()); 1377 /*else if(CASE_TYPE_ORIGINAL==caseType) 1378 sb.append(cfml.getCurrent()); 1379 else 1380 sb.append(cfml.getCurrentLower());*/ 1381 1382 1383 } 1384 while (cfml.isValidIndex()); 1385 return sb.toString();//cfml.substringLower(start,cfml.getPos()-start); 1386 } 1387 1388 /** 1389 * Transfomiert ein Collection Element das in eckigen Klammern aufgerufen wird. 1390 * <br /> 1391 * EBNF:<br /> 1392 * <code>"[" impOp "]"</code> 1393 * @return CFXD Element 1394 * @throws PageException 1395 */ 1396 private Ref structElement() throws PageException { 1397 cfml.removeSpace(); 1398 Ref ref = new Casting(pc,"string",CFTypes.TYPE_STRING,assignOp()); 1399 cfml.removeSpace(); 1400 return ref; 1401 } 1402 1403 /** 1404 * Liest die Argumente eines Funktonsaufruf ein und prft ob die Funktion 1405 * innerhalb der FLD (Function Library Descriptor) definiert ist. 1406 * Falls sie existiert wird die Funktion gegen diese geprft und ein build-in-function CFXD Element generiert, 1407 * ansonsten ein normales funcion-call Element. 1408 * <br /> 1409 * EBNF:<br /> 1410 * <code>[impOp{"," impOp}];</code> 1411 * @param name Identifier der Funktion als Zeichenkette 1412 * @param checkLibrary Soll geprft werden ob die Funktion innerhalb der Library existiert. 1413 * @param flf FLD Function definition . 1414 * @return CFXD Element 1415 * @throws PageException 1416 */ 1417 private Ref[] functionArg(String name,boolean checkLibrary,FunctionLibFunction flf,char end) throws PageException { 1418 1419 // get Function Library 1420 checkLibrary=checkLibrary && flf!=null; 1421 1422 1423 // Function Attributes 1424 ArrayList arr = new ArrayList(); 1425 1426 ArrayList arrFuncLibAtt = null; 1427 int libLen = 0; 1428 if (checkLibrary) { 1429 arrFuncLibAtt = flf.getArg(); 1430 libLen = arrFuncLibAtt.size(); 1431 } 1432 int count = 0; 1433 Ref ref; 1434 do { 1435 cfml.next(); 1436 cfml.removeSpace(); 1437 1438 // finish 1439 if (cfml.isCurrent(end)) 1440 break; 1441 1442 // too many Attributes 1443 boolean isDynamic=false; 1444 int max=-1; 1445 if(checkLibrary) { 1446 isDynamic=isDynamic(flf); 1447 max=flf.getArgMax(); 1448 // Dynamic 1449 if(isDynamic) { 1450 if(max!=-1 && max <= count) 1451 throw new ExpressionException("too many Attributes in function [" + name + "]"); 1452 } 1453 // Fix 1454 else { 1455 if(libLen <= count) 1456 throw new ExpressionException("too many Attributes in function [" + name + "]"); 1457 } 1458 } 1459 1460 1461 if (checkLibrary && !isDynamic) { 1462 // current attribues from library 1463 FunctionLibFunctionArg funcLibAtt = (FunctionLibFunctionArg) arrFuncLibAtt.get(count); 1464 short type=CFTypes.toShort(funcLibAtt.getType(),CFTypes.TYPE_UNKNOW); 1465 if(type==CFTypes.TYPE_VARIABLE_STRING) { 1466 arr.add(functionArgDeclarationVarString()); 1467 } 1468 else { 1469 ref = functionArgDeclaration(); 1470 arr.add(new Casting(pc,funcLibAtt.getTypeAsString(),type,ref)); 1471 } 1472 } 1473 else { 1474 arr.add(functionArgDeclaration()); 1475 } 1476 1477 // obj=andOrXor(); 1478 cfml.removeSpace(); 1479 count++; 1480 } 1481 while (cfml.isCurrent(',')); 1482 1483 // end with ) ?? 1484 if (!cfml.forwardIfCurrent(end)) { 1485 if(name.startsWith("_json")) throw new ExpressionException("Invalid Syntax Closing ["+end+"] not found"); 1486 throw new ExpressionException("Invalid Syntax Closing ["+end+"] for function ["+ name + "] not found"); 1487 } 1488 1489 // check min attributes 1490 if (checkLibrary && flf.getArgMin() > count) 1491 throw new ExpressionException("to less Attributes in function [" + name + "]"); 1492 1493 cfml.removeSpace(); 1494 return (Ref[]) arr.toArray(new Ref[arr.size()]); 1495 } 1496 1497 1498 private boolean isDynamic(FunctionLibFunction flf) { 1499 return flf.getArgType()==FunctionLibFunction.ARG_DYNAMIC; 1500 } 1501 1502 /** 1503 * Sharps (#) die innerhalb von Expressions auftauchen haben in CFML keine weitere Beteutung 1504 * und werden durch diese Methode einfach entfernt. 1505 * <br /> 1506 * Beispiel:<br /> 1507 * <code>arrayLen(#arr#)</code> und <code>arrayLen(arr)</code> sind identisch. 1508 * EBNF:<br /> 1509 * <code>"#" checker "#";</code> 1510 * @return CFXD Element 1511 * @throws PageException 1512 */ 1513 private Ref sharp() throws PageException { 1514 if(!cfml.forwardIfCurrent('#')) 1515 return null; 1516 Ref ref; 1517 cfml.removeSpace(); 1518 ref = assignOp(); 1519 cfml.removeSpace(); 1520 if (!cfml.forwardIfCurrent('#')) 1521 throw new ExpressionException("Syntax Error, Invalid Construct"); 1522 cfml.removeSpace(); 1523 return ref; 1524 } 1525 1526 /* * 1527 * Wandelt eine variable und ein key in eine reference um 1528 * @param value 1529 * @param name 1530 * @return cast a vlue in a reference 1531 * @throws PageException 1532 * / 1533 private Reference toReference(Object value, String name) { 1534 return NativeReference.getInstance(value, name); 1535 }*/ 1536 1537 }