001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     * All rights reserved.
008     */
009    
010    aspect EnhancedForToBytecode {
011      // Code generation
012      syn lazy int EnhancedForStmt.cond_label() = hostType().constantPool().newLabel();
013      syn lazy int EnhancedForStmt.update_label() = hostType().constantPool().newLabel();
014      syn lazy int EnhancedForStmt.end_label() = hostType().constantPool().newLabel();
015    
016      syn lazy int EnhancedForStmt.extraLocalIndex() = localNum();
017      eq EnhancedForStmt.getVariableDeclaration().localNum() = localNum() + (getExpr().type().isArrayDecl() ? 2 : 1);
018      eq EnhancedForStmt.getStmt().localNum() = getVariableDeclaration().localNum() + getVariableDeclaration().type().size();
019    
020       // EnhancedForStmt can be both break and continue target
021      eq EnhancedForStmt.break_label() = end_label();
022      eq EnhancedForStmt.continue_label() = update_label();
023    
024      public void EnhancedForStmt.createBCode(CodeGeneration gen) {
025        if(getExpr().type().isArrayDecl()) {
026          getExpr().createBCode(gen);
027          gen.emitStoreReference(extraLocalIndex());
028          IntegerLiteral.push(gen, 0);
029          gen.emit(Bytecode.ISTORE).add(extraLocalIndex()+1);
030          gen.addLabel(cond_label());
031          gen.emit(Bytecode.ILOAD).add(extraLocalIndex()+1);
032          gen.emitLoadReference(extraLocalIndex());
033          gen.emit(Bytecode.ARRAYLENGTH);
034          gen.emitCompare(Bytecode.IF_ICMPGE, end_label());
035          gen.emitLoadReference(extraLocalIndex());
036          gen.emit(Bytecode.ILOAD).add(extraLocalIndex()+1);
037          gen.emit(getExpr().type().componentType().arrayLoad());
038          getExpr().type().componentType().emitCastTo(gen, getVariableDeclaration().type());
039          getVariableDeclaration().type().emitStoreLocal(gen, getVariableDeclaration().localNum());
040          getStmt().createBCode(gen);
041          gen.addLabel(update_label());
042          gen.emit(Bytecode.IINC).add(extraLocalIndex()+1).add(1);
043          gen.emitGoto(cond_label());
044          gen.addLabel(end_label());
045        }
046        else {
047          getExpr().createBCode(gen);
048          iteratorMethod().emitInvokeMethod(gen, lookupType("java.lang", "Iterable"));
049          gen.emitStoreReference(extraLocalIndex());
050          gen.addLabel(cond_label());
051          gen.emitLoadReference(extraLocalIndex());
052          hasNextMethod().emitInvokeMethod(gen, lookupType("java.util", "Iterator"));
053          gen.emitCompare(Bytecode.IFEQ, end_label());
054          gen.emitLoadReference(extraLocalIndex());
055          nextMethod().emitInvokeMethod(gen, lookupType("java.util", "Iterator"));
056          VariableDeclaration obj = getVariableDeclaration();
057          if (!obj.type().boxed().isUnknown()) {
058            gen.emitCheckCast(obj.type().boxed());
059            obj.type().boxed().emitCastTo(gen, obj.type());
060            obj.type().emitStoreLocal(gen, obj.localNum());
061          } else {
062            gen.emitCheckCast(obj.type());
063            gen.emitStoreReference(obj.localNum());
064          }
065          getStmt().createBCode(gen);
066          gen.addLabel(update_label()); 
067          gen.emitGoto(cond_label());
068          gen.addLabel(end_label());
069        }
070      }
071    
072      private MethodDecl EnhancedForStmt.iteratorMethod() {
073        TypeDecl typeDecl = lookupType("java.lang", "Iterable");
074                for (Iterator iter = typeDecl.memberMethods("iterator").iterator(); iter.hasNext();) {
075                        MethodDecl m = (MethodDecl)iter.next();
076                        if (m.getNumParameter() == 0) {
077                                return m;
078          }
079        }
080        throw new Error("Could not find java.lang.Iterable.iterator()");
081      }
082      private MethodDecl EnhancedForStmt.hasNextMethod() {
083        TypeDecl typeDecl = lookupType("java.util", "Iterator");
084                for (Iterator iter = typeDecl.memberMethods("hasNext").iterator(); iter.hasNext();) {
085                        MethodDecl m = (MethodDecl)iter.next();
086                        if (m.getNumParameter() == 0) {
087                                return m;
088          }
089        }
090        throw new Error("Could not find java.util.Collection.hasNext()");
091      }
092      private MethodDecl EnhancedForStmt.nextMethod() {
093        TypeDecl typeDecl = lookupType("java.util", "Iterator");
094                for (Iterator iter = typeDecl.memberMethods("next").iterator(); iter.hasNext();) {
095                        MethodDecl m = (MethodDecl)iter.next();
096                        if (m.getNumParameter() == 0) {
097                                return m;
098          }
099        }
100        throw new Error("Could not find java.util.Collection.next()");
101      }
102    }