package carray.ast;

import polyglot.ast.ArrayTypeNode_c;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.TypeNode;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.util.Position;
import polyglot.util.SerialVersionUID;
import polyglot.visit.AmbiguityRemover;
import polyglot.visit.TypeBuilder;
import carray.types.CArrayTypeSystem;

/**
 * A {@code ConstArrayTypeNode} is a type node for a non-canonical
 * const array type.
 */
public class ConstArrayTypeNode_c extends ArrayTypeNode_c implements
        ConstArrayTypeNode {
    private static final long serialVersionUID = SerialVersionUID.generate();

    public ConstArrayTypeNode_c(Position pos, TypeNode base) {
        super(pos, base);
    }

    @Override
    public Node buildTypes(TypeBuilder tb) throws SemanticException {
        // Ask the type system to create a type object for constant array
        // of the base type.  At this point, the base type might not be
        // canonical.  The disambiguation phase will canonicalize the base type.
        CArrayTypeSystem ts = (CArrayTypeSystem) tb.typeSystem();
        return type(ts.constArrayOf(position(), base().type()));
    }

    @Override
    public Node disambiguate(AmbiguityRemover ar) throws SemanticException {
        Type baseType = base.type();
        if (!baseType.isCanonical()) {
            // It is possible that the base type is still ambiguous because
            // additional disambiguation passes are necessary to resolve more
            // supertypes and method signatures.  In this case, there is nothing
            // to do for now; this node will be visited and this method called
            // again in a subsequent disambiguation pass.
            return this;
        }

        // Otherwise, the base type is canonical, so we are ready to turn this
        // ambiguous type node into a canonical type node.  Replace the base
        // type of the underlying type object with the canonical base.
        CArrayTypeSystem ts = (CArrayTypeSystem) ar.typeSystem();
        NodeFactory nf = ar.nodeFactory();
        return nf.CanonicalTypeNode(position(),
                                    ts.constArrayOf(position(), baseType));
    }

    @Override
    public String toString() {
        String result = base.toString();
        if (base instanceof ConstArrayTypeNode) {
            // If base is also a ConstArrayTypeNode, the keyword "const" would
            // have been displayed, so just add additional dimension here.
            result += "[]";
        }
        else result += " const[]";
        return result;
    }
}
