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