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