package polyglot.ext.jl.ast; import java.util.*; import polyglot.ast.*; import polyglot.types.*; import polyglot.util.*; import polyglot.visit.*; import polyglot.main.Options; /** * A <code>ConstructorDecl</code> is an immutable representation of a * constructor declaration as part of a class body. */ public class ConstructorDecl_c extends Term_c implements ConstructorDecl { protected Flags flags; protected String name; protected List formals; protected List throwTypes; protected Block body; protected ConstructorInstance ci; public ConstructorDecl_c(Position pos, Flags flags, String name, List formals, List throwTypes, Block body) { super(pos); 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; } /** Get the flags of the constructor. */ public Flags flags() { return this.flags; } /** Set the flags of the constructor. */ public ConstructorDecl flags(Flags flags) { ConstructorDecl_c n = (ConstructorDecl_c) copy(); n.flags = flags; return n; } /** Get the name of the constructor. */ public String name() { return this.name; } /** Set the name of the constructor. */ public ConstructorDecl name(String name) { ConstructorDecl_c n = (ConstructorDecl_c) copy(); n.name = name; return n; } /** Get the formals of the constructor. */ public List formals() { return Collections.unmodifiableList(this.formals); } /** Set the formals of the constructor. */ public ConstructorDecl formals(List formals) { ConstructorDecl_c n = (ConstructorDecl_c) copy(); n.formals = TypedList.copyAndCheck(formals, Formal.class, true); return n; } /** Get the throwTypes of the constructor. */ public List throwTypes() { return Collections.unmodifiableList(this.throwTypes); } /** Set the throwTypes of the constructor. */ public ConstructorDecl throwTypes(List throwTypes) { ConstructorDecl_c n = (ConstructorDecl_c) copy(); n.throwTypes = TypedList.copyAndCheck(throwTypes, TypeNode.class, true); return n; } /** Get the body of the constructor. */ public Block body() { return this.body; } /** Set the body of the constructor. */ public CodeDecl body(Block body) { ConstructorDecl_c n = (ConstructorDecl_c) copy(); n.body = body; return n; } /** Get the constructorInstance of the constructor. */ public ConstructorInstance constructorInstance() { return ci; } /** Get the procedureInstance of the constructor. */ public ProcedureInstance procedureInstance() { return ci; } public CodeInstance codeInstance() { return procedureInstance(); } /** Set the constructorInstance of the constructor. */ public ConstructorDecl constructorInstance(ConstructorInstance ci) { ConstructorDecl_c n = (ConstructorDecl_c) copy(); n.ci = ci; return n; } /** Reconstruct the constructor. */ protected ConstructorDecl_c reconstruct(List formals, List throwTypes, Block body) { if (! CollectionUtil.equals(formals, this.formals) || ! CollectionUtil.equals(throwTypes, this.throwTypes) || body != this.body) { ConstructorDecl_c n = (ConstructorDecl_c) copy(); n.formals = TypedList.copyAndCheck(formals, Formal.class, true); n.throwTypes = TypedList.copyAndCheck(throwTypes, TypeNode.class, true); n.body = body; return n; } return this; } /** Visit the children of the constructor. */ public Node visitChildren(NodeVisitor v) { List formals = visitList(this.formals, v); List throwTypes = visitList(this.throwTypes, v); Block body = (Block) visitChild(this.body, v); return reconstruct(formals, throwTypes, body); } public NodeVisitor buildTypesEnter(TypeBuilder tb) throws SemanticException { return tb.pushCode(); } public Node buildTypes(TypeBuilder tb) throws SemanticException { TypeSystem ts = tb.typeSystem(); List l = new ArrayList(formals.size()); for (int i = 0; i < formals.size(); i++) { l.add(ts.unknownType(position())); } List m = new ArrayList(throwTypes().size()); for (int i = 0; i < throwTypes().size(); i++) { m.add(ts.unknownType(position())); } ConstructorInstance ci = ts.constructorInstance(position(), ts.Object(), Flags.NONE, l, m); return constructorInstance(ci); } public NodeVisitor disambiguateEnter(AmbiguityRemover ar) throws SemanticException { if (ar.kind() == AmbiguityRemover.SUPER) { return ar.bypassChildren(this); } else if (ar.kind() == AmbiguityRemover.SIGNATURES) { if (body != null) { return ar.bypass(body); } } return ar; } public Node disambiguate(AmbiguityRemover ar) throws SemanticException { if (ar.kind() == AmbiguityRemover.SIGNATURES) { Context c = ar.context(); TypeSystem ts = ar.typeSystem(); ParsedClassType ct = c.currentClassScope(); ConstructorInstance ci = makeConstructorInstance(ct, ts); return constructorInstance(ci); } return this; } public NodeVisitor addMembersEnter(AddMemberVisitor am) { ParsedClassType ct = am.context().currentClassScope(); ct.addConstructor(ci); return am.bypassChildren(this); } public Context enterScope(Context c) { return c.pushCode(ci); } /** Type check the constructor. */ public Node typeCheck(TypeChecker tc) throws SemanticException { Context c = tc.context(); TypeSystem ts = tc.typeSystem(); ClassType ct = c.currentClass(); if (ct.flags().isInterface()) { throw new SemanticException( "Cannot declare a constructor inside an interface.", position()); } if (ct.isAnonymous()) { throw new SemanticException( "Cannot declare a constructor inside an anonymous class.", position()); } String ctName = ct.name(); if (! ctName.equals(name)) { throw new SemanticException("Constructor name \"" + name + "\" does not match name of containing class \"" + ctName + "\".", position()); } try { ts.checkConstructorFlags(flags()); } catch (SemanticException e) { throw new SemanticException(e.getMessage(), position()); } if (body == null && ! flags().isNative()) { throw new SemanticException("Missing constructor body.", position()); } if (body != null && flags().isNative()) { throw new SemanticException( "A native constructor cannot have a body.", position()); } for (Iterator i = throwTypes().iterator(); i.hasNext(); ) { TypeNode tn = (TypeNode) i.next(); Type t = tn.type(); if (! t.isThrowable()) { throw new SemanticException("Type \"" + t + "\" is not a subclass of \"" + ts.Throwable() + "\".", tn.position()); } } return this; } /** Check exceptions thrown by the constructor. */ public Node exceptionCheck(ExceptionChecker ec) throws SemanticException { TypeSystem ts = ec.typeSystem(); SubtypeSet s = (SubtypeSet) ec.throwsSet(); for (Iterator i = s.iterator(); i.hasNext(); ) { Type t = (Type) i.next(); boolean throwDeclared = false; if (! t.isUncheckedException()) { for (Iterator j = throwTypes().iterator(); j.hasNext(); ) { TypeNode tn = (TypeNode) j.next(); Type tj = tn.type(); if (ts.isSubtype(t, tj)) { throwDeclared = true; break; } } if (! throwDeclared) { ec.throwsSet().clear(); Position pos = ec.exceptionPosition(t); throw new SemanticException("The exception \"" + t + "\" must either be caught or declared to be thrown.", pos==null?position():pos); } } } ec.throwsSet().clear(); return super.exceptionCheck(ec); } public String toString() { return flags.translate() + name + "(...)"; } /** Write the constructor to an output file. */ public void prettyPrintHeader(CodeWriter w, PrettyPrinter tr) { w.begin(0); w.write(flags().translate()); w.write(name); w.write("("); w.begin(0); for (Iterator i = formals.iterator(); i.hasNext(); ) { Formal f = (Formal) i.next(); print(f, w, tr); if (i.hasNext()) { w.write(","); w.allowBreak(0, " "); } } w.end(); w.write(")"); if (! throwTypes().isEmpty()) { w.allowBreak(6); w.write("throws "); for (Iterator i = throwTypes().iterator(); i.hasNext(); ) { TypeNode tn = (TypeNode) i.next(); print(tn, w, tr); if (i.hasNext()) { w.write(","); w.allowBreak(4, " "); } } } w.end(); } 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(); } } protected ConstructorInstance makeConstructorInstance(ClassType ct, TypeSystem ts) throws SemanticException { List argTypes = new LinkedList(); List excTypes = new LinkedList(); for (Iterator i = formals.iterator(); i.hasNext(); ) { Formal f = (Formal) i.next(); argTypes.add(f.declType()); } for (Iterator i = throwTypes().iterator(); i.hasNext(); ) { TypeNode tn = (TypeNode) i.next(); excTypes.add(tn.type()); } return ts.constructorInstance(position(), ct, flags, argTypes, excTypes); } /** * Return the first (sub)term performed when evaluating this * term. */ public Term entry() { return listEntry(formals(), (body()==null? this : body().entry())); } /** * Visit this term in evaluation order. */ public List acceptCFG(CFGBuilder v, List succs) { if (body() == null) { v.visitCFGList(formals(), this); } else { v.visitCFGList(formals(), body().entry()); v.visitCFG(body(), this); } return succs; } }