package polyglot.ext.jl.ast; import java.util.Collections; import java.util.Iterator; import java.util.List; import polyglot.ast.*; import polyglot.main.Report; import polyglot.types.*; import polyglot.util.CodeWriter; import polyglot.util.CollectionUtil; import polyglot.util.Position; import polyglot.util.TypedList; import polyglot.visit.*; import polyglot.main.Options; /** * A <code>ClassDecl</code> is the definition of a class, abstract class, * or interface. It may be a public or other top-level class, or an inner * named class, or an anonymous class. */ public class ClassDecl_c extends Term_c implements ClassDecl { protected Flags flags; protected String name; protected TypeNode superClass; protected List interfaces; protected ClassBody body; protected ParsedClassType type; public ClassDecl_c(Position pos, Flags flags, String name, TypeNode superClass, List interfaces, ClassBody body) { super(pos); this.flags = flags; this.name = name; this.superClass = superClass; this.interfaces = TypedList.copyAndCheck(interfaces, TypeNode.class, true); this.body = body; } public Named declaration() { return type(); } public ParsedClassType type() { return type; } public ClassDecl type(ParsedClassType type) { ClassDecl_c n = (ClassDecl_c) copy(); n.type = type; return n; } public Flags flags() { return this.flags; } public ClassDecl flags(Flags flags) { ClassDecl_c n = (ClassDecl_c) copy(); n.flags = flags; return n; } public String name() { return this.name; } public ClassDecl name(String name) { ClassDecl_c n = (ClassDecl_c) copy(); n.name = name; return n; } public TypeNode superClass() { return this.superClass; } public ClassDecl superClass(TypeNode superClass) { ClassDecl_c n = (ClassDecl_c) copy(); n.superClass = superClass; return n; } public List interfaces() { return this.interfaces; } public ClassDecl interfaces(List interfaces) { ClassDecl_c n = (ClassDecl_c) copy(); n.interfaces = TypedList.copyAndCheck(interfaces, TypeNode.class, true); return n; } public ClassBody body() { return this.body; } public ClassDecl body(ClassBody body) { ClassDecl_c n = (ClassDecl_c) copy(); n.body = body; return n; } protected ClassDecl_c reconstruct(TypeNode superClass, List interfaces, ClassBody body) { if (superClass != this.superClass || ! CollectionUtil.equals(interfaces, this.interfaces) || body != this.body) { ClassDecl_c n = (ClassDecl_c) copy(); n.superClass = superClass; n.interfaces = TypedList.copyAndCheck(interfaces, TypeNode.class, true); n.body = body; return n; } return this; } /** * Return the first (sub)term performed when evaluating this * term. */ public Term entry() { return this.body().entry(); } /** * Visit this term in evaluation order. */ public List acceptCFG(CFGBuilder v, List succs) { v.visitCFG(this.body(), this); return succs; } public Node visitChildren(NodeVisitor v) { TypeNode superClass = (TypeNode) visitChild(this.superClass, v); List interfaces = visitList(this.interfaces, v); ClassBody body = (ClassBody) visitChild(this.body, v); return reconstruct(superClass, interfaces, body); } public NodeVisitor buildTypesEnter(TypeBuilder tb) throws SemanticException { tb = tb.pushClass(position(), flags, name); ParsedClassType ct = tb.currentClass(); // Member classes of interfaces are implicitly public and static. if (ct.isMember() && ct.outer().flags().isInterface()) { ct.flags(ct.flags().Public().Static()); } // Member interfaces are implicitly static. if (ct.isMember() && ct.flags().isInterface()) { ct.flags(ct.flags().Static()); } // Interfaces are implicitly abstract. if (ct.flags().isInterface()) { ct.flags(ct.flags().Abstract()); } return tb; } public Node buildTypes(TypeBuilder tb) throws SemanticException { ParsedClassType type = tb.currentClass(); if (type != null) { return type(type).flags(type.flags()); } return this; } public Context enterScope(Node child, Context c) { if (child == this.body) { TypeSystem ts = c.typeSystem(); c = c.pushClass(type, ts.staticTarget(type).toClass()); } return super.enterScope(child, c); } public NodeVisitor disambiguateEnter(AmbiguityRemover ar) throws SemanticException { if (ar.kind() == AmbiguityRemover.SUPER) { return ar.bypass(body); } return ar; } protected void disambiguateSuperType(AmbiguityRemover ar) throws SemanticException { TypeSystem ts = ar.typeSystem(); if (this.superClass != null) { Type t = this.superClass.type(); if (! t.isCanonical()) { throw new SemanticException("Could not disambiguate super" + " class of " + type + ".", superClass.position()); } if (! t.isClass() || t.toClass().flags().isInterface()) { throw new SemanticException("Super class " + t + " of " + type + " is not a class.", superClass.position()); } if (Report.should_report(Report.types, 3)) Report.report(3, "setting super type of " + this.type + " to " + t); this.type.superType(t); ts.checkCycles(t.toReference()); } else if (ts.Object() != this.type && !ts.Object().fullName().equals(this.type.fullName())) { // the supertype was not specified, and the type is not the same // as ts.Object() (which is typically java.lang.Object) // As such, the default supertype is ts.Object(). this.type.superType(ts.Object()); } else { // the type is the same as ts.Object(), so it has no supertype. this.type.superType(null); } } public Node disambiguate(AmbiguityRemover ar) throws SemanticException { if (ar.kind() == AmbiguityRemover.SIGNATURES) { // make sure that the inStaticContext flag of the class is // correct Context ctxt = ar.context(); this.type().inStaticContext(ctxt.inStaticContext()); } if (ar.kind() == AmbiguityRemover.SIGNATURES) { // make sure that this class has the correct dependencies // recorded for its super classes and interfaces. ar.addSuperDependencies(this.type()); } if (ar.kind() != AmbiguityRemover.SUPER) { return this; } TypeSystem ts = ar.typeSystem(); if (Report.should_report(Report.types, 2)) Report.report(2, "Cleaning " + type + "."); disambiguateSuperType(ar); for (Iterator i = this.interfaces.iterator(); i.hasNext(); ) { TypeNode tn = (TypeNode) i.next(); Type t = tn.type(); if (! t.isCanonical()) { throw new SemanticException("Could not disambiguate super" + " class of " + type + ".", tn.position()); } if (! t.isClass() || ! t.toClass().flags().isInterface()) { throw new SemanticException("Interface " + t + " of " + type + " is not an interface.", tn.position()); } if (Report.should_report(Report.types, 3)) Report.report(3, "adding interface of " + this.type + " to " + t); if (!this.type.interfaces().contains(t)) this.type.addInterface(t); ts.checkCycles(t.toReference()); } return this; } public Node addMembers(AddMemberVisitor tc) throws SemanticException { TypeSystem ts = tc.typeSystem(); NodeFactory nf = tc.nodeFactory(); return addDefaultConstructorIfNeeded(ts, nf); } protected Node addDefaultConstructorIfNeeded(TypeSystem ts, NodeFactory nf) { if (defaultConstructorNeeded()) { return addDefaultConstructor(ts, nf); } return this; } protected boolean defaultConstructorNeeded() { if (flags().isInterface()) { return false; } return type().constructors().isEmpty(); } protected Node addDefaultConstructor(TypeSystem ts, NodeFactory nf) { ConstructorInstance ci = ts.defaultConstructor(position(), this.type); this.type.addConstructor(ci); Block block = null; if (this.type.superType() instanceof ClassType) { ConstructorInstance sci = ts.defaultConstructor(position(), (ClassType) this.type.superType()); ConstructorCall cc = nf.SuperCall(position(), Collections.EMPTY_LIST); cc = cc.constructorInstance(sci); block = nf.Block(position(), cc); } else { block = nf.Block(position()); } ConstructorDecl cd = nf.ConstructorDecl(position(), Flags.PUBLIC, name, Collections.EMPTY_LIST, Collections.EMPTY_LIST, block); cd = (ConstructorDecl) cd.constructorInstance(ci); return body(body.addMember(cd)); } public Node typeCheck(TypeChecker tc) throws SemanticException { if (this.type().isNested() && (this.type() instanceof Named)) { // The class cannot have the same simple name as any enclosing class. ClassType container = this.type.outer(); while (container instanceof Named) { if (!container.isAnonymous()) { String name = ((Named) container).name(); if (name.equals(this.name)) { throw new SemanticException("Cannot declare member " + "class \"" + this.type + "\" inside class with the " + "same name.", position()); } } if (container.isNested()) { container = container.outer(); } else { break; } } if (this.type().isLocal()) { // a local class name cannot be redeclared within the same // method, constructor or initializer, and within its scope Context ctxt = tc.context(); if (ctxt.isLocal(this.name)) { // something with the same name was declared locally. // (but not in an enclosing class) Named nm = ctxt.find(this.name); if (nm instanceof Type) { Type another = (Type)nm; if (another.isClass() && another.toClass().isLocal()) { throw new SemanticException("Cannot declare local " + "class \"" + this.type + "\" within the same " + "method, constructor or initializer as another " + "local class of the same name.", position()); } } } } } // check that inner classes do not declare member interfaces if (type().isMember() && flags().isInterface() && type().outer().isInnerClass()) { // it's a member interface in an inner class. throw new SemanticException("Inner classes cannot declare " + "member interfaces.", this.position()); } // Make sure that static members are not declared inside inner classes if (type().isMember() && type().flags().isStatic() && type().outer().isInnerClass()) { throw new SemanticException("Inner classes cannot declare static " + "member classes.", position()); } if (type.superType() != null) { if (! type.superType().isClass()) { throw new SemanticException("Cannot extend non-class \"" + type.superType() + "\".", position()); } if (type.superType().toClass().flags().isFinal()) { throw new SemanticException("Cannot extend final class \"" + type.superType() + "\".", position()); } } TypeSystem ts = tc.typeSystem(); try { if (type.isTopLevel()) { ts.checkTopLevelClassFlags(type.flags()); } if (type.isMember()) { ts.checkMemberClassFlags(type.flags()); } if (type.isLocal()) { ts.checkLocalClassFlags(type.flags()); } } catch (SemanticException e) { throw new SemanticException(e.getMessage(), position()); } // check the class implements all abstract methods that it needs to. ts.checkClassConformance(type); return this; } public String toString() { return flags.clearInterface().translate() + (flags.isInterface() ? "interface " : "class ") + name + " " + body; } public void prettyPrintHeader(CodeWriter w, PrettyPrinter tr) { if (flags.isInterface()) { w.write(flags.clearInterface().clearAbstract().translate()); } else { w.write(flags.translate()); } if (flags.isInterface()) { w.write("interface "); } else { w.write("class "); } w.write(name); if (superClass() != null) { w.write(" extends "); print(superClass(), w, tr); } if (! interfaces.isEmpty()) { if (flags.isInterface()) { w.write(" extends "); } else { w.write(" implements "); } for (Iterator i = interfaces().iterator(); i.hasNext(); ) { TypeNode tn = (TypeNode) i.next(); print(tn, w, tr); if (i.hasNext()) { w.write (", "); } } } w.write(" {"); } public void prettyPrintFooter(CodeWriter w, PrettyPrinter tr) { w.write("}"); w.newline(0); } public void prettyPrint(CodeWriter w, PrettyPrinter tr) { //generate a Java file. prettyPrintHeader(w, tr); print(body(), w, tr); prettyPrintFooter(w, tr); } public void dump(CodeWriter w) { super.dump(w); w.allowBreak(4, " "); w.begin(0); w.write("(name " + name + ")"); w.end(); if (type != null) { w.allowBreak(4, " "); w.begin(0); w.write("(type " + type + ")"); w.end(); } } }