/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * This file was originally derived from the Polyglot extensible compiler framework. * * (C) Copyright 2000-2007 Polyglot project group, Cornell University * (C) Copyright IBM Corporation 2007-2012. */ package polyglot.ast; import java.util.*; import polyglot.types.*; import polyglot.util.*; import polyglot.visit.*; import x10.errors.Errors; /** * An immutable representation of a Java language <code>for</code> * statement. Contains a statement to be executed and an expression * to be tested indicating whether to reexecute the statement. */ public class For_c extends Loop_c implements For { protected List<ForInit> inits; protected Expr cond; protected List<ForUpdate> iters; protected Stmt body; public For_c(Position pos, List<ForInit> inits, Expr cond, List<ForUpdate> iters, Stmt body) { super(pos); assert(inits != null && iters != null && body != null); // cond may be null, inits and iters may be empty this.inits = TypedList.copyAndCheck(inits, ForInit.class, true); this.cond = cond; this.iters = TypedList.copyAndCheck(iters, ForUpdate.class, true); this.body = body; } /** List of initialization statements */ public List<ForInit> inits() { return Collections.unmodifiableList(this.inits); } /** Set the inits of the statement. */ public For inits(List<ForInit> inits) { For_c n = (For_c) copy(); n.inits = TypedList.copyAndCheck(inits, ForInit.class, true); return n; } /** Loop condition */ public Expr cond() { return this.cond; } /** Set the conditional of the statement. */ public For cond(Expr cond) { For_c n = (For_c) copy(); n.cond = cond; return n; } /** List of iterator expressions. */ public List<ForUpdate> iters() { return Collections.unmodifiableList(this.iters); } /** Set the iterator expressions of the statement. */ public For iters(List<ForUpdate> iters) { For_c n = (For_c) copy(); n.iters = TypedList.copyAndCheck(iters, ForUpdate.class, true); return n; } /** Loop body */ public Stmt body() { return this.body; } /** Set the body of the statement. */ public For body(Stmt body) { For_c n = (For_c) copy(); n.body = body; return n; } /** Reconstruct the statement. */ protected For_c reconstruct(List<ForInit> inits, Expr cond, List<ForUpdate> iters, Stmt body) { if (! CollectionUtil.allEqual(inits, this.inits) || cond != this.cond || ! CollectionUtil.allEqual(iters, this.iters) || body != this.body) { For_c n = (For_c) copy(); n.inits = TypedList.copyAndCheck(inits, ForInit.class, true); n.cond = cond; n.iters = TypedList.copyAndCheck(iters, ForUpdate.class, true); n.body = body; return n; } return this; } /** Visit the children of the statement. */ public Node visitChildren(NodeVisitor v) { List<ForInit> inits = visitList(this.inits, v); Expr cond = (Expr) visitChild(this.cond, v); List<ForUpdate> iters = visitList(this.iters, v); Node body = visitChild(this.body, v); if (body instanceof NodeList) body = ((NodeList) body).toBlock(); return reconstruct(inits, cond, iters, (Stmt) body); } public Context enterScope(Context c) { return c.pushBlock(); } /** Type check the statement. */ public Node typeCheck(ContextVisitor tc) { TypeSystem ts = tc.typeSystem(); // Check that all initializers have the same type. // This should be enforced by the parser, but check again here, // just to be sure. Type t = null; for (ForInit s : inits) { if (s instanceof LocalDecl) { LocalDecl d = (LocalDecl) s; Type dt = d.type().type(); if (t == null) { t = dt; } else if (! t.typeEquals(dt, tc.context())) { throw new InternalCompilerError("Local variable " + "declarations in a for loop initializer must all " + "be the same type, in this case " + t + ", not " + dt + ".", d.position()); } } } if (cond != null && ! ts.isImplicitCastValid(cond.type(), ts.Boolean(), tc.context())) { Errors.issue(tc.job(), new SemanticException("The condition of a for statement must have boolean type.",cond.position()), this); } return this; } /** Write the statement to an output file. */ public void prettyPrint(CodeWriter w, PrettyPrinter tr) { w.write("for ("); w.begin(0); if (inits != null) { boolean first = true; for (ForInit s : inits) { if (!first) { w.write(","); w.allowBreak(2, " "); } printForInit(s, w, tr, first); first = false; } } w.write(";"); w.allowBreak(0); if (cond != null) { printBlock(cond, w, tr); } w.write (";"); w.allowBreak(0); if (iters != null) { for (Iterator<ForUpdate> i = iters.iterator(); i.hasNext();) { ForUpdate s = i.next(); printForUpdate(s, w, tr); if (i.hasNext()) { w.write(","); w.allowBreak(2, " "); } } } w.end(); w.write(")"); printSubStmt(body, w, tr); } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("for ("); String sep = ""; for (ForInit s : inits()) { sb.append(sep); sep = ", "; sb.append(s); } sb.append("; "); if (cond() != null) sb.append(cond()); sb.append("; "); sep = ""; for (ForUpdate s : iters()) { sb.append(sep); sep = ", "; sb.append(s); } sb.append(") "); sb.append(body()); return sb.toString(); } private void printForInit(ForInit s, CodeWriter w, PrettyPrinter tr, boolean printType) { boolean oldSemiColon = tr.appendSemicolon(false); boolean oldPrintType = tr.printType(printType); printBlock(s, w, tr); tr.printType(oldPrintType); tr.appendSemicolon(oldSemiColon); } private void printForUpdate(ForUpdate s, CodeWriter w, PrettyPrinter tr) { boolean oldSemiColon = tr.appendSemicolon(false); printBlock(s, w, tr); tr.appendSemicolon(oldSemiColon); } public Term firstChild() { return listChild(inits, cond != null ? (Term) cond : body); } public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) { v.visitCFGList(inits, cond != null ? (Term) cond : body, ENTRY); if (cond != null) { if (condIsConstantTrue()) { v.visitCFG(cond, body, ENTRY); } else { v.visitCFG(cond, FlowGraph.EDGE_KEY_TRUE, body, ENTRY, FlowGraph.EDGE_KEY_FALSE, this, EXIT); } } v.push(this).visitCFG(body, continueTarget(), ENTRY); v.visitCFGList(iters, cond != null ? (Term) cond : body, ENTRY); return succs; } public Term continueTarget() { return listChild(iters, cond != null ? (Term) cond : body); } }