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