/*
* 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>ConstructorDecl</code> is an immutable representation of a
* constructor declaration as part of a class body.
*/
public abstract class ConstructorDecl_c extends Term_c implements ConstructorDecl
{
protected FlagsNode flags;
protected Id name;
protected List<Formal> formals;
// protected List<TypeNode> throwTypes;
public Block body;
protected ConstructorDef ci;
public ConstructorDecl_c(Position pos, FlagsNode flags, Id name, List<Formal> formals, Block body) {
super(pos);
assert(flags != null && name != null && formals != null); // body may be null
this.flags = flags;
this.name = name;
this.formals = TypedList.copyAndCheck(formals, Formal.class, true);
// this.throwTypes = TypedList.copyAndCheck(throwTypes, TypeNode.class, true);
this.body = body;
}
public List<Def> defs() {
return Collections.<Def>singletonList(ci);
}
public MemberDef memberDef() {
return ci;
}
/** Get the flags of the constructor. */
public FlagsNode flags() {
return this.flags;
}
/** Set the flags of the constructor. */
public ConstructorDecl flags(FlagsNode flags) {
ConstructorDecl_c n = (ConstructorDecl_c) copy();
n.flags = flags;
return n;
}
/** Get the name of the constructor. */
public Id name() {
return this.name;
}
/** Set the name of the constructor. */
public ConstructorDecl name(Id name) {
ConstructorDecl_c n = (ConstructorDecl_c) copy();
n.name = name;
return n;
}
/** Get the formals of the constructor. */
public List<Formal> formals() {
return Collections.unmodifiableList(this.formals);
}
/** Set the formals of the constructor. */
public ConstructorDecl formals(List<Formal> formals) {
ConstructorDecl_c n = (ConstructorDecl_c) copy();
n.formals = TypedList.copyAndCheck(formals, Formal.class, true);
return n;
}
public Term codeBody() {
return this.body;
}
/** Get the body of the constructor. */
public Block body() {
return this.body;
}
/** Set the body of the constructor. */
public CodeBlock body(Block body) {
ConstructorDecl_c n = (ConstructorDecl_c) copy();
n.body = body;
return n;
}
/** Get the constructorInstance of the constructor. */
public ConstructorDef constructorDef() {
return ci;
}
/** Get the procedureInstance of the constructor. */
public ProcedureDef procedureInstance() {
return ci;
}
public CodeDef codeDef() {
return procedureInstance();
}
/** Set the constructorInstance of the constructor. */
public ConstructorDecl constructorDef(ConstructorDef ci) {
if (ci == this.ci) return this;
ConstructorDecl_c n = (ConstructorDecl_c) copy();
n.ci = ci;
return n;
}
/** Reconstruct the constructor. */
protected ConstructorDecl_c reconstruct(FlagsNode flags, Id name, List<Formal> formals, Block body) {
if (flags != this.flags || name != this.name || ! CollectionUtil.allEqual(formals, this.formals) || body != this.body) {
ConstructorDecl_c n = (ConstructorDecl_c) copy();
n.flags = flags;
n.name = name;
n.formals = TypedList.copyAndCheck(formals, Formal.class, true);
n.body = body;
return n;
}
return this;
}
/** Visit the children of the constructor. */
public Node visitChildren(NodeVisitor v) {
ConstructorDecl_c n = (ConstructorDecl_c) visitSignature(v);
Block body = (Block) n.visitChild(n.body, v);
return body == n.body ? n : n.body(body);
}
protected abstract ConstructorDef createConstructorDef(TypeSystem ts, ClassDef ct, Flags flags);
public Context enterScope(Context c) {
return c.pushCode(ci);
}
public Node visitSignature(NodeVisitor v) {
FlagsNode flags = (FlagsNode) this.visitChild(this.flags, v);
Id name = (Id) this.visitChild(this.name, v);
List<Formal> formals = this.visitList(this.formals, v);
return reconstruct(flags, name, formals, this.body);
}
/** Type check the declaration. */
public Node typeCheckBody(Node parent, TypeChecker tc, TypeChecker childtc) {
ConstructorDecl_c n = this;
Block body = (Block) n.visitChild(n.body, childtc);
n = (ConstructorDecl_c) n.body(body);
return n;
}
/** Type check the constructor. */
public Node typeCheck(ContextVisitor tc) {
TypeSystem ts = tc.typeSystem();
return this;
}
public Node conformanceCheck(ContextVisitor tc) {
Context c = tc.context();
TypeSystem ts = tc.typeSystem();
ClassType ct = c.currentClass();
if (ct.flags().isInterface()) {
Errors.issue(tc.job(),
new Errors.CannotDeclareConstructorInInterface(name().position()));
}
if (ct.isAnonymous()) {
Errors.issue(tc.job(),
new Errors.CannotDeclareConstructorInAnonymousClass(name().position()));
}
Name ctName = ct.name();
if (! ctName.equals(name.id())) {
Errors.issue(tc.job(),
new Errors.ConstructorNameDoesNotMatchContainingClassName(name, ctName, name().position()));
}
Flags flags = flags().flags();
try {
ts.checkConstructorFlags(flags);
}
catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
if (body == null && ! flags.isNative()) {
Errors.issue(tc.job(), new Errors.MissingConstructorBody(name().position()));
}
if (body != null && flags.isNative()) {
Errors.issue(tc.job(), new Errors.NativeConstructorCannotHaveABody(name().position()));
}
return this;
}
public abstract String toString();
/** Write the constructor to an output file. */
public abstract void prettyPrintHeader(CodeWriter w, PrettyPrinter tr);
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
prettyPrintHeader(w, tr);
if (body != null) {
printSubStmt(body, w, tr);
}
else {
w.write(";");
}
}
public void dump(CodeWriter w) {
super.dump(w);
if (ci != null) {
w.allowBreak(4, " ");
w.begin(0);
w.write("(instance " + ci + ")");
w.end();
}
}
public Term firstChild() {
return listChild(formals(), body() != null ? body() : null);
}
public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) {
if (body() != null) {
v.visitCFGList(formals(), body(), ENTRY);
v.visitCFG(body(), this, EXIT);
}
else {
v.visitCFGList(formals(), this, EXIT);
}
return succs;
}
}