package typechecker; import gui.errors.ErrorCollector; import gui.errors.TaZQLError; import gui.errors.TaZQLWarning; import java.util.List; import java.util.Map; import ast.expression.Binary; import ast.expression.Brackets; import ast.expression.Expression; import ast.expression.IExpressionVisitor; import ast.expression.arithmetic.Addition; import ast.expression.arithmetic.Division; import ast.expression.arithmetic.Multiplication; import ast.expression.arithmetic.Substraction; import ast.expression.comparison.Equal; import ast.expression.comparison.GreaterEqual; import ast.expression.comparison.GreaterThan; import ast.expression.comparison.LessEqual; import ast.expression.comparison.LessThan; import ast.expression.comparison.NotEqual; import ast.expression.logical.And; import ast.expression.logical.Or; import ast.expression.variables.BooleanVariable; import ast.expression.variables.Id; import ast.expression.variables.IntegerVariable; import ast.expression.variables.StringVariable; import ast.form.Form; import ast.form.IFormVisitor; import ast.question.ComputationQuestion; import ast.question.IQuestionVisitor; import ast.question.IfElseStatement; import ast.question.IfStatement; import ast.question.Question; import ast.question.SimpleQuestion; import ast.type.IntegerType; import ast.type.Type; import ast.unary.Minus; import ast.unary.Not; import ast.unary.Plus; import ast.unary.Unary; public class TypeCheckerVisitor implements IFormVisitor<Void>, IQuestionVisitor<Void>, IExpressionVisitor<Void> { private final ErrorCollector errorCollector; private final TypeRepository typeRepository; public TypeCheckerVisitor() { this.errorCollector = new ErrorCollector(); this.typeRepository = new TypeRepository(); } public List<TaZQLError> getError() { return this.errorCollector.getErrorCollection(); } public List<TaZQLWarning> getWarning() { return this.errorCollector.getWarningCollection(); } public boolean isCorrect() { return !this.errorCollector.containsError(); } /*** Question checks ***/ public void checkQuestion(SimpleQuestion question) { checkDuplicateDeclaration(question); checkDuplicateLabels(question); } // duplicate question declarations with different types public void checkDuplicateDeclaration(SimpleQuestion question) { String id = question.getQuestionId().getID(); Type type = question.getQuestionType(); if(!this.typeRepository.empty()) { if (!this.typeRepository.isDeclared(id) || this.typeRepository.getValue(id).equals(type)) { return; } this.errorCollector.addError("Question declaration *" + id + "* is duplicated. " + "It is used with a different type."); } } //duplicate labels (warning) public void checkDuplicateLabels(SimpleQuestion question) { String id = question.getQuestionId().getID(); String label = question.getQuestionText(); if(!this.typeRepository.empty()) { for(Map.Entry<String, String> entry : this.typeRepository.getLabelRepository().entrySet()) { String key = entry.getKey(); String labelValue = entry.getValue(); if(!labelValue.equals(label) || key.equals(id)) { continue; } this.errorCollector.addWarning("Warning! Duplicated label *" + labelValue + "* in question *" + key + "*."); } } } /*** Expression checks ***/ public Void checkExpression(Binary expression) { expression.getLeftExpression().accept(this); expression.getRightExpression().accept(this); checkType(expression.getLeftExpression(),expression.getType()); checkType( expression.getRightExpression(), expression.getType()); return null; } public Void checkComparisonExpression(Binary expression) { expression.getLeftExpression().accept(this); expression.getRightExpression().accept(this); checkType(expression.getLeftExpression(), new IntegerType()); checkType(expression.getRightExpression(), new IntegerType()); return null; } public Void checkUnaryExpression(Unary expression) { expression.getUnaryExpression().accept(this); checkType(expression.getUnaryExpression(), expression.getType()); return null; } public Void checkEqualityExpression(Binary expression) { expression.getLeftExpression().accept(this); expression.getRightExpression().accept(this); checkType(expression.getLeftExpression(), expression.getRightExpression().getType()); return null; } public void checkType(Expression expression, Type type) { if(expression.getType() != null) { if(expression.getType().isCompatibleToType(type)) { return; } this.errorCollector.addError("Error. Expression *" + expression.toString() + "* is of wrong type: *" + expression.getType() + "*, has to be *" +type + "*."); } } /*** Visitors ***/ @Override public Void visit(Form form) { for(Question q : form.getQuestionText()) q.accept(this); return null; } @Override public Void visit(Id identifier) { String id = identifier.getID(); if(!this.typeRepository.isDeclared(id)) { this.errorCollector.addError("Error: reference to undefined question *" + id + "*."); } return null; } @Override public Void visit(SimpleQuestion simpleQuestion) { this.checkQuestion(simpleQuestion); typeRepository.putType(simpleQuestion.getQuestionId().getID(), simpleQuestion.getQuestionType()); typeRepository.putLabel(simpleQuestion.getQuestionId().getID(), simpleQuestion.getQuestionText()); return null; } @Override public Void visit(ComputationQuestion calQuestion) { this.checkQuestion(calQuestion); String id = calQuestion.getQuestionId().getID(); typeRepository.putType(id, calQuestion.getQuestionType()); typeRepository.putLabel(id, calQuestion.getQuestionText()); calQuestion.getExpression().accept(this); checkType(calQuestion.getExpression(), calQuestion.getQuestionType()); return null; } @Override public Void visit(IfStatement ifStatement) { for(Question q : ifStatement.getIfStatement()) { q.accept(this); } ifStatement.getExpression().accept(this); Expression expression = ifStatement.getExpression(); checkType(expression, expression.getType()); return null; } @Override public Void visit(IfElseStatement ifElseStatement) { for(Question q : ifElseStatement.getIfStatement()) { q.accept(this); } for(Question q : ifElseStatement.getElseStatement()) { q.accept(this); } ifElseStatement.getExpression().accept(this); Expression expression = ifElseStatement.getExpression(); checkType(expression, expression.getType()); return null; } @Override public Void visit(Brackets expr) { expr.getBracketsExpression().accept(this); checkType(expr.getBracketsExpression(), expr.getType()); return null; } @Override public Void visit(Multiplication expr) { return this.checkExpression(expr); } @Override public Void visit(Division expr) { return this.checkExpression(expr); } @Override public Void visit(Addition expr) { return this.checkExpression(expr); } @Override public Void visit(Substraction expr) { return this.checkExpression(expr); } @Override public Void visit(Equal expr) { return this.checkEqualityExpression(expr); } @Override public Void visit(NotEqual expr) { return this.checkEqualityExpression(expr); } @Override public Void visit(LessThan expr) { return this.checkComparisonExpression(expr); } @Override public Void visit(GreaterThan expr) { return this.checkComparisonExpression(expr); } @Override public Void visit(LessEqual expr) { return this.checkComparisonExpression(expr); } @Override public Void visit(GreaterEqual expr) { return this.checkComparisonExpression(expr); } @Override public Void visit(Not expr) { return this.checkUnaryExpression(expr); } @Override public Void visit(Plus expr) { return this.checkUnaryExpression(expr); } @Override public Void visit(Minus expr) { return this.checkUnaryExpression(expr); } @Override public Void visit(And expr) { return this.checkExpression(expr); } @Override public Void visit(Or expr) { return this.checkExpression(expr); } @Override public Void visit(StringVariable string) { // TODO Auto-generated method stub return null; } @Override public Void visit(IntegerVariable integer) { // TODO Auto-generated method stub return null; } @Override public Void visit(BooleanVariable bool) { // TODO Auto-generated method stub return null; } }