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.runtime.type.scope.Undefined;
022import lucee.runtime.util.NumberIterator;
023import lucee.transformer.bytecode.BytecodeContext;
024import lucee.transformer.bytecode.BytecodeException;
025import lucee.transformer.bytecode.Statement;
026import lucee.transformer.bytecode.cast.CastInt;
027import lucee.transformer.bytecode.expression.Expression;
028import lucee.transformer.bytecode.literal.LitString;
029import lucee.transformer.bytecode.util.Types;
030import lucee.transformer.bytecode.visitor.DecisionIntVisitor;
031import lucee.transformer.bytecode.visitor.NotVisitor;
032import lucee.transformer.bytecode.visitor.OnFinally;
033import lucee.transformer.bytecode.visitor.ParseBodyVisitor;
034import lucee.transformer.bytecode.visitor.TryFinallyVisitor;
035import lucee.transformer.bytecode.visitor.WhileVisitor;
036
037import org.objectweb.asm.Label;
038import org.objectweb.asm.Opcodes;
039import org.objectweb.asm.Type;
040import org.objectweb.asm.commons.GeneratorAdapter;
041import org.objectweb.asm.commons.Method;
042
043public class TagGroupUtil {
044        
045
046        // Undefined us()
047        public static final Type UNDEFINED = Type.getType(Undefined.class);
048        public static final Method US = new Method(
049                        "us",
050                        UNDEFINED,
051                        new Type[]{});
052
053        // void addQuery(Query coll)
054        public static final Method ADD_QUERY = new Method(
055                        "addQuery",
056                        Types.VOID,
057                        new Type[]{Types.QUERY});
058
059        // void removeQuery()
060        public static final Method REMOVE_QUERY = new Method(
061                        "removeQuery",
062                        Types.VOID,
063                        new Type[]{});
064
065        
066        // int getRecordcount()
067        public static final Method GET_RECORDCOUNT = new Method(
068                        "getRecordcount",
069                        Types.INT_VALUE,
070                        new Type[]{});
071
072        // double range(double number, double from)
073        public static final Method RANGE = new Method(
074                        "range",
075                        Types.INT_VALUE,
076                        new Type[]{Types.INT_VALUE,Types.INT_VALUE});
077
078        public static final Type NUMBER_ITERATOR = Type.getType(NumberIterator.class);
079
080        // NumberIterator load(double from, double to, double max) 
081        public static final Method LOAD_MAX = new Method(
082                        "loadMax",
083                        NUMBER_ITERATOR,
084                        new Type[]{Types.INT_VALUE,Types.INT_VALUE,Types.INT_VALUE});
085
086        public static final Method LOAD_END = new Method(
087                        "loadEnd",
088                        NUMBER_ITERATOR,
089                        new Type[]{Types.INT_VALUE,Types.INT_VALUE,Types.INT_VALUE});
090
091
092        // NumberIterator load(double from, double to, double max) 
093        public static final Method LOAD_2 = new Method(
094                        "load",
095                        NUMBER_ITERATOR,
096                        new Type[]{Types.INT_VALUE,Types.INT_VALUE});
097        
098
099        // NumberIterator load(NumberIterator ni, Query query, String groupName, boolean caseSensitive)
100        public static final Method LOAD_5 = new Method(
101                        "load",
102                        NUMBER_ITERATOR,
103                        new Type[]{Types.PAGE_CONTEXT, NUMBER_ITERATOR,Types.QUERY,Types.STRING,Types.BOOLEAN_VALUE});
104
105        // boolean isValid()
106        /*public static final Method IS_VALID_0 = new Method(
107                        "isValid",
108                        Types.BOOLEAN_VALUE,
109                        new Type[]{});*/
110        
111        public static final Method IS_VALID_1 = new Method(
112                        "isValid",
113                        Types.BOOLEAN_VALUE,
114                        new Type[]{Types.INT_VALUE});
115
116        // int current()
117        public static final Method CURRENT = new Method(
118                        "current",
119                        Types.INT_VALUE,
120                        new Type[]{});
121
122        // void release(NumberIterator ni)
123        public static final Method REALEASE = new Method(
124                        "release",
125                        Types.VOID,
126                        new Type[]{NUMBER_ITERATOR});
127
128        // void setCurrent(int current)
129        public static final Method SET_CURRENT = new Method(
130                        "setCurrent",
131                        Types.VOID,
132                        new Type[]{Types.INT_VALUE});
133        
134
135        // void reset()
136        public static final Method RESET = new Method(
137                        "reset",
138                        Types.VOID,
139                        new Type[]{Types.INT_VALUE});
140
141        // int first()
142        public static final Method FIRST = new Method(
143                        "first",
144                        Types.INT_VALUE,
145                        new Type[]{});
146        public static final Method GET_ID = new Method(
147                        "getId",
148                        Types.INT_VALUE,
149                        new Type[]{});
150
151
152        
153        
154        public static void writeOutTypeQuery(final TagGroup tag, BytecodeContext bc) throws BytecodeException {
155                final GeneratorAdapter adapter = bc.getAdapter();
156
157                tag.setNumberIterator(adapter.newLocal(NUMBER_ITERATOR));
158                boolean isOutput=tag.getType()==TagGroup.TAG_OUTPUT;
159                ParseBodyVisitor pbv=isOutput?new ParseBodyVisitor():null;
160                if(isOutput)pbv.visitBegin(bc);
161                        
162                
163                // Query query=pc.getQuery(@query);
164                tag.setQuery(adapter.newLocal(Types.QUERY));
165                adapter.loadArg(0);
166                Expression val = tag.getAttribute("query").getValue();
167                val.writeOut(bc, Expression.MODE_REF);
168                if(val instanceof LitString)
169                        adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_QUERY_STRING);
170                else
171                        adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_QUERY_OBJ);
172                
173                adapter.storeLocal(tag.getQuery());
174                
175                
176                tag.setPID(adapter.newLocal(Types.INT_VALUE));
177                adapter.loadArg(0);
178                adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID);
179                adapter.storeLocal(tag.getPID());
180                
181
182                
183                // int startAt=query.getCurrentrow();
184                final int startAt=adapter.newLocal(Types.INT_VALUE);
185                adapter.loadLocal(tag.getQuery());
186                
187                adapter.loadLocal(tag.getPID());
188                //adapter.loadArg(0);
189                //adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID);
190                adapter.invokeInterface(Types.QUERY, TagLoop.GET_CURRENTROW_1);
191                
192                adapter.storeLocal(startAt);
193                
194                
195                
196                // if(query.getRecordcount()>0) {
197                DecisionIntVisitor div=new DecisionIntVisitor();
198                div.visitBegin();
199                        adapter.loadLocal(tag.getQuery());
200                        adapter.invokeInterface(Types.QUERY, GET_RECORDCOUNT);
201                div.visitGT();
202                        adapter.push(0);
203                div.visitEnd(bc);
204                Label ifRecCount=new Label();
205                adapter.ifZCmp(Opcodes.IFEQ, ifRecCount);
206                        
207                        // startrow
208                        int from = adapter.newLocal(Types.INT_VALUE);
209                        Attribute attrStartRow = tag.getAttribute("startrow");
210                        if(attrStartRow!=null){
211                                // NumberRange.range(@startrow,1)
212                                //attrStartRow.getValue().writeOut(bc, Expression.MODE_VALUE);
213                                CastInt.toExprInt(attrStartRow.getValue()).writeOut(bc, Expression.MODE_VALUE);
214                                //adapter.visitInsn(Opcodes.D2I);
215                                adapter.push(1);
216                                adapter.invokeStatic(Types.NUMBER_RANGE, RANGE);
217                                //adapter.visitInsn(Opcodes.D2I);
218                        }
219                        else {
220                                adapter.push(1);
221                        }
222                        adapter.storeLocal(from);
223                        
224                        // numberIterator
225                        
226                        
227                        adapter.loadLocal(from);
228                        adapter.loadLocal(tag.getQuery());
229                        adapter.invokeInterface(Types.QUERY, GET_RECORDCOUNT);
230                        //adapter.visitInsn(Opcodes.I2D);
231                        
232                        Attribute attrMaxRow = tag.getAttribute("maxrows");
233                        Attribute attrEndRow = tag.getAttribute("endrow");
234                        if(attrMaxRow!=null) {
235                                CastInt.toExprInt(attrMaxRow.getValue()).writeOut(bc, Expression.MODE_VALUE);
236                                adapter.invokeStatic(NUMBER_ITERATOR, LOAD_MAX);
237                        }
238                        else if(attrEndRow!=null) {
239                                CastInt.toExprInt(attrEndRow.getValue()).writeOut(bc, Expression.MODE_VALUE);
240                                adapter.invokeStatic(NUMBER_ITERATOR, LOAD_END);
241                        }
242                        else {
243                                adapter.invokeStatic(NUMBER_ITERATOR, LOAD_2);
244                        }
245                        adapter.storeLocal(tag.getNumberIterator());
246                        
247                        // Group
248                        Attribute attrGroup = tag.getAttribute("group");
249                        Attribute attrGroupCS = tag.getAttribute("groupcasesensitive");
250                        tag.setGroup(adapter.newLocal(Types.STRING));
251                        final int groupCaseSensitive=adapter.newLocal(Types.BOOLEAN_VALUE);
252                        if(attrGroup!=null)     {
253                                attrGroup.getValue().writeOut(bc, Expression.MODE_REF);
254                                adapter.storeLocal(tag.getGroup());
255                                
256                                if(attrGroupCS!=null)   attrGroupCS.getValue().writeOut(bc, Expression.MODE_VALUE);
257                                else                                    adapter.push(false);
258                                adapter.storeLocal(groupCaseSensitive);
259                        }
260                        
261                        // pc.us().addQuery(query);
262                        adapter.loadArg(0);
263                        adapter.invokeVirtual(Types.PAGE_CONTEXT, US);
264                        adapter.loadLocal(tag.getQuery());
265                        adapter.invokeInterface(UNDEFINED, ADD_QUERY);
266                        
267                        // current
268                        final int current=adapter.newLocal(Types.INT_VALUE);
269                        adapter.loadLocal(from);
270                        adapter.push(1);
271                        adapter.visitInsn(Opcodes.ISUB);
272                        adapter.storeLocal(current);
273                        
274                        
275                        // Try
276                        TryFinallyVisitor tfv=new TryFinallyVisitor(new OnFinally() {
277                                public void _writeOut(BytecodeContext bc) {
278                                        // query.reset();
279                                        
280                                        // query.go(startAt);
281                                        adapter.loadLocal(tag.getQuery());
282                                        adapter.loadLocal(startAt);
283                                        
284                                        adapter.loadLocal(tag.getPID());
285                                        //adapter.loadArg(0);
286                                        //adapter.invokeVirtual(Types.PAGE_CONTEXT, TagLoop.GET_ID);
287                                        adapter.invokeInterface(Types.QUERY, TagLoop.GO);
288                                        adapter.pop();
289                                        
290                                        
291                                        
292                                        
293                                        // pc.us().removeQuery();
294                                        adapter.loadArg(0);
295                                        adapter.invokeVirtual(Types.PAGE_CONTEXT, US);
296                                        adapter.invokeInterface(UNDEFINED, REMOVE_QUERY);
297                                        
298                                // NumberIterator.release(ni);
299                                        adapter.loadLocal(tag.getNumberIterator());
300                                        adapter.invokeStatic(NUMBER_ITERATOR, REALEASE);
301                                }
302                        },null);
303                        tfv.visitTryBegin(bc);
304                                WhileVisitor wv = new WhileVisitor();
305                                if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); 
306                                wv.visitBeforeExpression(bc);
307                                        
308                                        //while(ni.isValid()) {
309                                        adapter.loadLocal(tag.getNumberIterator());
310                                        adapter.loadLocal(current);
311                                        adapter.push(1);
312                                        adapter.visitInsn(Opcodes.IADD);
313                                        adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1);
314                                        
315                                wv.visitAfterExpressionBeforeBody(bc);
316                                
317                                        // if(!query.go(ni.current()))break; 
318                                        adapter.loadLocal(tag.getQuery());
319                                        adapter.loadLocal(tag.getNumberIterator());
320                                        adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
321                                        
322                                        adapter.loadLocal(tag.getPID());
323                                        adapter.invokeInterface(Types.QUERY, TagLoop.GO);
324                                        
325                                        NotVisitor.visitNot(bc);
326                                        Label _if=new Label();
327                                        adapter.ifZCmp(Opcodes.IFEQ, _if);
328                                                wv.visitBreak(bc);
329                                        adapter.visitLabel(_if);
330                                        
331                                        if(attrGroup!=null) {
332                                                // NumberIterator oldNi=numberIterator;
333                                                int oldNi=adapter.newLocal(NUMBER_ITERATOR);
334                                                adapter.loadLocal(tag.getNumberIterator());
335                                                adapter.storeLocal(oldNi);
336                                                
337                                                // numberIterator=NumberIterator.load(ni,query,group,grp_case);
338                                                adapter.loadArg(0);
339                                                adapter.loadLocal(tag.getNumberIterator());
340                                                adapter.loadLocal(tag.getQuery());
341                                                adapter.loadLocal(tag.getGroup());
342                                                adapter.loadLocal(groupCaseSensitive);
343                                                adapter.invokeStatic(NUMBER_ITERATOR, LOAD_5);
344                                                adapter.storeLocal(tag.getNumberIterator());
345                                                
346                                                // current=oldNi.current();
347                                                adapter.loadLocal(oldNi);
348                                                adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
349                                                adapter.storeLocal(current);
350                                                
351                                                tag.getBody().writeOut(bc);
352                                                
353                                                //tmp(adapter,current);
354                                                
355                                                // NumberIterator.release(ni);
356                                                adapter.loadLocal(tag.getNumberIterator());
357                                                adapter.invokeStatic(NUMBER_ITERATOR, REALEASE);
358                                                
359                                                // numberIterator=oldNi;
360                                                adapter.loadLocal(oldNi);
361                                                adapter.storeLocal(tag.getNumberIterator());
362                                        }
363                                        else {
364                                                // current=ni.current();
365                                                adapter.loadLocal(tag.getNumberIterator());
366                                                adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
367                                                adapter.storeLocal(current);
368                                                
369                                                tag.getBody().writeOut(bc);
370                                        }
371
372                                        // ni.setCurrent(current+1);
373                                        /*adapter.loadLocal(tag.getNumberIterator());
374                                        adapter.loadLocal(current);
375                                        adapter.push(1);
376                                        adapter.visitInsn(Opcodes.IADD);
377                                        adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/
378                        
379                                wv.visitAfterBody(bc,tag.getEnd());
380                        
381                                tfv.visitTryEnd(bc);
382
383                adapter.visitLabel(ifRecCount);
384                
385
386                if(isOutput)pbv.visitEnd(bc);
387        }
388        
389        
390
391        public static void writeOutTypeGroup(TagGroup tag,BytecodeContext bc) throws BytecodeException {
392                GeneratorAdapter adapter = bc.getAdapter();
393                boolean isOutput=tag.getType()==TagGroup.TAG_OUTPUT;
394                ParseBodyVisitor pbv=isOutput?new ParseBodyVisitor():null;
395                if(isOutput)pbv.visitBegin(bc);
396                
397                // Group
398                Attribute attrGroup = tag.getAttribute("group");
399                tag.setGroup(adapter.newLocal(Types.STRING));
400                attrGroup.getValue().writeOut(bc, Expression.MODE_REF);
401                adapter.storeLocal(tag.getGroup());
402                
403                // Group Case Sensitve
404                Attribute attrGroupCS = tag.getAttribute("groupcasesensitive");
405                int groupCaseSensitive=adapter.newLocal(Types.BOOLEAN_VALUE);
406                if(attrGroupCS!=null)   attrGroupCS.getValue().writeOut(bc, Expression.MODE_VALUE);
407                else                                    adapter.push(true);
408                adapter.storeLocal(groupCaseSensitive);
409                
410                TagGroup parent = getParentTagGroupQuery(tag,tag.getType());
411                tag.setNumberIterator(parent.getNumberIterator());
412                tag.setQuery(parent.getQuery());
413                //queryImpl = parent.getQueryImpl();
414                
415                // current
416                int current=adapter.newLocal(Types.INT_VALUE);
417                adapter.loadLocal(tag.getNumberIterator());
418                adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
419                adapter.storeLocal(current);
420                
421                
422                // current
423                int icurrent=adapter.newLocal(Types.INT_VALUE);
424                
425                adapter.loadLocal(current);
426                adapter.push(1);
427                adapter.visitInsn(Opcodes.ISUB);
428                adapter.storeLocal(icurrent);
429                
430                
431                WhileVisitor wv = new WhileVisitor();
432                if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); 
433                wv.visitBeforeExpression(bc);
434                        
435                        //while(ni.isValid()) {
436                        adapter.loadLocal(tag.getNumberIterator());
437                        adapter.loadLocal(icurrent);
438                        adapter.push(1);
439                        adapter.visitInsn(Opcodes.IADD);
440                        adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1);
441                        
442                wv.visitAfterExpressionBeforeBody(bc);
443                
444                        // if(!query.go(ni.current()))break; 
445                        adapter.loadLocal(tag.getQuery());
446                        adapter.loadLocal(tag.getNumberIterator());
447                        adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
448                        
449                        adapter.loadArg(0);
450                        adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID);
451                        adapter.invokeInterface(Types.QUERY, TagLoop.GO);
452                        
453                        NotVisitor.visitNot(bc);
454                        Label _if=new Label();
455                        adapter.ifZCmp(Opcodes.IFEQ, _if);
456                                wv.visitBreak(bc);
457                        adapter.visitLabel(_if);
458                
459                        // NumberIterator oldNi=numberIterator;
460                        int oldNi=adapter.newLocal(NUMBER_ITERATOR);
461                        
462                        adapter.loadLocal(tag.getNumberIterator());
463                        adapter.storeLocal(oldNi);
464                        
465                        // numberIterator=NumberIterator.load(ni,query,group,grp_case);
466                        adapter.loadArg(0);
467                        adapter.loadLocal(tag.getNumberIterator());
468                        adapter.loadLocal(tag.getQuery());
469                        adapter.loadLocal(tag.getGroup());
470                        adapter.loadLocal(groupCaseSensitive);
471                        adapter.invokeStatic(NUMBER_ITERATOR, LOAD_5);
472                        adapter.storeLocal(tag.getNumberIterator());
473                        
474                        // current=oldNi.current();
475                        adapter.loadLocal(oldNi);
476                        adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
477                        adapter.storeLocal(icurrent);
478                        
479                        tag.getBody().writeOut(bc);
480                        
481                        //tmp(adapter,current);
482                        
483                        
484                        // NumberIterator.release(ni);
485                        adapter.loadLocal(tag.getNumberIterator());
486                        adapter.invokeStatic(NUMBER_ITERATOR, REALEASE);
487                        
488                        // numberIterator=oldNi;
489                        adapter.loadLocal(oldNi);
490                        adapter.storeLocal(tag.getNumberIterator());
491                
492                        // ni.setCurrent(current+1);
493                        /*adapter.loadLocal(tag.getNumberIterator());
494                        adapter.loadLocal(icurrent);
495                        adapter.push(1);
496                        adapter.visitInsn(Opcodes.IADD);
497                        adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);
498                        */
499                wv.visitAfterBody(bc,tag.getEnd());
500        
501
502                //query.go(ni.current(),pc.getId())
503                resetCurrentrow(adapter,tag,current);
504                
505                // ni.first();
506                adapter.loadLocal(tag.getNumberIterator());
507                adapter.invokeVirtual(NUMBER_ITERATOR, FIRST);
508                adapter.pop();
509                
510
511                if(isOutput)pbv.visitEnd(bc);
512        }
513        
514        public static void writeOutTypeInnerGroup(TagGroup tag,BytecodeContext bc) throws BytecodeException {
515                GeneratorAdapter adapter = bc.getAdapter();
516
517                TagGroup parent = getParentTagGroupQuery(tag,tag.getType());
518                tag.setNumberIterator(parent.getNumberIterator());
519                tag.setQuery(parent.getQuery());
520                //queryImpl = parent.getQueryImpl();
521                
522                int current=adapter.newLocal(Types.INT_VALUE);
523                adapter.loadLocal(tag.getNumberIterator());
524                adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
525                adapter.storeLocal(current);
526                
527                
528                // inner current
529                int icurrent=adapter.newLocal(Types.INT_VALUE);
530                
531                adapter.loadLocal(current);
532                adapter.push(1);
533                adapter.visitInsn(Opcodes.ISUB);
534                adapter.storeLocal(icurrent);
535                
536                
537                
538                WhileVisitor wv = new WhileVisitor();
539                if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); 
540                wv.visitBeforeExpression(bc);
541                        
542                        //while(ni.isValid()) {
543                        adapter.loadLocal(tag.getNumberIterator());
544                        adapter.loadLocal(icurrent);
545                        adapter.push(1);
546                        adapter.visitInsn(Opcodes.IADD);
547                        adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1);
548                        
549                wv.visitAfterExpressionBeforeBody(bc);
550                
551                        // if(!query.go(ni.current()))break; 
552                        
553                        adapter.loadLocal(tag.getQuery());
554                        adapter.loadLocal(tag.getNumberIterator());
555                        adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
556                        
557                        adapter.loadArg(0);
558                        adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID);
559                        adapter.invokeInterface(Types.QUERY, TagLoop.GO);
560                        
561                        /*OLD
562                        adapter.invokeInterface(Types.QUERY, TagLoop.GO_1);
563                        */
564                        NotVisitor.visitNot(bc);
565                        Label _if=new Label();
566                        adapter.ifZCmp(Opcodes.IFEQ, _if);
567                                wv.visitBreak(bc);
568                        adapter.visitLabel(_if);
569                
570                        // current=ni.current();
571                        adapter.loadLocal(tag.getNumberIterator());
572                        adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
573                        adapter.storeLocal(icurrent);
574                        
575                        tag.getBody().writeOut(bc);
576                        
577                        // ni.setCurrent(current+1);
578                        /*adapter.loadLocal(tag.getNumberIterator());
579                        adapter.loadLocal(icurrent);
580                        adapter.push(1);
581                        adapter.visitInsn(Opcodes.IADD);
582                        adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/
583        
584                wv.visitAfterBody(bc,tag.getEnd());
585        
586                resetCurrentrow(adapter,tag,current);
587                
588                
589                // ni.first();
590                adapter.loadLocal(tag.getNumberIterator());
591                adapter.invokeVirtual(NUMBER_ITERATOR, FIRST);
592                adapter.pop();
593        }
594        
595        public static void writeOutTypeInnerQuery(TagGroup tag,BytecodeContext bc) throws BytecodeException {
596                GeneratorAdapter adapter = bc.getAdapter();
597                //if(tr ue)return ;
598                TagGroup parent = getParentTagGroupQuery(tag,tag.getType());
599                tag.setNumberIterator(parent.getNumberIterator());
600                tag.setQuery(parent.getQuery());
601                tag.setPID(parent.getPID());
602                //queryImpl = parent.getQueryImpl();
603                
604                //int currentOuter=ni.current();
605                int current=adapter.newLocal(Types.INT_VALUE);
606                adapter.loadLocal(tag.getNumberIterator());
607                adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
608                adapter.storeLocal(current);
609                
610                // current
611                int icurrent=adapter.newLocal(Types.INT_VALUE);
612                
613                adapter.loadLocal(current);
614                adapter.push(1);
615                adapter.visitInsn(Opcodes.ISUB);
616                adapter.storeLocal(icurrent);
617                
618                
619                WhileVisitor wv = new WhileVisitor();
620                if(tag instanceof TagLoop) ((TagLoop)tag).setLoopVisitor(wv); 
621                wv.visitBeforeExpression(bc);
622                        
623                        //while(ni.isValid()) {
624                        adapter.loadLocal(tag.getNumberIterator());
625                        adapter.loadLocal(icurrent);
626                        adapter.push(1);
627                        adapter.visitInsn(Opcodes.IADD);
628                        adapter.invokeVirtual(NUMBER_ITERATOR, IS_VALID_1);
629                        
630                wv.visitAfterExpressionBeforeBody(bc);
631                
632                        // if(!query.go(ni.current()))break; 
633                        adapter.loadLocal(tag.getQuery());
634                        adapter.loadLocal(tag.getNumberIterator());
635                        adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
636                        
637                        adapter.loadLocal(tag.getPID());
638                        adapter.invokeInterface(Types.QUERY, TagLoop.GO);
639                        
640                        NotVisitor.visitNot(bc);
641                        Label _if=new Label();
642                        adapter.ifZCmp(Opcodes.IFEQ, _if);
643                                wv.visitBreak(bc);
644                        adapter.visitLabel(_if);
645                
646                        // current=ni.current();
647                        adapter.loadLocal(tag.getNumberIterator());
648                        adapter.invokeVirtual(NUMBER_ITERATOR, CURRENT);
649                        adapter.storeLocal(icurrent);
650                        
651                        tag.getBody().writeOut(bc);
652                        
653                        // ni.setCurrent(current+1);
654                        /*adapter.loadLocal(tag.getNumberIterator());
655                        adapter.loadLocal(icurrent);
656                        adapter.push(1);
657                        adapter.visitInsn(Opcodes.IADD);
658                        adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);*/
659        
660                wv.visitAfterBody(bc,tag.getEnd());
661        
662                
663                // ni.setCurrent(currentOuter);
664                adapter.loadLocal(tag.getNumberIterator());
665                adapter.loadLocal(current);
666                adapter.invokeVirtual(NUMBER_ITERATOR, SET_CURRENT);
667                
668                adapter.loadLocal(tag.getQuery());
669                adapter.loadLocal(current);
670                
671                adapter.loadLocal(tag.getPID());
672                //adapter.loadArg(0);
673                //adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID);
674                adapter.invokeInterface(Types.QUERY, TagLoop.GO);
675                adapter.pop();
676                //adapter.pop();
677        }
678        
679        public static TagGroup getParentTagGroupQuery(Statement st, short type) throws BytecodeException {
680                Statement parent=st.getParent();
681                if(parent==null) throw new BytecodeException("there is no parent output with query",null);
682                else if(parent instanceof TagGroup && type==((TagGroup)parent).getType()) {
683                        if(((TagGroup)parent).hasQuery())
684                                return ((TagGroup)parent);
685                }
686                return getParentTagGroupQuery(parent,type);
687        }
688        
689        private static void resetCurrentrow(GeneratorAdapter adapter,TagGroup tg, int current) {
690                //query.go(ni.current(),pc.getId())
691                adapter.loadLocal(tg.getQuery());
692                adapter.loadLocal(current);
693                adapter.loadArg(0);
694                adapter.invokeVirtual(Types.PAGE_CONTEXT, GET_ID);
695                adapter.invokeInterface(Types.QUERY, TagLoop.GO);
696                
697                /* OLD
698                adapter.invokeInterface(Types.QUERY, TagLoop.GO_1);
699                */
700                adapter.pop();
701                
702        }
703
704}