001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.transformer.bytecode.statement.tag; 020 021import lucee.commons.io.IOUtil; 022import lucee.commons.io.res.util.ResourceUtil; 023import lucee.runtime.exp.TemplateException; 024import lucee.transformer.bytecode.BytecodeContext; 025import lucee.transformer.bytecode.BytecodeException; 026import lucee.transformer.bytecode.Position; 027import lucee.transformer.bytecode.cast.CastBoolean; 028import lucee.transformer.bytecode.expression.Expression; 029import lucee.transformer.bytecode.statement.FlowControlBreak; 030import lucee.transformer.bytecode.statement.FlowControlContinue; 031import lucee.transformer.bytecode.statement.FlowControlFinal; 032import lucee.transformer.bytecode.statement.ForEach; 033import lucee.transformer.bytecode.util.ASMConstants; 034import lucee.transformer.bytecode.util.ExpressionUtil; 035import lucee.transformer.bytecode.util.Methods; 036import lucee.transformer.bytecode.util.Methods_Caster; 037import lucee.transformer.bytecode.util.Types; 038import lucee.transformer.bytecode.visitor.DecisionDoubleVisitor; 039import lucee.transformer.bytecode.visitor.DecisionIntVisitor; 040import lucee.transformer.bytecode.visitor.DecisionObjectVisitor; 041import lucee.transformer.bytecode.visitor.DoWhileVisitor; 042import lucee.transformer.bytecode.visitor.ForDoubleVisitor; 043import lucee.transformer.bytecode.visitor.ForVisitor; 044import lucee.transformer.bytecode.visitor.LoopVisitor; 045import lucee.transformer.bytecode.visitor.OnFinally; 046import lucee.transformer.bytecode.visitor.TryFinallyVisitor; 047import lucee.transformer.bytecode.visitor.WhileVisitor; 048 049import org.objectweb.asm.Label; 050import org.objectweb.asm.Opcodes; 051import org.objectweb.asm.Type; 052import org.objectweb.asm.commons.GeneratorAdapter; 053import org.objectweb.asm.commons.Method; 054 055public final class TagLoop extends TagGroup implements FlowControlBreak,FlowControlContinue { 056 057 058 public static final int TYPE_FILE = 1; 059 public static final int TYPE_LIST = 2; 060 public static final int TYPE_FROM_TO = 3; 061 public static final int TYPE_CONDITION = 4; 062 public static final int TYPE_QUERY = 5; 063 public static final int TYPE_COLLECTION = 6; 064 public static final int TYPE_ARRAY = 7; 065 public static final int TYPE_GROUP = 8; 066 public static final int TYPE_INNER_GROUP = 9; 067 public static final int TYPE_INNER_QUERY = 10; 068 public static final int TYPE_NOTHING = 11; 069 public static final int TYPE_STRUCT = 12; 070 public static final int TYPE_TIMES = 13; 071 072 073 074 075 // VariableReference getVariableReference(PageContext pc,String var) 076 private static final Method GET_VARIABLE_REFERENCE = new Method( 077 "getVariableReference", 078 Types.VARIABLE_REFERENCE, 079 new Type[]{Types.PAGE_CONTEXT,Types.STRING}); 080 081 082 // Object set(PageContext pc, Object value) 083 private static final Method SET = new Method( 084 "set", 085 Types.OBJECT, 086 new Type[]{Types.PAGE_CONTEXT,Types.OBJECT}); 087 // Object set(double value) 088 private static final Method SET_DOUBLE = new Method( 089 "set", 090 Types.VOID, 091 new Type[]{Types.DOUBLE_VALUE}); 092 093 094 095 /*private static final Method KEYS = new Method( 096 "keyIterator", 097 Types.COLLECTION_KEY_ARRAY, 098 new Type[]{});*/ 099 100 private static final Method GET = new Method( 101 "get", 102 Types.OBJECT, 103 new Type[]{Types.INT_VALUE,Types.OBJECT}); 104 105 private static final Method NEXT = new Method( 106 "next", 107 Types.OBJECT, 108 new Type[]{}); 109 110 private static final Method HAS_NEXT = new Method( 111 "hasNext", 112 Types.BOOLEAN_VALUE, 113 new Type[]{}); 114 115 // File toFileExisting(PageContext pc ,String destination) 116 private static final Type RESOURCE_UTIL = Type.getType(ResourceUtil.class); 117 private static final Method TO_RESOURCE_EXISTING = new Method( 118 "toResourceExisting", 119 Types.RESOURCE, 120 new Type[]{Types.PAGE_CONTEXT,Types.STRING}); 121 122 // Config getConfig() 123 private static final Method GET_CONFIG = new Method( 124 "getConfig", 125 Types.CONFIG_WEB, 126 new Type[]{}); 127 128 // SecurityManager getSecurityManager() 129 private static final Method GET_SECURITY_MANAGER = new Method( 130 "getSecurityManager", 131 Types.SECURITY_MANAGER, 132 new Type[]{}); 133 134 // void checkFileLocation(File file) 135 private static final Method CHECK_FILE_LOCATION = new Method( 136 "checkFileLocation", 137 Types.VOID, 138 new Type[]{Types.RESOURCE}); 139 140 // Reader getReader(File file, String charset) 141 private static final Type IO_UTIL = Type.getType(IOUtil.class); 142 private static final Method GET_BUFFERED_READER = new Method( 143 "getBufferedReader", 144 Types.BUFFERED_READER, 145 new Type[]{Types.RESOURCE,Types.STRING}); 146 147 // void closeEL(Reader r) 148 private static final Method CLOSE_EL = new Method( 149 "closeEL", 150 Types.VOID, 151 new Type[]{Types.READER}); 152 153 // String readLine() 154 private static final Method READ_LINE = new Method( 155 "readLine", 156 Types.STRING, 157 new Type[]{}); 158 159 160 // Array listToArrayRemoveEmpty(String list, String delimiter) 161 private static final Method LIST_TO_ARRAY_REMOVE_EMPTY_SS = new Method( 162 "listToArrayRemoveEmpty", 163 Types.ARRAY, 164 new Type[]{Types.STRING,Types.STRING}); 165 166 // Array listToArrayRemoveEmpty(String list, char delimiter) 167 private static final Method LIST_TO_ARRAY_REMOVE_EMPTY_SC = new Method( 168 "listToArrayRemoveEmpty", 169 Types.ARRAY, 170 new Type[]{Types.STRING,Types.CHAR}); 171 172 private static final Method SIZE = new Method( 173 "size", 174 Types.INT_VALUE, 175 new Type[]{}); 176 177 178 // Object get(int key) klo 179 private static final Method GETE = new Method( 180 "getE", 181 Types.OBJECT, 182 new Type[]{Types.INT_VALUE}); 183 184 185 186 187 // Query getQuery(String key) 188 public static final Method GET_QUERY_OBJ = new Method( 189 "getQuery", 190 Types.QUERY, 191 new Type[]{Types.OBJECT}); 192 public static final Method GET_QUERY_STRING = new Method( 193 "getQuery", 194 Types.QUERY, 195 new Type[]{Types.STRING}); 196 197 // int getCurrentrow() 198 static final Method GET_CURRENTROW_1 = new Method( 199 "getCurrentrow", 200 Types.INT_VALUE, 201 new Type[]{Types.INT_VALUE}); 202 203 static final Method GO = new Method( 204 "go", 205 Types.BOOLEAN_VALUE, 206 new Type[]{Types.INT_VALUE,Types.INT_VALUE}); 207 208 static final Method GET_ID = new Method( 209 "getId", 210 Types.INT_VALUE, 211 new Type[]{}); 212 private static final Method READ = new Method( 213 "read", 214 Types.STRING, 215 new Type[]{Types.READER,Types.INT_VALUE}); 216 private static final Method ENTRY_ITERATOR = new Method("entryIterator",Types.ITERATOR,new Type[]{}); 217 private static final Method GET_KEY = new Method("getKey",Types.OBJECT,new Type[]{}); 218 private static final Method GET_VALUE = new Method("getValue",Types.OBJECT,new Type[]{}); 219 220 221 222 223 224 private int type; 225 private LoopVisitor loopVisitor; 226 private String label; 227 228 public TagLoop(Position start,Position end) { 229 super(start,end); 230 } 231 232 public void setType(int type) { 233 this.type=type; 234 } 235 236 237 /** 238 * 239 * @see lucee.transformer.bytecode.statement.tag.TagBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter) 240 */ 241 public void _writeOut(BytecodeContext bc) throws BytecodeException { 242 boolean old; 243 244 switch(type) { 245 case TYPE_STRUCT: 246 case TYPE_COLLECTION: 247 writeOutTypeCollection(bc); 248 break; 249 case TYPE_CONDITION: 250 writeOutTypeCondition(bc); 251 break; 252 case TYPE_FILE: 253 writeOutTypeFile(bc); 254 break; 255 case TYPE_FROM_TO: 256 writeOutTypeFromTo(bc); 257 break; 258 case TYPE_LIST: 259 writeOutTypeListArray(bc,false); 260 break; 261 case TYPE_ARRAY: 262 writeOutTypeListArray(bc,true); 263 break; 264 case TYPE_QUERY: 265 old = bc.changeDoSubFunctions(false); 266 TagGroupUtil.writeOutTypeQuery(this,bc); 267 bc.changeDoSubFunctions(old); 268 //writeOutTypeQuery(bc); 269 break; 270 271 case TYPE_GROUP: 272 old = bc.changeDoSubFunctions(false); 273 TagGroupUtil.writeOutTypeGroup(this,bc); 274 bc.changeDoSubFunctions(old); 275 //writeOutTypeQuery(bc); 276 break; 277 278 case TYPE_INNER_GROUP: 279 old = bc.changeDoSubFunctions(false); 280 TagGroupUtil.writeOutTypeInnerGroup(this,bc); 281 bc.changeDoSubFunctions(old); 282 break; 283 284 case TYPE_INNER_QUERY: 285 old = bc.changeDoSubFunctions(false); 286 TagGroupUtil.writeOutTypeInnerQuery(this,bc); 287 bc.changeDoSubFunctions(old); 288 break; 289 case TYPE_TIMES: 290 // writeOutTypeTimes(bc); 291 //break; 292 case TYPE_NOTHING: 293 GeneratorAdapter a = bc.getAdapter(); 294 DoWhileVisitor dwv=new DoWhileVisitor(); 295 setLoopVisitor(dwv); 296 dwv.visitBeginBody(a); 297 getBody().writeOut(bc); 298 dwv.visitEndBodyBeginExpr(a); 299 a.push(false); 300 dwv.visitEndExpr(a); 301 302 303 break; 304 305 306 307 default: 308 throw new BytecodeException("invalid type",getStart()); 309 } 310 } 311 312 /** 313 * write out collection loop 314 * @param adapter 315 * @throws TemplateException 316 */ 317 private void writeOutTypeCollection(BytecodeContext bc) throws BytecodeException { 318 319 GeneratorAdapter adapter = bc.getAdapter(); 320 321 //VariableReference item=VariableInterpreter.getVariableReference(pc,index); 322 int index = -1; 323 Attribute attrIndex = getAttribute("index"); 324 if(attrIndex!=null){ 325 index = adapter.newLocal(Types.VARIABLE_REFERENCE); 326 adapter.loadArg(0); 327 attrIndex.getValue().writeOut(bc, Expression.MODE_REF); 328 adapter.invokeStatic(Types.VARIABLE_INTERPRETER, GET_VARIABLE_REFERENCE); 329 adapter.storeLocal(index); 330 } 331 332 //VariableReference item=VariableInterpreter.getVariableReference(pc,item); 333 int item = -1; 334 Attribute attrItem = getAttribute("item"); 335 if(attrItem!=null){ 336 item = adapter.newLocal(Types.VARIABLE_REFERENCE); 337 adapter.loadArg(0); 338 attrItem.getValue().writeOut(bc, Expression.MODE_REF); 339 adapter.invokeStatic(Types.VARIABLE_INTERPRETER, GET_VARIABLE_REFERENCE); 340 adapter.storeLocal(item); 341 } 342 boolean hasIndexAndItem=index!=-1 && item!=-1; 343 344 345 346 WhileVisitor whileVisitor = new WhileVisitor(); 347 loopVisitor=whileVisitor; 348 // java.util.Iterator it=Caster.toIterator(@collection'); 349 int it=adapter.newLocal(Types.ITERATOR); 350 Attribute coll = getAttribute("struct"); 351 if(coll==null)coll=getAttribute("collection"); 352 coll.getValue().writeOut(bc,Expression.MODE_REF); 353 354 // item and index 355 int entry=-1; 356 if(hasIndexAndItem) { 357 entry = adapter.newLocal(Types.MAP_ENTRY); 358 // Caster.toCollection(collection) 359 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_COLLECTION); 360 //coll.entryIterator(); 361 adapter.invokeInterface(Types.COLLECTION, ENTRY_ITERATOR); 362 } 363 else { 364 adapter.invokeStatic(Types.CASTER,ForEach.TO_ITERATOR); 365 } 366 367 368 adapter.storeLocal(it); 369 370 371 372 373 // while(it.hasNext()) { 374 whileVisitor.visitBeforeExpression(bc); 375 adapter.loadLocal(it); 376 adapter.invokeInterface(Types.ITERATOR, HAS_NEXT); 377 378 whileVisitor.visitAfterExpressionBeforeBody(bc); 379 if(hasIndexAndItem) { 380 // entry=it.next(); 381 adapter.loadLocal(it); 382 adapter.invokeInterface(Types.ITERATOR, NEXT); 383 adapter.storeLocal(entry); 384 385 // keyRef.set(pc,entry.getKey()) 386 adapter.loadLocal(index); 387 adapter.loadArg(0); 388 adapter.loadLocal(entry); 389 adapter.invokeInterface(Types.MAP_ENTRY, GET_KEY); 390 adapter.invokeStatic(Types.CASTER,Methods.METHOD_TO_STRING); 391 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 392 adapter.pop(); 393 394 // valueRef.set(pc,entry.getKey()) 395 adapter.loadLocal(item); 396 adapter.loadArg(0); 397 adapter.loadLocal(entry); 398 adapter.invokeInterface(Types.MAP_ENTRY, GET_VALUE); 399 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 400 adapter.pop(); 401 402 } 403 else { 404 if(index==-1) adapter.loadLocal(item); 405 else adapter.loadLocal(index); 406 407 adapter.loadArg(0); 408 adapter.loadLocal(it); 409 adapter.invokeInterface(Types.ITERATOR, NEXT); 410 411 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 412 adapter.pop(); 413 } 414 415 416 417 418 419 420 getBody().writeOut(bc); 421 whileVisitor.visitAfterBody(bc,getEnd()); 422 423 } 424 425 /** 426 * write out condition loop 427 * @param adapter 428 * @throws TemplateException 429 */ 430 private void writeOutTypeCondition(BytecodeContext bc) throws BytecodeException { 431 WhileVisitor whileVisitor = new WhileVisitor(); 432 loopVisitor=whileVisitor; 433 whileVisitor.visitBeforeExpression(bc); 434 CastBoolean.toExprBoolean(getAttribute("condition").getValue()).writeOut(bc, Expression.MODE_VALUE); 435 whileVisitor.visitAfterExpressionBeforeBody(bc); 436 getBody().writeOut(bc); 437 whileVisitor.visitAfterBody(bc,getEnd()); 438 439 } 440 441 /** 442 * write out file loop 443 * @param adapter 444 * @throws TemplateException 445 */ 446 private void writeOutTypeFile(BytecodeContext bc) throws BytecodeException { 447 WhileVisitor whileVisitor = new WhileVisitor(); 448 loopVisitor=whileVisitor; 449 GeneratorAdapter adapter = bc.getAdapter(); 450 451 // charset=@charset 452 int charset=adapter.newLocal(Types.STRING); 453 Attribute attrCharset = getAttribute("charset"); 454 if(attrCharset==null) adapter.visitInsn(Opcodes.ACONST_NULL); 455 else attrCharset.getValue().writeOut(bc, Expression.MODE_REF); 456 adapter.storeLocal(charset); 457 458 // startline=@startline 459 int startline=adapter.newLocal(Types.INT_VALUE); 460 Attribute attrStartLine = getAttribute("startline"); 461 if(attrStartLine==null) attrStartLine = getAttribute("from"); // CF8 462 if(attrStartLine==null) adapter.push(1); 463 else { 464 attrStartLine.getValue().writeOut(bc, Expression.MODE_VALUE); 465 adapter.visitInsn(Opcodes.D2I); 466 } 467 adapter.storeLocal(startline); 468 469 // endline=@endline 470 int endline=adapter.newLocal(Types.INT_VALUE); 471 Attribute attrEndLine = getAttribute("endline"); 472 if(attrEndLine==null) attrEndLine = getAttribute("to"); 473 if(attrEndLine==null) adapter.push(-1); 474 else { 475 attrEndLine.getValue().writeOut(bc, Expression.MODE_VALUE); 476 adapter.visitInsn(Opcodes.D2I); 477 } 478 adapter.storeLocal(endline); 479 480 481 //VariableReference index=VariableInterpreter.getVariableReference(pc,@index); 482 int index=-1,item=-1; 483 484 // item 485 Attribute attrItem = getAttribute("item"); 486 if(attrItem!=null) { 487 item = adapter.newLocal(Types.VARIABLE_REFERENCE); 488 adapter.loadArg(0); 489 attrItem.getValue().writeOut(bc, Expression.MODE_REF); 490 adapter.invokeStatic(Types.VARIABLE_INTERPRETER, GET_VARIABLE_REFERENCE); 491 adapter.storeLocal(item); 492 } 493 494 // index 495 Attribute attrIndex = getAttribute("index"); 496 if(attrIndex!=null) { 497 index = adapter.newLocal(Types.VARIABLE_REFERENCE); 498 adapter.loadArg(0); 499 attrIndex.getValue().writeOut(bc, Expression.MODE_REF); 500 adapter.invokeStatic(Types.VARIABLE_INTERPRETER, GET_VARIABLE_REFERENCE); 501 adapter.storeLocal(index); 502 } 503 504 //java.io.File file=FileUtil.toResourceExisting(pc,@file); 505 int resource=adapter.newLocal(Types.RESOURCE); 506 adapter.loadArg(0); 507 getAttribute("file").getValue().writeOut(bc, Expression.MODE_REF); 508 adapter.invokeStatic(RESOURCE_UTIL, TO_RESOURCE_EXISTING); 509 adapter.storeLocal(resource); 510 511 // pc.getConfig().getSecurityManager().checkFileLocation(resource); 512 adapter.loadArg(0); 513 adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_CONFIG); 514 adapter.invokeInterface(Types.CONFIG_WEB, GET_SECURITY_MANAGER); 515 adapter.loadLocal(resource); 516 adapter.invokeInterface(Types.SECURITY_MANAGER, CHECK_FILE_LOCATION); 517 518 // char[] carr=new char[characters]; 519 Attribute attr = getAttribute("characters"); 520 int carr=-1; 521 if(attr!=null) { 522 carr=adapter.newLocal(Types.CHAR_ARRAY); 523 attr.getValue().writeOut(bc, Expression.MODE_VALUE); 524 adapter.cast(Types.DOUBLE_VALUE, Types.INT_VALUE); 525 adapter.newArray(Types.CHAR); 526 adapter.storeLocal(carr); 527 } 528 529 // BufferedReader reader = IOUtil.getBufferedReader(resource,charset); 530 final int br=adapter.newLocal(Types.BUFFERED_READER); 531 adapter.loadLocal(resource); 532 adapter.loadLocal(charset); 533 adapter.invokeStatic(IO_UTIL, GET_BUFFERED_READER); 534 adapter.storeLocal(br); 535 536 // String line; 537 int line=adapter.newLocal(Types.STRING); 538 539 // int count=0; 540 int count=adapter.newLocal(Types.INT_VALUE); 541 adapter.push(0); 542 adapter.storeLocal(count); 543 544 TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() { 545 public void _writeOut(BytecodeContext bc) { 546 bc.getAdapter().loadLocal(br); 547 bc.getAdapter().invokeStatic(IO_UTIL, CLOSE_EL); 548 } 549 },null); 550 //TryFinallyVisitor tcfv=new TryFinallyVisitor(); 551 552 // try 553 tfv.visitTryBegin(bc); 554 //tcfv.visitTryBegin(bc); 555 // while((line=br.readLine())!=null) { 556 //WhileVisitor wv=new WhileVisitor(); 557 whileVisitor.visitBeforeExpression(bc); 558 DecisionObjectVisitor dv=new DecisionObjectVisitor(); 559 dv.visitBegin(); 560 if(attr!=null) { 561 // IOUtil.read(bufferedreader,12) 562 adapter.loadLocal(br); 563 adapter.loadLocal(carr); 564 adapter.arrayLength(); 565 adapter.invokeStatic(Types.IOUTIL, READ); 566 } 567 else { 568 // br.readLine() 569 adapter.loadLocal(br); 570 adapter.invokeVirtual(Types.BUFFERED_READER, READ_LINE); 571 } 572 adapter.dup(); 573 adapter.storeLocal(line); 574 575 dv.visitNEQ(); 576 adapter.visitInsn(Opcodes.ACONST_NULL); 577 dv.visitEnd(bc); 578 579 whileVisitor.visitAfterExpressionBeforeBody(bc); 580 //if(++count < startLine) continue; 581 DecisionIntVisitor dv2=new DecisionIntVisitor(); 582 dv2.visitBegin(); 583 adapter.iinc(count, 1); 584 adapter.loadLocal(count); 585 dv2.visitLT(); 586 adapter.loadLocal(startline); 587 dv2.visitEnd(bc); 588 Label end=new Label(); 589 adapter.ifZCmp(Opcodes.IFEQ, end); 590 whileVisitor.visitContinue(bc); 591 adapter.visitLabel(end); 592 593 // if(endLine!=-1 && count > endLine) break; 594 DecisionIntVisitor div=new DecisionIntVisitor(); 595 div.visitBegin(); 596 adapter.loadLocal(endline); 597 div.visitNEQ(); 598 adapter.push(-1); 599 div.visitEnd(bc); 600 Label end2=new Label(); 601 adapter.ifZCmp(Opcodes.IFEQ, end2); 602 603 DecisionIntVisitor div2 = new DecisionIntVisitor(); 604 div2.visitBegin(); 605 adapter.loadLocal(count); 606 div2.visitGT(); 607 adapter.loadLocal(endline); 608 div2.visitEnd(bc); 609 Label end3=new Label(); 610 adapter.ifZCmp(Opcodes.IFEQ, end3); 611 whileVisitor.visitBreak(bc); 612 adapter.visitLabel(end3); 613 adapter.visitLabel(end2); 614 615 // index and item 616 if(index!=-1 && item!=-1) { 617 // index.set(pc,line); 618 adapter.loadLocal(index); 619 adapter.loadArg(0); 620 adapter.loadLocal(count); 621 adapter.cast(Types.INT_VALUE,Types.DOUBLE_VALUE); 622 adapter.invokeStatic(Types.CASTER, Methods.METHOD_TO_DOUBLE_FROM_DOUBLE); 623 624 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 625 adapter.pop(); 626 627 // item.set(pc,line); 628 adapter.loadLocal(item); 629 adapter.loadArg(0); 630 adapter.loadLocal(line); 631 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 632 adapter.pop(); 633 634 } 635 // only index 636 else if(index!=-1) { 637 // index.set(pc,line); 638 adapter.loadLocal(index); 639 adapter.loadArg(0); 640 adapter.loadLocal(line); 641 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 642 adapter.pop(); 643 644 } 645 // only item 646 else { 647 // item.set(pc,line); 648 adapter.loadLocal(item); 649 adapter.loadArg(0); 650 adapter.loadLocal(line); 651 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 652 adapter.pop(); 653 } 654 655 656 657 658 getBody().writeOut(bc); 659 660 whileVisitor.visitAfterBody(bc,getEnd()); 661 662 tfv.visitTryEnd(bc); 663 664 } 665 666 /** 667 * write out index loop 668 * @param adapter 669 * @throws TemplateException 670 */ 671 private void writeOutTypeFromTo(BytecodeContext bc) throws BytecodeException { 672 ForDoubleVisitor forDoubleVisitor = new ForDoubleVisitor(); 673 loopVisitor=forDoubleVisitor; 674 GeneratorAdapter adapter = bc.getAdapter(); 675 676 // int from=(int)@from; 677 int from=adapter.newLocal(Types.DOUBLE_VALUE); 678 ExpressionUtil.writeOutSilent(getAttribute("from").getValue(), bc, Expression.MODE_VALUE); 679 adapter.storeLocal(from); 680 681 // int to=(int)@to; 682 int to=adapter.newLocal(Types.DOUBLE_VALUE); 683 ExpressionUtil.writeOutSilent(getAttribute("to").getValue(), bc, Expression.MODE_VALUE); 684 adapter.storeLocal(to); 685 686 // int step=(int)@step; 687 int step=adapter.newLocal(Types.DOUBLE_VALUE); 688 Attribute attrStep = getAttribute("step"); 689 if(attrStep!=null) { 690 ExpressionUtil.writeOutSilent(attrStep.getValue(), bc, Expression.MODE_VALUE); 691 } 692 else { 693 adapter.push(1D); 694 } 695 adapter.storeLocal(step); 696 697 // boolean dirPlus=(step > 0); 698 int dirPlus=adapter.newLocal(Types.BOOLEAN_VALUE); 699 DecisionDoubleVisitor div=new DecisionDoubleVisitor(); 700 div.visitBegin(); 701 adapter.loadLocal(step); 702 div.visitGT(); 703 adapter.push(0D); 704 div.visitEnd(bc); 705 adapter.storeLocal(dirPlus); 706 707 //if(step!=0) { 708 div=new DecisionDoubleVisitor(); 709 div.visitBegin(); 710 adapter.loadLocal(step); 711 div.visitNEQ(); 712 adapter.push(0D); 713 div.visitEnd(bc); 714 Label ifEnd=new Label(); 715 adapter.ifZCmp(Opcodes.IFEQ, ifEnd); 716 717 // VariableReference index>=VariableInterpreter.getVariableReference(pc,@index)); 718 int index = adapter.newLocal(Types.VARIABLE_REFERENCE); 719 adapter.loadArg(0); 720 Attribute attr = getAttribute("index"); 721 if(attr==null) attr = getAttribute("item"); 722 ExpressionUtil.writeOutSilent(attr.getValue(), bc, Expression.MODE_REF); 723 adapter.invokeStatic(Types.VARIABLE_INTERPRETER, GET_VARIABLE_REFERENCE); 724 adapter.storeLocal(index); 725 726 727 // index.set(from); 728 adapter.loadLocal(index); 729 adapter.loadLocal(from); 730 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET_DOUBLE); 731 732 // for 733 734 //int i=forConditionVisitor.visitBeforeExpression(adapter,from,step,true); 735 736 // init 737 adapter.visitLabel(forDoubleVisitor.beforeInit); 738 forDoubleVisitor.forInit(adapter, from, true); 739 adapter.goTo(forDoubleVisitor.beforeExpr); 740 741 // update 742 adapter.visitLabel(forDoubleVisitor.beforeUpdate); 743 adapter.loadLocal(index); 744 //forConditionVisitor.forUpdate(adapter, step, true); 745 adapter.visitVarInsn(Opcodes.DLOAD, forDoubleVisitor.i); 746 adapter.loadLocal(step); 747 adapter.visitInsn(Opcodes.DADD); 748 adapter.visitInsn(Opcodes.DUP2); 749 adapter.visitVarInsn(Opcodes.DSTORE, forDoubleVisitor.i); 750 751 752 753 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET_DOUBLE); 754 755 756 757 758 // expression 759 adapter.visitLabel(forDoubleVisitor.beforeExpr); 760 int i=forDoubleVisitor.i; 761 762 763 764 765 766 adapter.loadLocal(dirPlus); 767 Label l1 = new Label(); 768 adapter.visitJumpInsn(Opcodes.IFEQ, l1); 769 770 div=new DecisionDoubleVisitor(); 771 div.visitBegin(); 772 adapter.visitVarInsn(Opcodes.DLOAD, i); 773 div.visitLTE(); 774 adapter.loadLocal(to); 775 div.visitEnd(bc); 776 777 Label l2 = new Label(); 778 adapter.visitJumpInsn(Opcodes.GOTO, l2); 779 adapter.visitLabel(l1); 780 781 div=new DecisionDoubleVisitor(); 782 div.visitBegin(); 783 adapter.visitVarInsn(Opcodes.DLOAD, i); 784 div.visitGTE(); 785 adapter.loadLocal(to); 786 div.visitEnd(bc); 787 788 adapter.visitLabel(l2); 789 forDoubleVisitor.visitAfterExpressionBeginBody(adapter); 790 791 //adapter.loadLocal(index); 792 //adapter.visitVarInsn(Opcodes.DLOAD, i); 793 //adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET_DOUBLE); 794 795 getBody().writeOut(bc); 796 797 forDoubleVisitor.visitEndBody(bc,getEnd()); 798 799 800 801 ////// set i after usage 802 //adapter.loadLocal(index); 803 //adapter.visitVarInsn(Opcodes.DLOAD, i); 804 //adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET_DOUBLE); 805 806 adapter.visitLabel(ifEnd); 807 808 } 809 810 /** 811 * write out list loop 812 * @param adapter 813 * @throws TemplateException 814 */ 815 private void writeOutTypeListArray(BytecodeContext bc, boolean isArray) throws BytecodeException { 816 ForVisitor forVisitor = new ForVisitor(); 817 loopVisitor=forVisitor; 818 GeneratorAdapter adapter = bc.getAdapter(); 819 820 //List.listToArrayRemoveEmpty("", 'c') 821 int array = adapter.newLocal(Types.ARRAY); 822 int len = adapter.newLocal(Types.INT_VALUE); 823 824 if(isArray) { 825 getAttribute("array").getValue().writeOut(bc, Expression.MODE_REF); 826 } 827 else { 828 // array=List.listToArrayRemoveEmpty(list, delimter) 829 getAttribute("list").getValue().writeOut(bc, Expression.MODE_REF); 830 if(containsAttribute("delimiters")) { 831 getAttribute("delimiters").getValue().writeOut(bc, Expression.MODE_REF); 832 adapter.invokeStatic(Types.LIST_UTIL, LIST_TO_ARRAY_REMOVE_EMPTY_SS); 833 } 834 else { 835 adapter.visitIntInsn(Opcodes.BIPUSH, 44);// ',' 836 //adapter.push(','); 837 adapter.invokeStatic(Types.LIST_UTIL, LIST_TO_ARRAY_REMOVE_EMPTY_SC); 838 } 839 } 840 adapter.storeLocal(array); 841 842 843 // int len=array.size(); 844 adapter.loadLocal(array); 845 adapter.invokeInterface(Types.ARRAY, SIZE); 846 adapter.storeLocal(len); 847 848 849 //VariableInterpreter.getVariableReference(pc,Caster.toString(index)); 850 Attribute attrIndex = getAttribute("index"); 851 int index = -1; 852 if(attrIndex!=null) { 853 index = adapter.newLocal(Types.VARIABLE_REFERENCE); 854 adapter.loadArg(0); 855 attrIndex.getValue().writeOut(bc, Expression.MODE_REF); 856 adapter.invokeStatic(Types.VARIABLE_INTERPRETER, GET_VARIABLE_REFERENCE); 857 adapter.storeLocal(index); 858 } 859 860 861 //VariableInterpreter.getVariableReference(pc,Caster.toString(item)); 862 Attribute attrItem = getAttribute("item"); 863 int item = -1; 864 if(attrItem!=null) { 865 item = adapter.newLocal(Types.VARIABLE_REFERENCE); 866 adapter.loadArg(0); 867 attrItem.getValue().writeOut(bc, Expression.MODE_REF); 868 adapter.invokeStatic(Types.VARIABLE_INTERPRETER, GET_VARIABLE_REFERENCE); 869 adapter.storeLocal(item); 870 } 871 872 873 int obj=0; 874 if(isArray)obj=adapter.newLocal(Types.OBJECT); 875 876 // for(int i=1;i<=len;i++) { 877 int i = forVisitor.visitBegin(adapter, 1, false); 878 // index.set(pc, list.get(i)); 879 880 if(isArray) { 881 882 883 // value 884 adapter.loadLocal(array); 885 adapter.visitVarInsn(Opcodes.ILOAD, i); 886 ASMConstants.NULL(adapter); 887 adapter.invokeInterface(Types.ARRAY, GET); 888 adapter.dup(); 889 adapter.storeLocal(obj); 890 Label endIf=new Label(); 891 //adapter.loadLocal(obj); 892 adapter.visitJumpInsn(Opcodes.IFNONNULL, endIf); 893 adapter.goTo(forVisitor.getContinueLabel()); 894 adapter.visitLabel(endIf); 895 896 897 if(item==-1) adapter.loadLocal(index); 898 else adapter.loadLocal(item); 899 900 adapter.loadArg(0); 901 902 903 adapter.loadLocal(obj); 904 905 } 906 else { 907 if(item==-1) adapter.loadLocal(index); 908 else adapter.loadLocal(item); 909 adapter.loadArg(0); 910 adapter.loadLocal(array); 911 adapter.visitVarInsn(Opcodes.ILOAD, i); 912 adapter.invokeInterface(Types.ARRAY, GETE); 913 914 915 } 916 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 917 adapter.pop(); 918 919 920 // key 921 if(index!=-1 && item!=-1) { 922 adapter.loadLocal(index); 923 adapter.loadArg(0); 924 adapter.visitVarInsn(Opcodes.ILOAD, i); 925 adapter.cast(Types.INT_VALUE,Types.DOUBLE_VALUE); 926 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DOUBLE[Methods_Caster.DOUBLE]); 927 adapter.invokeVirtual(Types.VARIABLE_REFERENCE, SET); 928 adapter.pop(); 929 } 930 931 932 getBody().writeOut(bc); 933 forVisitor.visitEnd(bc, len, true,getStart()); 934 } 935 936 /* * 937 * write out query loop 938 * @param adapter 939 * @throws TemplateException 940 * / 941 private void writeOutTypeQuery(BytecodeContext bc) throws BytecodeException { 942 ForConditionIntVisitor forConditionVisitor = new ForConditionIntVisitor();// TODO replace with ForIntVisitor 943 loopVisitor=forConditionVisitor; 944 final GeneratorAdapter adapter = bc.getAdapter(); 945 946 // lucee.runtime.type.Query query=pc.getQuery(@query); 947 final int query=adapter.newLocal(Types.QUERY); 948 adapter.loadArg(0); 949 Expression val = getAttribute("query").getValue(); 950 val.writeOut(bc, Expression.MODE_REF); 951 if(val instanceof LitString) 952 adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_QUERY_STRING); 953 else 954 adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_QUERY_OBJ); 955 //adapter.dup(); 956 adapter.storeLocal(query); 957 958 //int queryImpl = adapter.newLocal(Types.QUERY_IMPL); 959 //adapter.checkCast(Types.QUERY_IMPL); 960 //adapter.storeLocal(queryImpl); 961 962 963 // int startAt=query.getCurrentrow(); 964 final int startAt=adapter.newLocal(Types.INT_VALUE); 965 966 adapter.loadLocal(query); 967 adapter.loadArg(0); 968 adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID); 969 adapter.invokeInterface(Types.QUERY, GET_CURRENTROW_1); 970 adapter.storeLocal(startAt); 971 972 973 // startrow 974 int start=adapter.newLocal(Types.INT_VALUE); 975 Attribute attrStartRow = getAttribute("startrow"); 976 if(attrStartRow!=null){ 977 //lucee.runtime.util.NumberRange.range(@startrow,1) 978 attrStartRow.getValue().writeOut(bc, Expression.MODE_VALUE); 979 adapter.push(1d); 980 adapter.invokeStatic(Types.NUMBER_RANGE, RANGE); 981 adapter.visitInsn(Opcodes.D2I); 982 } 983 else { 984 adapter.push(1); 985 } 986 adapter.storeLocal(start); 987 988 // endrow 989 int end=adapter.newLocal(Types.INT_VALUE); 990 Attribute attrEndRow = getAttribute("endrow"); 991 if(attrEndRow!=null){ 992 attrEndRow.getValue().writeOut(bc, Expression.MODE_VALUE); 993 adapter.visitInsn(Opcodes.D2I); 994 adapter.storeLocal(end); 995 } 996 997 // pc.us().addQuery(query); 998 adapter.loadArg(0); 999 adapter.invokeVirtual(Types.PAGE_CONTEXT, US); 1000 adapter.loadLocal(query); 1001 adapter.invokeInterface(UNDEFINED, ADD_QUERY); 1002 1003 // try 1004 TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() { 1005 public void writeOut(BytecodeContext bc) { 1006 //GeneratorAdapter ga = bc.getAdapter(); 1007 // pc.us().removeCollection(); 1008 adapter.loadArg(0); 1009 adapter.invokeVirtual(Types.PAGE_CONTEXT, US); 1010 adapter.invokeInterface(UNDEFINED, REMOVE_QUERY); 1011 1012 // query.go(startAt); 1013 adapter.loadLocal(query); 1014 adapter.loadLocal(startAt); 1015 1016 adapter.loadArg(0); 1017 adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID); 1018 adapter.invokeInterface(Types.QUERY, GO); 1019 adapter.pop(); 1020 } 1021 }); 1022 tfv.visitTryBegin(bc); 1023 // For 1024 1025 int i=forConditionVisitor.visitBegin(adapter, start, true); 1026 getBody().writeOut(bc); 1027 forConditionVisitor.visitEndBeforeCondition(bc,1,false,getStart()); 1028 1029 // && i<=endrow 1030 if(attrEndRow!=null){ 1031 AndVisitor av=new AndVisitor(); 1032 av.visitBegin(); 1033 adapter.loadLocal(query); 1034 adapter.visitVarInsn(Opcodes.ILOAD, i); 1035 1036 adapter.loadArg(0); 1037 adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID); 1038 adapter.invokeInterface(Types.QUERY, GO); 1039 1040 av.visitMiddle(bc); 1041 //LitBoolean.TRUE.writeOut(bc, Expression.MODE_VALUE); 1042 DecisionIntVisitor dv=new DecisionIntVisitor(); 1043 dv.visitBegin(); 1044 adapter.visitVarInsn(Opcodes.ILOAD, i); 1045 dv.visitLTE(); 1046 adapter.loadLocal(end); 1047 dv.visitEnd(bc); 1048 av.visitEnd(bc); 1049 } 1050 else { 1051 adapter.loadLocal(query); 1052 adapter.visitVarInsn(Opcodes.ILOAD, i); 1053 1054 adapter.loadArg(0); 1055 adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID); 1056 adapter.invokeInterface(Types.QUERY, GO); 1057 1058 1059 } 1060 1061 1062 forConditionVisitor.visitEndAfterCondition(bc); 1063 1064 // Finally 1065 tfv.visitTryEnd(bc); 1066 }*/ 1067 1068 /** 1069 * @see lucee.transformer.bytecode.statement.FlowControl#getBreakLabel() 1070 */ 1071 public Label getBreakLabel() { 1072 return loopVisitor.getBreakLabel(); 1073 } 1074 1075 /** 1076 * @see lucee.transformer.bytecode.statement.FlowControl#getContinueLabel() 1077 */ 1078 public Label getContinueLabel() { 1079 return loopVisitor.getContinueLabel(); 1080 } 1081 1082 @Override 1083 public short getType() { 1084 return TAG_LOOP; 1085 } 1086 1087 public void setLoopVisitor(LoopVisitor loopVisitor) { 1088 this.loopVisitor=loopVisitor; 1089 } 1090 1091 @Override 1092 public FlowControlFinal getFlowControlFinal() { 1093 return null; 1094 } 1095 1096 public void setLabel(String label) { 1097 this.label=label; 1098 } 1099 1100 @Override 1101 public String getLabel() { 1102 return label; 1103 } 1104}