def visitExpr(self, ctx: DecafParser.ExprContext):
        line_num = ctx.start.line
        expr_type = ""

        if len(ctx.expr()) == 2:

            type_a = self.visit(ctx.expr(0))
            type_b = self.visit(ctx.expr(1))
            op = ctx.bin_op()

            if type_a == type_b:
                expr_type = type_a

            else:
                expr_type = None
                #print('Error on line', line_num, 'type mismatched in expression')

            #12
            if (op.rel_op() != None or op.arith_op() != None
                ) and type_a != 'int' and type_b != 'int':
                print('Error on line ' + str(line_num) +
                      ' operands must be of type int')
            #13
            elif op.eq_op() != None and type_a != type_b:
                print('Error on line ' + str(line_num) +
                      ' operands must be of same type')
            #14
            elif op.cond_op() != None and (type_a != 'boolean'
                                           or type_b != 'boolean'):
                print('Error on line ' + str(line_num) +
                      ' operands must be of type boolean')

        elif ctx.location() != None:

            var_name = ctx.location().ID().getText()
            var_symbol = self.st.lookup(var_name)

            if var_symbol != None:
                expr_type = var_symbol.type

            else:
                #2
                expr_type = None
                print('Error on line ' + str(line_num) + ', ' + var_name +
                      ' has not been declared')

        elif ctx.data_literal() != None:

            if ctx.data_literal().int_literal() != None:
                expr_type = 'int'

            elif ctx.data_literal().bool_literal() != None:
                expr_type = 'boolean'

            else:
                expr_type = None

        elif ctx.method_call() != None:

            method_name = ctx.method_call().method_name().getText()
            method_symbol = self.st.lookup(method_name)

            if method_symbol != None:

                expr_type = method_symbol.type
                self.visit(ctx.method_call())

            else:
                method_symbol = None

        elif ctx.EXCLAMATION() != None:

            expr_type = self.visit(ctx.expr(0))

            #14
            if expr_type != 'boolean':
                print('Error on line ' + str(line_num) +
                      ' operand must be of type boolean')

        else:
            self.visitChildren(ctx)

        return expr_type
    def visitExpr(self, ctx: DecafParser.ExprContext):
        line_number = ctx.start.line
        method_call = ctx.method_call()
        bin_oper = ""

        if ctx.expr(0) != None:
            if ctx.expr(0).bin_op() != None:
                bin_oper = ctx.expr(0).bin_op().getText()
        if self.eq_op:
            pass
        else:
            expressions = ctx.expr(0)
            if expressions != None:
                if ctx.expr(0).location() and bin_oper != None:
                    for items in ctx.expr():
                        locatons = items.getText()
                        """
                        check that the operands of bin_op are ints
                        """
                        if self.st.lookup(locatons).type != "int":
                            print(
                                "ERROR: can only use a airthmetic operation on ints",
                                line_number)
                if ctx.expr(0) and bin_oper != None:
                    if ctx.expr(0).location:
                        pass
                    else:
                        airth_op = ctx.expr(0).bin_op().airth_op().getText()
                        if airth_op in expressions.getText():
                            operands = ctx.expr(0).getText().replace(
                                airth_op, "")
                            listOfoperands = list(operands)
                            """
                            if operands are not loctions (meaning not varibles), try to chnage the 
                            type to int, if that fails throw error
                            """
                            for i in range(len(listOfoperands)):
                                try:
                                    int(listOfoperands[i])
                                except:
                                    print(
                                        "ERROR: can only use a airthmetic operation on ints",
                                        line_number)
        """
        check if a method call in side of an expression is not void as it must be a type to 
        be evaluated to something for it to be used in an expression, void is anon type
        """
        method_expr_params = []
        if method_call != None:
            method_params = method_call.expr()
            if self.st.lookup(method_call.ID().getText()).type == "void":
                print(
                    "ERROR: for method to be used here, method must return something"
                    + " line numnber", line_number)
                if "()" in method_call.getText():
                    name = method_call.getText()
                    name = name.replace("()", "")

                    for names in method_params:
                        method_expr_params = method_expr_params.append[names]
                    if len(method_expr_params) < len(
                            self.st.lookup(name).params):
                        print(
                            "ERROR: " + "method " +
                            self.st.lookup(name).id + " epecting",
                            len(self.st.lookup(name).params), "but got",
                            len(method_expr_params), "on line", line_number)

        return self.visitChildren(ctx)