75 lines
2.1 KiB
Java
75 lines
2.1 KiB
Java
package cd.frontend.semantic;
|
|
|
|
import cd.frontend.semantic.SemanticFailure.Cause;
|
|
import cd.ir.Ast.ClassDecl;
|
|
import cd.ir.Ast.MethodDecl;
|
|
import cd.ir.AstVisitor;
|
|
import cd.ir.Symbol.ClassSymbol;
|
|
import cd.ir.Symbol.MethodSymbol;
|
|
import cd.ir.Symbol.VariableSymbol;
|
|
import cd.util.Pair;
|
|
|
|
import java.util.HashSet;
|
|
import java.util.Set;
|
|
|
|
public class InheritanceChecker extends AstVisitor<Void, Void> {
|
|
|
|
ClassSymbol classSym;
|
|
|
|
@Override
|
|
public Void classDecl(ClassDecl ast, Void arg) {
|
|
classSym = ast.sym;
|
|
|
|
// check for cycles in the inheritance hierarchy:
|
|
Set<ClassSymbol> supers = new HashSet<ClassSymbol>();
|
|
ClassSymbol sc = classSym.superClass;
|
|
supers.add(classSym);
|
|
while (sc != null) {
|
|
if (supers.contains(sc))
|
|
throw new SemanticFailure(
|
|
Cause.CIRCULAR_INHERITANCE,
|
|
"Class %s has %s as a superclass twice",
|
|
ast.name, sc.name);
|
|
supers.add(sc);
|
|
sc = sc.superClass;
|
|
}
|
|
|
|
this.visitChildren(ast, null);
|
|
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public Void methodDecl(MethodDecl ast, Void arg) {
|
|
|
|
// check that methods overridden from a parent class agree
|
|
// on number/type of parameters
|
|
MethodSymbol sym = ast.sym;
|
|
MethodSymbol superSym = classSym.superClass.getMethod(ast.name);
|
|
if (superSym != null) {
|
|
if (superSym.parameters.size() != sym.parameters.size())
|
|
throw new SemanticFailure(
|
|
Cause.INVALID_OVERRIDE,
|
|
"Overridden method %s has %d parameters, " +
|
|
"but original has %d",
|
|
ast.name, sym.parameters.size(),
|
|
superSym.parameters.size());
|
|
for (Pair<VariableSymbol> pair : Pair.zip(sym.parameters, superSym.parameters))
|
|
if (pair.a.type != pair.b.type)
|
|
throw new SemanticFailure(
|
|
Cause.INVALID_OVERRIDE,
|
|
"Method parameter %s has type %s, but " +
|
|
"corresponding base class parameter %s has type %s",
|
|
pair.a.name, pair.a.type, pair.b.name, pair.b.type);
|
|
if (superSym.returnType != sym.returnType)
|
|
throw new SemanticFailure(
|
|
Cause.INVALID_OVERRIDE,
|
|
"Overridden method %s has return type %s," +
|
|
"but its superclass has %s",
|
|
ast.name, sym.returnType, superSym.returnType);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
}
|