package typecheck; import java.util.ArrayList; import java.util.List; import java.util.Map; import ast.Visitor; import ast.errormsg.Error; import ast.errormsg.Message; import ast.form.Block; import ast.form.Computedquest; import ast.form.Form; import ast.form.IfElse; import ast.form.Ifstate; import ast.form.Question; import ast.form.Statement; import ast.form.StatementList; import ast.literals.BoolLiteral; import ast.literals.IntLiteral; import ast.literals.StrLiteral; import ast.type.Booltype; import ast.type.Inttype; import ast.type.Strtype; import ast.type.Type; import expr.Expr; import expr.Ident; import expr.conditional.And; import expr.conditional.Or; import expr.operation.Add; import expr.operation.Div; import expr.operation.Mul; import expr.operation.Sub; import expr.relational.Eq; import expr.relational.GEq; import expr.relational.GT; import expr.relational.LEq; import expr.relational.LT; import expr.relational.NEq; import expr.unary.Neg; import expr.unary.Not; import expr.unary.Pos; public class Typecheck implements Visitor<Boolean>{ private final Map<Ident,Type> identifier; private List<Message> errors = new ArrayList<Message>(); public Typecheck (Map<Ident,Type> identifier) { this.identifier= identifier; } public List<Message> getErrors(){ return this.errors; } public boolean ValidExpression(Expr exp) { boolean result= exp.typeof(identifier).accept(this); return result; } public boolean ValidInteger(Expr operand, String side, String token) { if(ValidExpression(operand)) { Type optype = operand.typeof(identifier); if(optype.isInt()) { return true; } else { errors.add(new Error("Invalid Type at " + side + " " + token)); } } return false; } public boolean ValidInteger(Expr lhs, Expr rhs, String operator) { boolean Validop1 = ValidInteger(lhs, "left side", operator); boolean Validop2 = ValidInteger(rhs, "right side", operator); return (Validop1 && Validop2); } public boolean ValidBoolean(Expr operand, String side, String token) { if(ValidExpression(operand)) { Type optype = operand.typeof(identifier); if(optype.isBool()) { return true; } else{ errors.add(new Error("Invalid/Incompatible Type at " + side + " " + token)); } } return false; } public boolean ValidBoolean(Expr lhs, Expr rhs, String operator) { boolean Validop1 = ValidBoolean(lhs, "left side", operator); boolean Validop2 = ValidBoolean(rhs, "right side", operator); return (Validop1 && Validop2); } public boolean Equaltypes(Expr lhs, Expr rhs, String token){ boolean ValidLhs = ValidExpression(lhs); boolean ValidRhs = ValidExpression(rhs); if(ValidLhs && ValidRhs ){ Type type1 = lhs.typeof(identifier); Type type2 = rhs.typeof(identifier); if(((type1.isStr() && type2.isStr()) || (type1.isBool() && type2.isBool()) || (type1.isInt() && type2.isInt()))){ return true; } else{ errors.add(new Error("Not Equal types at ")); } } return false; } @Override public Boolean visit(And node) { return ValidBoolean(node.getLhs(), node.getRhs(), "&&") ; } @Override public Boolean visit(Or node) { return ValidBoolean(node.getLhs(), node.getRhs(), "||"); } @Override public Boolean visit(Ident node) { if(identifier.containsKey(node)) { return true; } else{ errors.add(new Error("Undefined identifier at " + node.getId())); } return false; } @Override public Boolean visit(Form node) { return node.getStatements().accept(this); } @Override public Boolean visit(Question node) { return checkIdent(node.getId(), node.getType()); } public boolean checkIdent(Ident id, Type type) { if(identifier.containsKey(id) && identifier.get(id).istype(type)) { return false; } else { identifier.put(id, type); return true; } } @Override public Boolean visit(IfElse node) { boolean validExpr = ValidExpression(node.getExpr()); boolean validIfState = node.getStatements().accept(this); boolean validElseState = node.getStatement1().accept(this); return (validExpr && validIfState && validElseState ); } @Override public Boolean visit(Ifstate node) { boolean validExpr = ValidBoolean(node.getExpr(), "", "if"); boolean validState = node.getStatements().accept(this); return (validExpr && validState); } @Override public Boolean visit(Add node) { return ValidInteger(node.getLhs(),node.getRhs(), "+"); } @Override public Boolean visit(Div node) { return ValidInteger(node.getLhs(),node.getRhs(), "/"); } @Override public Boolean visit(Mul node) { return ValidInteger(node.getLhs(),node.getRhs(), "*"); } @Override public Boolean visit(Sub node) { return ValidInteger(node.getLhs(),node.getRhs(), "-"); } @Override public Boolean visit(Eq node) { return Equaltypes(node.getLhs(),node.getRhs(), "=="); } @Override public Boolean visit(GEq node) { return Equaltypes(node.getLhs(),node.getRhs(), ">="); } @Override public Boolean visit(GT node) { return Equaltypes(node.getLhs(),node.getRhs(), ">"); } @Override public Boolean visit(LEq node) { return Equaltypes(node.getLhs(),node.getRhs(), "<="); } @Override public Boolean visit(LT node) { return Equaltypes(node.getLhs(),node.getRhs(),"<"); } @Override public Boolean visit(NEq node) { return Equaltypes(node.getLhs(),node.getRhs(),"!="); } @Override public Boolean visit(Booltype node) { return true; } @Override public Boolean visit(Inttype node) { return true; } @Override public Boolean visit(Strtype node) { return true; } @Override public Boolean visit(Neg node) { return ValidInteger(node.getOperand(), "", "-"); } @Override public Boolean visit(Not node) { return ValidInteger(node.getOperand(), "", "!"); } @Override public Boolean visit(Pos node) { return ValidInteger(node.getOperand(), "", "+"); } @Override public Boolean visit(StatementList statementList) { for(Statement statement: statementList.getList()) { if(!statement.accept(this)) { return false; } } return true; } @Override public Boolean visit(Computedquest node) { boolean ValidId = checkIdent(node.getId(), node.getType()); boolean ValidExpr = ValidExpression(node.getExpr()); boolean ValidType = Validtype(node.getId(),node.getType()); return (ValidId && ValidExpr && ValidType); } public boolean Validtype(Ident id, Type type) { if(identifier.get(id).istype(type)) { return true; } return false; } @Override public Boolean visit(BoolLiteral node) { return true; } @Override public Boolean visit(IntLiteral node) { return true; } @Override public Boolean visit(StrLiteral node) { return true; } @Override public Boolean visit(Block block) { return visit (block.getStatements()); } }