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}