package typecheck; import java.util.ArrayList; import java.util.List; import ast.expr.Expr; import ast.expr.Identifier; import ast.expr.literal.StrLiteral; import ast.statement.Block; import ast.statement.ComputedQuestion; import ast.statement.Form; import ast.statement.IfStatement; import ast.statement.IfelseStatement; import ast.statement.Question; import ast.statement.Statement; import ast.statement.StatementList; import ast.types.Type; import ast.visitors.StatementVisitor; public class StatementTypeChecker implements StatementVisitor<Boolean>{ private final SymbolTable symb_map; private ErrorList errors; private List<StrLiteral> labels; public StatementTypeChecker(SymbolTable symb_map, ErrorList errors) { this.symb_map = symb_map; this.errors = errors; labels = new ArrayList<StrLiteral>(); } public String get_errorList(){ return errors.toString(); } private void checkLabel(StrLiteral label) { if(labels.contains(label)){ errors.addWarning("Warning: Duplicate label at " + label.getVal()); } labels.add(label); } @Override public Boolean visit(StatementList node) { boolean result = true; for(Statement s: node.getList()){ if(!s.accept(this)){ result = false; } } return result; } @Override public Boolean visit(Question node) { checkLabel(node.getLabel()); return putIdentifier(node.getId(), node.getType()); } private boolean putIdentifier(Identifier id, Type type){ if(symb_map.containsSymbol(id) && (symb_map.getType(id)).isCompatibleTo(type)){ errors.addError("Error: Invalid identifier (already used) " + id.getIdentName()); return false; } else if(symb_map.containsSymbol(id) && !(symb_map.getType(id).isCompatibleTo(type))){ errors.addError("Error: Identifier already used with another type " + id.getIdentName()); return false; } symb_map.put(id, type); return true; } @Override public Boolean visit(ComputedQuestion node) { boolean validId = putIdentifier(node.getId(), node.getType()); boolean validExpr = ExprTypeChecker.check_expr(node.getExpr(), symb_map, errors); boolean validType = true; Type exprType = node.getExpr().typeof(symb_map); if (!node.getType().isCompatibleTo(exprType)){ validType = false; } return (validId && validExpr && validType); } @Override public Boolean visit(Block node) { return visit(node.getStatements()); } @Override public Boolean visit(IfStatement node) { boolean validExpr = isBooleanExpr(node.getExpr(), "if"); boolean validStatement = node.getStatements().accept(this); return (validExpr && validStatement); } private boolean isBooleanExpr(Expr expr, String token) { boolean validExpr = ExprTypeChecker.check_expr(expr, symb_map, errors); if (validExpr){ Type type = expr.typeof(symb_map); if(type.isCompatibleToBool()){ return true; } errors.addError("Error: Expression type is not boolean at " + token); } return false; } @Override public Boolean visit(Form node) { return node.getStatements().accept(this); } @Override public Boolean visit(IfelseStatement node) { boolean validExpr = isBooleanExpr(node.getExpr(), "if"); boolean validStatement_if = node.getStatements().accept(this); boolean validStatement_else = node.getElseStatements().accept(this); return (validExpr && validStatement_if && validStatement_else); } }