package polyglot.ext.jl.ast;
import java.util.*;
import polyglot.ast.ClassBody;
import polyglot.ast.ClassDecl;
import polyglot.ast.ClassMember;
import polyglot.ast.Node;
import polyglot.ast.Term;
import polyglot.frontend.Job;
import polyglot.frontend.Pass;
import polyglot.main.Report;
import polyglot.types.*;
import polyglot.util.*;
import polyglot.visit.*;
/**
* A <code>ClassBody</code> represents the body of a class or interface
* declaration or the body of an anonymous class.
*/
public class ClassBody_c extends Term_c implements ClassBody
{
protected List members;
public ClassBody_c(Position pos, List members) {
super(pos);
this.members = TypedList.copyAndCheck(members, ClassMember.class, true);
}
public List members() {
return this.members;
}
public ClassBody members(List members) {
ClassBody_c n = (ClassBody_c) copy();
n.members = TypedList.copyAndCheck(members, ClassMember.class, true);
return n;
}
public ClassBody addMember(ClassMember member) {
ClassBody_c n = (ClassBody_c) copy();
List l = new ArrayList(this.members.size() + 1);
l.addAll(this.members);
l.add(member);
n.members = TypedList.copyAndCheck(l, ClassMember.class, true);
return n;
}
protected ClassBody_c reconstruct(List members) {
if (! CollectionUtil.equals(members, this.members)) {
ClassBody_c n = (ClassBody_c) copy();
n.members = TypedList.copyAndCheck(members,
ClassMember.class, true);
return n;
}
return this;
}
public Node visitChildren(NodeVisitor v) {
List members = visitList(this.members, v);
return reconstruct(members);
}
public NodeVisitor disambiguateEnter(AmbiguityRemover ar) throws SemanticException {
// We can't clean-super any member classes yet until we are finished
// with this class and all at the same nesting level.
// Delay until the clean-sigs pass.
if (ar.kind() == AmbiguityRemover.SUPER ||
ar.kind() == AmbiguityRemover.SIGNATURES) {
return ar.bypassChildren(this);
}
/*
// Skip clean-sigs for member classes; this will be done when we leave
// the node, but only after clean-super is performed.
if (ar.kind() == AmbiguityRemover.SIGNATURES) {
for (Iterator i = members.iterator(); i.hasNext(); ) {
ClassMember n = (ClassMember) i.next();
if (n instanceof ClassDecl) {
ar = (AmbiguityRemover) ar.bypass(n);
}
}
return ar;
}
*/
return ar;
}
public Node disambiguate(AmbiguityRemover ar) throws SemanticException {
// Now we can clean-super on the member classes.
if (ar.kind() == AmbiguityRemover.SIGNATURES) {
List l = new ArrayList(members.size());
Job j = ar.job();
for (Iterator i = members.iterator(); i.hasNext(); ) {
ClassMember n = (ClassMember) i.next();
if (n instanceof ClassDecl) {
Job sj = j.spawn(ar.context(), n,
Pass.CLEAN_SUPER, Pass.CLEAN_SUPER_ALL);
if (! sj.status()) {
if (! sj.reportedErrors()) {
throw new SemanticException("Could not disambiguate " +
"class member.",
n.position());
}
throw new SemanticException();
}
ClassDecl m = (ClassDecl) sj.ast();
l.add(m.visit(ar.visitChildren()));
}
else {
l.add(n.visit(ar.visitChildren()));
}
}
return members(l);
}
return this;
}
public String toString() {
return "{ ... }";
}
protected void duplicateFieldCheck(TypeChecker tc) throws SemanticException {
ClassType type = tc.context().currentClass();
ArrayList l = new ArrayList(type.fields());
for (int i = 0; i < l.size(); i++) {
FieldInstance fi = (FieldInstance) l.get(i);
for (int j = i+1; j < l.size(); j++) {
FieldInstance fj = (FieldInstance) l.get(j);
if (fi.name().equals(fj.name())) {
throw new SemanticException("Duplicate field \"" + fj + "\".", fj.position());
}
}
}
}
protected void duplicateConstructorCheck(TypeChecker tc) throws SemanticException {
ClassType type = tc.context().currentClass();
ArrayList l = new ArrayList(type.constructors());
for (int i = 0; i < l.size(); i++) {
ConstructorInstance ci = (ConstructorInstance) l.get(i);
for (int j = i+1; j < l.size(); j++) {
ConstructorInstance cj = (ConstructorInstance) l.get(j);
if (ci.hasFormals(cj.formalTypes())) {
throw new SemanticException("Duplicate constructor \"" + cj + "\".", cj.position());
}
}
}
}
protected void duplicateMethodCheck(TypeChecker tc) throws SemanticException {
ClassType type = tc.context().currentClass();
TypeSystem ts = tc.typeSystem();
ArrayList l = new ArrayList(type.methods());
for (int i = 0; i < l.size(); i++) {
MethodInstance mi = (MethodInstance) l.get(i);
for (int j = i+1; j < l.size(); j++) {
MethodInstance mj = (MethodInstance) l.get(j);
if (isSameMethod(ts, mi, mj)) {
throw new SemanticException("Duplicate method \"" + mj + "\".", mj.position());
}
}
}
}
protected void duplicateMemberClassCheck(TypeChecker tc) throws SemanticException {
ClassType type = tc.context().currentClass();
TypeSystem ts = tc.typeSystem();
ArrayList l = new ArrayList(type.memberClasses());
for (int i = 0; i < l.size(); i++) {
ClassType mi = (ClassType) l.get(i);
for (int j = i+1; j < l.size(); j++) {
ClassType mj = (ClassType) l.get(j);
if (mi.name().equals(mj.name())) {
throw new SemanticException("Duplicate member type \"" + mj + "\".", mj.position());
}
}
}
}
protected boolean isSameMethod(TypeSystem ts, MethodInstance mi,
MethodInstance mj) {
return mi.isSameMethod(mj);
}
public Node typeCheck(TypeChecker tc) throws SemanticException {
duplicateFieldCheck(tc);
duplicateConstructorCheck(tc);
duplicateMethodCheck(tc);
duplicateMemberClassCheck(tc);
return this;
}
public NodeVisitor exceptionCheckEnter(ExceptionChecker ec) throws SemanticException {
return ec.pushNew();
}
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
if (!members.isEmpty()) {
w.newline(4);
w.begin(0);
for (Iterator i = members.iterator(); i.hasNext(); ) {
ClassMember member = (ClassMember) i.next();
printBlock(member, w, tr);
if (i.hasNext()) {
w.newline(0);
w.newline(0);
}
}
w.end();
w.newline(0);
}
}
/**
* Return the first (sub)term performed when evaluating this
* term.
*/
public Term entry() {
// Do _not_ visit class members.
return this;
}
/**
* Visit this term in evaluation order.
*/
public List acceptCFG(CFGBuilder v, List succs) {
return succs;
}
protected static final Collection TOPICS =
CollectionUtil.list(Report.types, Report.context);
}