package polyglot.ext.jl.ast; import java.util.Iterator; import java.util.List; import polyglot.ast.*; import polyglot.types.*; import polyglot.util.CodeWriter; import polyglot.util.Position; import polyglot.util.SubtypeSet; import polyglot.visit.*; /** * An <code>Initializer</code> is an immutable representation of an * initializer block in a Java class (which appears outside of any * method). Such a block is executed before the code for any of the * constructors. Such a block can optionally be static, in which case * it is executed when the class is loaded. */ public class Initializer_c extends Term_c implements Initializer { protected Flags flags; protected Block body; protected InitializerInstance ii; public Initializer_c(Position pos, Flags flags, Block body) { super(pos); this.flags = flags; this.body = body; } /** Get the flags of the initializer. */ public Flags flags() { return this.flags; } /** Set the flags of the initializer. */ public Initializer flags(Flags flags) { Initializer_c n = (Initializer_c) copy(); n.flags = flags; return n; } /** Get the initializer instance of the initializer. */ public InitializerInstance initializerInstance() { return ii; } public CodeInstance codeInstance() { return initializerInstance(); } /** Set the initializer instance of the initializer. */ public Initializer initializerInstance(InitializerInstance ii) { Initializer_c n = (Initializer_c) copy(); n.ii = ii; return n; } /** Get the body of the initializer. */ public Block body() { return this.body; } /** Set the body of the initializer. */ public CodeDecl body(Block body) { Initializer_c n = (Initializer_c) copy(); n.body = body; return n; } /** Reconstruct the initializer. */ protected Initializer_c reconstruct(Block body) { if (body != this.body) { Initializer_c n = (Initializer_c) copy(); n.body = body; return n; } return this; } /** Visit the children of the initializer. */ public Node visitChildren(NodeVisitor v) { Block body = (Block) visitChild(this.body, v); return reconstruct(body); } public Context enterScope(Context c) { return c.pushCode(ii); } public NodeVisitor buildTypesEnter(TypeBuilder tb) throws SemanticException { return tb.pushCode(); } /** * Return the first (sub)term performed when evaluating this * term. */ public Term entry() { return this.body().entry(); } public List acceptCFG(CFGBuilder v, List succs) { v.visitCFG(this.body(), this); return succs; } /** Build type objects for the method. */ public Node buildTypes(TypeBuilder tb) throws SemanticException { TypeSystem ts = tb.typeSystem(); ClassType ct = tb.currentClass(); InitializerInstance ii = ts.initializerInstance(position(), ct, flags); return initializerInstance(ii); } public NodeVisitor addMembersEnter(AddMemberVisitor am) { // do not add members for the children of this node. return am.bypassChildren(this); } public NodeVisitor disambiguateEnter(AmbiguityRemover ar) throws SemanticException { // Do not visit body on the clean-super and clean-signatures passes. if (ar.kind() == AmbiguityRemover.SUPER || ar.kind() == AmbiguityRemover.SIGNATURES) { return ar.bypassChildren(this); } return ar; } /** Type check the initializer. */ public Node typeCheck(TypeChecker tc) throws SemanticException { TypeSystem ts = tc.typeSystem(); try { ts.checkInitializerFlags(flags()); } catch (SemanticException e) { throw new SemanticException(e.getMessage(), position()); } // check that inner classes do not declare static initializers if (flags().isStatic() && initializerInstance().container().toClass().isInnerClass()) { // it's a static initializer in an inner class. throw new SemanticException("Inner classes cannot declare " + "static initializers.", this.position()); } return this; } /** Check exceptions thrown by the initializer. */ 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(); if (! t.isUncheckedException()) { // TODO: This should agree with Java Language Spec 2nd Ed. 8.6 // An instance initializer of a named class may not throw // a checked exception unless that exception or one of its // superclasses is explicitly declared in the throws clause // of each contructor or its class, and the class has at least // one explicitly declared constructor. if (initializerInstance().flags().isStatic()) { throw new SemanticException( "A static initializer block may not throw a " + t + ".", ec.exceptionPosition(t)); } if (!initializerInstance().container().toClass().isAnonymous()) { // XXX should only throw this if it is not common to all // declared constructors, and there is at least one // declared constructor. throw new SemanticException( "An instance initializer block may not throw a " + t + ".", ec.exceptionPosition(t)); } } } return super.exceptionCheck(ec); } /** Write the initializer to an output file. */ public void prettyPrint(CodeWriter w, PrettyPrinter tr) { w.write(flags.translate()); printBlock(body, w, tr); } public void dump(CodeWriter w) { super.dump(w); if (ii != null) { w.allowBreak(4, " "); w.begin(0); w.write("(instance " + ii + ")"); w.end(); } } public String toString() { return flags.translate() + "{ ... }"; } }