/*
* 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.Iterator;
import java.util.List;
import polyglot.types.*;
import polyglot.util.*;
import polyglot.visit.*;
import x10.errors.Errors;
import x10.types.constants.ConstantValue;
/**
* 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<Expr> elements;
public ArrayInit_c(Position pos, List<Expr> elements) {
super(pos);
assert(elements != null);
this.elements = TypedList.copyAndCheck(elements, Expr.class, true);
}
/** Get the elements of the initializer. */
public List<Expr> elements() {
return this.elements;
}
/** Set the elements of the initializer. */
public ArrayInit elements(List<Expr> 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<Expr> elements) {
if (! CollectionUtil.allEqual(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<Expr> elements = visitList(this.elements, v);
return reconstruct(elements);
}
/** Type check the initializer. */
public Node typeCheck(ContextVisitor tc) {
TypeSystem ts = tc.typeSystem();
Type type = null;
for (Expr e : elements) {
if (type == null) {
type = e.type();
}
else {
try {
type = ts.leastCommonAncestor(type, e.type(), tc.context());
} catch (SemanticException e1) {
// Leave type unchanged
}
}
}
if (type == null) {
return type(ts.Null());
}
else {
return type(ts.arrayOf(type));
}
}
public void typeCheckElements(ContextVisitor tc, Type lhsType) {
TypeSystem ts = tc.typeSystem();
if (! lhsType.isArray()) {
Errors.issue(tc.job(),
new SemanticException("Cannot initialize " + lhsType + " with " + type + ".", position()));
}
// Check if we can assign each individual element.
Type t = lhsType.toArray().base();
for (Iterator<Expr> i = elements.iterator(); i.hasNext(); ) {
Expr e = (Expr) i.next();
Type s = e.type();
if (e instanceof ArrayInit) {
((ArrayInit) e).typeCheckElements(tc, t);
continue;
}
if (! ts.isImplicitCastValid(s, t, tc.context()) &&
! ts.typeEquals(s, t, tc.context()) &&
! ts.numericConversionValid(t, ConstantValue.toJavaObject(e.constantValue()), tc.context())) {
Errors.issue(tc.job(),
new SemanticException("Cannot assign " + s + " to " + t + ".", e.position()),
this);
}
}
}
public String toString() {
return "{ ... }";
}
/** Write the initializer to an output file. */
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
w.write("{ ");
for (Iterator<Expr> i = elements.iterator(); i.hasNext(); ) {
Expr e = i.next();
print(e, w, tr);
if (i.hasNext()) {
w.write(",");
w.allowBreak(0, " ");
}
}
w.write(" }");
}
public Term firstChild() {
return listChild(elements, null);
}
public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) {
v.visitCFGList(elements, this, EXIT);
return succs;
}
}