/* * 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; /** * A <code>NewArray</code> represents a new array expression such as <code>new * File[8][] { null }</code>. It consists of an element type (e.g., * <code>File</code>), a list of dimension expressions (e.g., 8), 0 or more * additional dimensions (e.g., 1 for []), and an array initializer. The * dimensions of the array initializer must equal the number of additional "[]" * dimensions. */ public class NewArray_c extends Expr_c implements NewArray { protected TypeNode baseType; protected List<Expr> dims; protected int addDims; protected ArrayInit init; public NewArray_c(Position pos, TypeNode baseType, List<Expr> dims, int addDims, ArrayInit init) { super(pos); assert(baseType != null && dims != null); // init may be null assert(addDims >= 0); assert(! dims.isEmpty() || init != null); // dims may be empty only if there is an initializer assert(addDims > 0 || init == null); // init may be non-null only if addDims > 0 assert(dims.size() + addDims > 0); // must allocate something this.baseType = baseType; this.dims = TypedList.copyAndCheck(dims, Expr.class, true); this.addDims = addDims; this.init = init; } /** Get the base type node of the expression. */ public TypeNode baseType() { return this.baseType; } /** Set the base type node of the expression. */ public NewArray baseType(TypeNode baseType) { NewArray_c n = (NewArray_c) copy(); n.baseType = baseType; return n; } /** Get the dimension expressions of the expression. */ public List<Expr> dims() { return Collections.unmodifiableList(this.dims); } /** Set the dimension expressions of the expression. */ public NewArray dims(List<Expr> dims) { NewArray_c n = (NewArray_c) copy(); n.dims = TypedList.copyAndCheck(dims, Expr.class, true); return n; } /** Get the number of dimensions of the expression. */ public int numDims() { return dims.size() + addDims; } /** Get the number of additional dimensions of the expression. */ public int additionalDims() { return this.addDims; } /** Set the number of additional dimensions of the expression. */ public NewArray additionalDims(int addDims) { NewArray_c n = (NewArray_c) copy(); n.addDims = addDims; return n; } /** Get the initializer of the expression. */ public ArrayInit init() { return this.init; } /** Set the initializer of the expression. */ public NewArray init(ArrayInit init) { NewArray_c n = (NewArray_c) copy(); n.init = init; return n; } /** Reconstruct the expression. */ protected NewArray_c reconstruct(TypeNode baseType, List<Expr> dims, ArrayInit init) { if (baseType != this.baseType || ! CollectionUtil.allEqual(dims, this.dims) || init != this.init) { NewArray_c n = (NewArray_c) copy(); n.baseType = baseType; n.dims = TypedList.copyAndCheck(dims, Expr.class, true); n.init = init; return n; } return this; } /** Visit the children of the expression. */ public Node visitChildren(NodeVisitor v) { TypeNode baseType = (TypeNode) visitChild(this.baseType, v); List<Expr> dims = visitList(this.dims, v); ArrayInit init = (ArrayInit) visitChild(this.init, v); return reconstruct(baseType, dims, init); } /** Type check the expression. */ public Node typeCheck(ContextVisitor tc) { TypeSystem ts = tc.typeSystem(); for (Expr expr : dims) { if (! ts.isImplicitCastValid(expr.type(), ts.Int(), tc.context())) { Errors.issue(tc.job(), new SemanticException("Array dimension must be an integer.", expr.position()), this); } } Type type = ts.arrayOf(baseType.type(), dims.size() + addDims); if (init != null) { init.typeCheckElements(tc, type); } return type(type); } public String toString() { return "new " + baseType + "[...]"; } /** Write the expression to an output file. */ public void prettyPrint(CodeWriter w, PrettyPrinter tr) { w.write("new "); print(baseType, w, tr); for (Expr e : dims) { w.write("["); printBlock(e, w, tr); w.write("]"); } for (int i = 0; i < addDims; i++) { w.write("[]"); } if (init != null) { w.write(" "); print(init, w, tr); } } public Term firstChild() { return baseType; } public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) { if (init != null) { v.visitCFG(baseType, listChild(dims, init), ENTRY); v.visitCFGList(dims, init, ENTRY); v.visitCFG(init, this, EXIT); } else { v.visitCFG(baseType, listChild(dims, null), ENTRY); v.visitCFGList(dims, this, EXIT); } return succs; } public List<Type> throwTypes(TypeSystem ts) { if (dims != null && !dims.isEmpty()) { // if dimension expressions are given, then // a NegativeArraySizeException may be thrown. try { return CollectionUtil.list(ts.forName(QName.make("java.lang.NegativeArraySizeException"))); } catch (SemanticException e) { throw new InternalCompilerError("Cannot find class java.lang.NegativeArraySizeException", e); } } return Collections.<Type>emptyList(); } }