package qlProject.typeChecking.typeCheckVisitors;
import java.util.HashSet;
import java.util.Map;
import qlProject.ast.expression.BinaryExpression;
import qlProject.ast.expression.IExpressionVisitor;
import qlProject.ast.expression.Id;
import qlProject.ast.expression.ParenthesisExpr;
import qlProject.ast.expression.UnaryExpression;
import qlProject.ast.expression.StringExpr.ConcatenationExpr;
import qlProject.ast.expression.StringExpr.StringLiteral;
import qlProject.ast.expression.arithmeticExpr.AdditionExpr;
import qlProject.ast.expression.arithmeticExpr.DivisionExpr;
import qlProject.ast.expression.arithmeticExpr.IntLiteral;
import qlProject.ast.expression.arithmeticExpr.MultiplicationExpr;
import qlProject.ast.expression.arithmeticExpr.NegationExpr;
import qlProject.ast.expression.arithmeticExpr.SubtractionExpr;
import qlProject.ast.expression.booleanExpr.BoolLiteral;
import qlProject.ast.expression.booleanExpr.comparisonExpression.BiggerEqExpr;
import qlProject.ast.expression.booleanExpr.comparisonExpression.BiggerThanExpr;
import qlProject.ast.expression.booleanExpr.comparisonExpression.EqualExpr;
import qlProject.ast.expression.booleanExpr.comparisonExpression.SmallerEqExpr;
import qlProject.ast.expression.booleanExpr.comparisonExpression.SmallerThanExpr;
import qlProject.ast.expression.booleanExpr.comparisonExpression.UnequalExpr;
import qlProject.ast.expression.booleanExpr.logicalExpression.AndExpr;
import qlProject.ast.expression.booleanExpr.logicalExpression.NotExpr;
import qlProject.ast.expression.booleanExpr.logicalExpression.OrExpr;
import qlProject.ast.type.BooleanType;
import qlProject.ast.type.IntType;
import qlProject.ast.type.StringType;
import qlProject.ast.type.Type;
import qlProject.typeChecking.complaints.Complaint;
import qlProject.typeChecking.complaints.expression_level_complaint.ReferenceToUndefinedQError;
import qlProject.typeChecking.complaints.expression_level_complaint.operation_error.EqualityOperationError;
import qlProject.typeChecking.complaints.expression_level_complaint.operation_error.OperationError;
import qlProject.util.QuestionDetails;
public class ExpressionsTypeCheckVisitor implements IExpressionVisitor{
private final Map<String,QuestionDetails> questionsDetails;
private final HashSet<Complaint> complaints = new HashSet<Complaint>();
public ExpressionsTypeCheckVisitor(Map<String,QuestionDetails> questionsDetails){
this.questionsDetails = questionsDetails;
}
public HashSet<Complaint> getComplaints(){
return complaints;
}
public void checkBinarySubExprs(BinaryExpression e, Type t){
Type typeLeft = (Type)e.getLeft().accept(this);
Type typeRight = (Type)e.getRight().accept(this);
if (!typeLeft.equals(t))
complaints.add(new OperationError(e.getLeft(), typeLeft, t));
if (!typeRight.equals(t))
complaints.add(new OperationError(e.getRight(), typeRight, t));
}
public void checkUnarySubExprs2(UnaryExpression e, Type expectedT){
Type type = (Type)e.getSubExpression().accept(this);
if (!type.equals(expectedT))
complaints.add(new OperationError(e.getSubExpression(), type, expectedT));
}
public void checkSubExprsMatching2(BinaryExpression e){
Type typeLeft = (Type)e.getLeft().accept(this);
Type typeRight = (Type)e.getRight().accept(this);
if(!typeLeft.equals(typeRight))
complaints.add(new EqualityOperationError (e.getLeft(), e.getRight(), typeLeft, typeRight));
}
@Override
public Type visit (NotExpr e){
checkUnarySubExprs2(e, new BooleanType());
return new BooleanType();
}
@Override
public Type visit(NegationExpr e) {
checkUnarySubExprs2(e, new IntType());
return new IntType();
}
@Override
public Type visit(ParenthesisExpr e) {
Type t = (Type)e.getSubExpression().accept(this);
return t;
}
@Override
public Type visit (Id id){
if (!(questionsDetails.containsKey(id.getIdString())))
complaints.add(new ReferenceToUndefinedQError (id.getIdString()));
return questionsDetails.get(id.getIdString()).getType();
}
@Override
public Type visit (IntLiteral intLiteral){
return new IntType();
}
@Override
public Type visit (BoolLiteral boolLiteral){
return new BooleanType();
}
@Override
public Type visit (StringLiteral stringLiteral) {
return new StringType();
}
@Override
public Type visit (EqualExpr e){
checkSubExprsMatching2(e);
return new BooleanType();
}
@Override
public Type visit (UnequalExpr e){
checkSubExprsMatching2(e);
return new BooleanType();
}
@Override
public Type visit(BiggerThanExpr e) {
checkBinarySubExprs(e, new IntType());
return new BooleanType();
}
@Override
public Type visit(BiggerEqExpr e) {
checkBinarySubExprs(e, new IntType());
return new BooleanType();
}
@Override
public Type visit(SmallerThanExpr e) {
checkBinarySubExprs(e, new IntType());
return new BooleanType();
}
@Override
public Type visit(SmallerEqExpr e) {
checkBinarySubExprs(e, new IntType());
return new BooleanType();
}
@Override
public Type visit(OrExpr e) {
checkBinarySubExprs(e, new BooleanType());
return new BooleanType();
}
@Override
public Type visit(AndExpr e) {
checkBinarySubExprs(e, new BooleanType());
return new BooleanType();
}
@Override
public Type visit(AdditionExpr e) {
checkBinarySubExprs(e, new IntType());
return new IntType();
}
@Override
public Type visit(DivisionExpr e) {
checkBinarySubExprs(e, new IntType());
return new IntType();
}
@Override
public Type visit(MultiplicationExpr e) {
checkBinarySubExprs(e, new IntType());
return new IntType();
}
@Override
public Type visit(SubtractionExpr e) {
checkBinarySubExprs(e, new IntType());
return new IntType();
}
@Override
public Type visit(ConcatenationExpr e) {
checkBinarySubExprs(e, new StringType());
return new StringType();
}
}