package polyglot.visit;
import java.util.HashMap;
import java.util.Map;
import polyglot.ast.ConstructorCall;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.frontend.Job;
import polyglot.types.ConstructorInstance;
import polyglot.types.Context;
import polyglot.types.SemanticException;
import polyglot.types.TypeSystem;
import polyglot.util.InternalCompilerError;
/** Visitor which ensures that constructor calls are not recursive. */
public class ConstructorCallChecker extends ContextVisitor
{
public ConstructorCallChecker(Job job, TypeSystem ts, NodeFactory nf) {
super(job, ts, nf);
}
protected Map constructorInvocations = new HashMap();
protected NodeVisitor enterCall(Node n) throws SemanticException {
if (n instanceof ConstructorCall) {
ConstructorCall cc = (ConstructorCall)n;
if (cc.kind() == ConstructorCall.THIS) {
// the constructor calls another constructor in the same class
Context ctxt = context();
if (!(ctxt.currentCode() instanceof ConstructorInstance)) {
throw new InternalCompilerError("Constructor call " +
"occurring in a non-constructor.", cc.position());
}
ConstructorInstance srcCI = (ConstructorInstance)ctxt.currentCode();
ConstructorInstance destCI = cc.constructorInstance();
constructorInvocations.put(srcCI, destCI);
while (destCI != null) {
destCI = (ConstructorInstance)constructorInvocations.get(destCI);
if (destCI != null && srcCI.equals(destCI)) {
// loop in the constructor invocations!
throw new SemanticException("Recursive constructor " +
"invocation.", cc.position());
}
}
}
}
return this;
}
}