package typecheck;
import ast.expr.Expr;
import ast.expr.Identifier;
import ast.expr.binExpr.Add;
import ast.expr.binExpr.And;
import ast.expr.binExpr.Div;
import ast.expr.binExpr.Eq;
import ast.expr.binExpr.GEq;
import ast.expr.binExpr.GT;
import ast.expr.binExpr.LEq;
import ast.expr.binExpr.LT;
import ast.expr.binExpr.Mul;
import ast.expr.binExpr.NEq;
import ast.expr.binExpr.Or;
import ast.expr.binExpr.Sub;
import ast.expr.literal.BoolLiteral;
import ast.expr.literal.IntLiteral;
import ast.expr.literal.StrLiteral;
import ast.expr.unExpr.Neg;
import ast.expr.unExpr.Not;
import ast.expr.unExpr.Pos;
import ast.types.Type;
import ast.visitors.ExprVisitor;
public class ExprTypeChecker implements ExprVisitor<Boolean>{
private final SymbolTable symbolTable;
private ErrorList errors;
private ExprTypeChecker(SymbolTable symb_map, ErrorList errors) {
this.symbolTable = symb_map;
this.errors = errors;
}
public static boolean check_expr(Expr expr, SymbolTable table, ErrorList errors){
ExprTypeChecker checker = new ExprTypeChecker(table, errors);
return expr.accept(checker);
}
private boolean isValidExpr(Expr exp){
return exp.accept(this);
}
private boolean isValidInt(Expr exp, String side, String token){
if (isValidExpr(exp)){
Type type = exp.typeof(symbolTable);
if(type.isCompatibleToInt()){
return true;
}
errors.addError("Error: Invalid/Incompatible Type at " + side + " " + token);
}
return false;
}
private boolean isValidInt(Expr lhs, Expr rhs, String token){
boolean isValid_lhs = isValidInt(lhs, "left side", token);
boolean isValid_rhs = isValidInt(rhs, "right side", token);
return (isValid_lhs && isValid_rhs);
}
private boolean isValidBool(Expr exp, String side, String token){
if (isValidExpr(exp)){
Type type = exp.typeof(symbolTable);
if(type.isCompatibleToBool()){
return true;
}
errors.addError("Error: Invalid/Incompatible Type at " + side + " " + token);
}
return false;
}
private boolean isValidBool(Expr lhs, Expr rhs, String token){
boolean isValid_lhs = isValidBool(lhs, "left side", token);
boolean isValid_rhs = isValidBool(rhs, "right side", token);
return (isValid_lhs && isValid_rhs);
}
private boolean areEqual_types(Expr lhs, Expr rhs, String token){
boolean isValid_lhs = isValidExpr(lhs);
boolean isValid_rhs = isValidExpr(rhs);
if(isValid_lhs && isValid_rhs){
Type t1 = lhs.typeof(symbolTable);
Type t2 = rhs.typeof(symbolTable);
if(t1.isCompatibleTo(t2)){
return true;
}
errors.addError("Error: Incompataible types at " + token);
}
return false;
}
private boolean areRelationalTypes(Expr lhs, Expr rhs, String token){
boolean isValid_lhs = isValidExpr(lhs);
boolean isValid_rhs = isValidExpr(rhs);
if(isValid_lhs && isValid_rhs){
Type t1 = lhs.typeof(symbolTable);
Type t2 = rhs.typeof(symbolTable);
if((t1.isCompatibleToStr() && t2.isCompatibleToStr()) ||
(t1.isCompatibleToInt() && t2.isCompatibleToInt())){
return true;
}
errors.addError("Error: Incompataible types at " + token);
}
return false;
}
@Override
public Boolean visit(Pos node) {
return isValidInt(node.getOperand(), "", "+");
}
@Override
public Boolean visit(Neg node) {
return isValidInt(node.getOperand(), "", "-");
}
@Override
public Boolean visit(Not node) {
return isValidBool(node.getOperand(), "", "!");
}
@Override
public Boolean visit(Add node) {
return isValidInt(node.getLhs(), node.getRhs(), "+");
}
@Override
public Boolean visit(And node) {
return isValidBool(node.getLhs(), node.getRhs(), "&&");
}
@Override
public Boolean visit(Div node) {
return isValidInt(node.getLhs(), node.getRhs(), "/");
}
@Override
public Boolean visit(Eq node) {
return areEqual_types(node.getLhs(), node.getRhs(), "==");
}
@Override
public Boolean visit(GEq node) {
return areRelationalTypes(node.getLhs(), node.getRhs(), ">=");
}
@Override
public Boolean visit(GT node) {
return areRelationalTypes(node.getLhs(), node.getRhs(), ">");
}
@Override
public Boolean visit(LEq node) {
return areRelationalTypes(node.getLhs(), node.getRhs(), "<=");
}
@Override
public Boolean visit(LT node) {
return areRelationalTypes(node.getLhs(), node.getRhs(), "<");
}
@Override
public Boolean visit(Mul node) {
return isValidInt(node.getLhs(), node.getRhs(), "*");
}
@Override
public Boolean visit(NEq node) {
return areEqual_types(node.getLhs(), node.getRhs(), "!=");
}
@Override
public Boolean visit(Or node) {
return isValidBool(node.getLhs(), node.getRhs(), "||");
}
@Override
public Boolean visit(Sub node) {
return isValidInt(node.getLhs(), node.getRhs(), "-");
}
@Override
public Boolean visit(Identifier node) {
if(symbolTable.containsSymbol(node)){
return true;
}
errors.addError("Error: Undefined identifier: " + node.getIdentName());
return false;
}
@Override
public Boolean visit(IntLiteral node) {
return true;
}
@Override
public Boolean visit(BoolLiteral node) {
return true;
}
@Override
public Boolean visit(StrLiteral node) {
return true;
}
}