/* * 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.Collections; import java.util.List; import polyglot.types.*; import polyglot.util.*; import polyglot.visit.*; import x10.errors.Errors; /** * 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 FlagsNode flags; protected Block body; protected InitializerDef ii; public Initializer_c(Position pos, FlagsNode flags, Block body) { super(pos); assert(flags != null && body != null); this.flags = flags; this.body = body; } public List<Def> defs() { return Collections.<Def>singletonList(ii); } public MemberDef memberDef() { return ii; } /** Get the flags of the initializer. */ public FlagsNode flags() { return this.flags; } /** Set the flags of the initializer. */ public Initializer flags(FlagsNode flags) { Initializer_c n = (Initializer_c) copy(); n.flags = flags; return n; } /** Get the initializer instance of the initializer. */ public InitializerDef initializerDef() { return ii; } public CodeDef codeDef() { return initializerDef(); } /** Set the initializer instance of the initializer. */ public Initializer initializerDef(InitializerDef ii) { if (ii == this.ii) return this; Initializer_c n = (Initializer_c) copy(); n.ii = ii; return n; } public Term codeBody() { return this.body; } /** Get the body of the initializer. */ public Block body() { return this.body; } /** Set the body of the initializer. */ public CodeBlock body(Block body) { Initializer_c n = (Initializer_c) copy(); n.body = body; return n; } /** Reconstruct the initializer. */ protected Initializer_c reconstruct(FlagsNode flags, Block body) { if (flags != this.flags || body != this.body) { Initializer_c n = (Initializer_c) copy(); n.flags = flags; n.body = body; return n; } return this; } /** Visit the children of the initializer. */ public Node visitChildren(NodeVisitor v) { FlagsNode flags = (FlagsNode) visitChild(this.flags, v); Block body = (Block) visitChild(this.body, v); return reconstruct(flags, body); } public Context enterScope(Context c) { return c.pushCode(ii); } /** * Return the first (sub)term performed when evaluating this * term. */ public Term firstChild() { return body(); } public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) { v.visitCFG(body(), this, EXIT); return succs; } public Node buildTypesOverride(TypeBuilder tb) { TypeSystem ts = tb.typeSystem(); ClassDef ct = tb.currentClass(); assert ct != null; Flags flags = this.flags.flags(); InitializerDef ii = createInitializerDef(ts, ct, flags); TypeBuilder tbChk = tb.pushCode(ii); final TypeBuilder tbx = tb; final InitializerDef mix = ii; Initializer_c n = (Initializer_c) this.visitSignature(new NodeVisitor() { public Node override(Node n) { return Initializer_c.this.visitChild(n, tbx.pushCode(mix)); } }); Block body = (Block) n.visitChild(n.body, tbChk); n = (Initializer_c) n.body(body); n = (Initializer_c) n.initializerDef(ii); return n; } protected InitializerDef createInitializerDef(TypeSystem ts, ClassDef ct, Flags flags) { InitializerDef ii = ts.initializerDef(position(), Types.ref(ct.asType()), flags); return ii; } public Node visitSignature(NodeVisitor v) { return this; } /** Type check the declaration. */ public Node typeCheckBody(Node parent, TypeChecker tc, TypeChecker childtc) { TypeSystem ts = tc.typeSystem(); Initializer_c n; Block body = this.body; body = (Block) this.visitChild(this.body, childtc); n = reconstruct(this.flags, body); n = (Initializer_c) tc.leave(parent, this, n, childtc); return n; } /** Type check the initializer. */ public Node typeCheck(ContextVisitor tc) { TypeSystem ts = tc.typeSystem(); Flags flags = this.flags.flags(); try { ts.checkInitializerFlags(flags); } catch (SemanticException e) { Errors.issue(tc.job(), new SemanticException(e.getMessage(), position())); } // check that inner classes do not declare static initializers if (flags.isStatic() && initializerDef().container().get().toClass().isInnerClass()) { // it's a static initializer in an inner class. Errors.issue(tc.job(), new SemanticException("Inner classes cannot declare static initializers.", position())); } return this; } public NodeVisitor exceptionCheckEnter(ExceptionChecker ec) { /* if (initializerDef().flags().isStatic()) { return ec.push(new ExceptionChecker.CodeTypeReporter("A static initializer block")); } if (!initializerDef().container().get().toClass().isAnonymous()) { ec = ec.push(new ExceptionChecker.CodeTypeReporter("An instance initializer block")); // 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. SubtypeSet allowed = null; Type throwable = ec.typeSystem().Throwable(); ClassType container = initializerDef().container().get().toClass(); for (ConstructorInstance ci : container.constructors()) { if (allowed == null) { allowed = new SubtypeSet(throwable); allowed.addAll(ci.throwTypes()); } else { // intersect allowed with ci.throwTypes() SubtypeSet other = new SubtypeSet(throwable); other.addAll(ci.throwTypes()); SubtypeSet inter = new SubtypeSet(throwable); for (Type t : allowed) { if (other.contains(t)) { // t or a supertype is thrown by other. inter.add(t); } } for (Type t : other) { if (allowed.contains(t)) { // t or a supertype is thrown by the allowed. inter.add(t); } } allowed = inter; } } // allowed is now an intersection of the throw types of all // constructors ec = ec.push(allowed); return ec; }*/ return ec.push(); } /** Write the initializer to an output file. */ public void prettyPrint(CodeWriter w, PrettyPrinter tr) { w.begin(0); print(flags, w, tr); print(body, w, tr); w.end(); } 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.flags().translate() + "{ ... }"; } }