package polyglot.ext.jl.ast; import polyglot.ast.*; import polyglot.types.*; import polyglot.util.*; import polyglot.visit.*; import polyglot.main.Options; import java.util.*; /** * An <code>ArrayInit</code> is an immutable representation of * an array initializer, such as { 3, 1, { 4, 1, 5 } }. Note that * the elements of these array may be expressions of any type (e.g., * <code>Call</code>). */ public class ArrayInit_c extends Expr_c implements ArrayInit { protected List elements; public ArrayInit_c(Position pos, List elements) { super(pos); this.elements = TypedList.copyAndCheck(elements, Expr.class, true); } /** Get the elements of the initializer. */ public List elements() { return this.elements; } /** Set the elements of the initializer. */ public ArrayInit elements(List elements) { ArrayInit_c n = (ArrayInit_c) copy(); n.elements = TypedList.copyAndCheck(elements, Expr.class, true); return n; } /** Reconstruct the initializer. */ protected ArrayInit_c reconstruct(List elements) { if (! CollectionUtil.equals(elements, this.elements)) { ArrayInit_c n = (ArrayInit_c) copy(); n.elements = TypedList.copyAndCheck(elements, Expr.class, true); return n; } return this; } /** Visit the children of the initializer. */ public Node visitChildren(NodeVisitor v) { List elements = visitList(this.elements, v); return reconstruct(elements); } /** Type check the initializer. */ public Node typeCheck(TypeChecker tc) throws SemanticException { TypeSystem ts = tc.typeSystem(); Type type = null; for (Iterator i = elements.iterator(); i.hasNext(); ) { Expr e = (Expr) i.next(); if (type == null) { type = e.type(); } else { type = ts.leastCommonAncestor(type, e.type()); } } if (type == null) { return type(ts.Null()); } else { return type(ts.arrayOf(type)); } } public Type childExpectedType(Expr child, AscriptionVisitor av) { if (elements.isEmpty()) { return child.type(); } Type t = av.toType(); if (! t.isArray()) { throw new InternalCompilerError("Type of array initializer must " + "be an array.", position()); } t = t.toArray().base(); TypeSystem ts = av.typeSystem(); for (Iterator i = elements.iterator(); i.hasNext(); ) { Expr e = (Expr) i.next(); if (e == child) { if (ts.numericConversionValid(t, e.constantValue())) { return child.type(); } else { return t; } } } return child.type(); } public void typeCheckElements(Type lhsType) throws SemanticException { TypeSystem ts = lhsType.typeSystem(); if (! lhsType.isArray()) { throw new SemanticException("Cannot initialize " + lhsType + " with " + type + ".", position()); } // Check if we can assign each individual element. Type t = lhsType.toArray().base(); for (Iterator i = elements.iterator(); i.hasNext(); ) { Expr e = (Expr) i.next(); Type s = e.type(); if (e instanceof ArrayInit) { ((ArrayInit) e).typeCheckElements(t); continue; } if (! ts.isImplicitCastValid(s, t) && ! ts.equals(s, t) && ! ts.numericConversionValid(t, e.constantValue())) { throw new SemanticException("Cannot assign " + s + " to " + t + ".", e.position()); } } } public String toString() { return "{ ... }"; } /** Write the initializer to an output file. */ public void prettyPrint(CodeWriter w, PrettyPrinter tr) { w.write("{ "); for (Iterator i = elements.iterator(); i.hasNext(); ) { Expr e = (Expr) i.next(); print(e, w, tr); if (i.hasNext()) { w.write(", "); } } w.write(" }"); } public Term entry() { return listEntry(elements, this); } public List acceptCFG(CFGBuilder v, List succs) { v.visitCFGList(elements, this); return succs; } }