Commits

Carl Friedrich Bolz  committed bced0d1

properly handle ZeroDivisionErrors

  • Participants
  • Parent commits 5453153

Comments (0)

Files changed (3)

File prolog/interpreter/arithmetic.py

         return other.arith_div_number(self.num)
 
     def arith_div_number(self, other_num):
+        if self.num == 0:
+            error.throw_evaluation_error("zero_divisor")
         try:
             res = rarithmetic.ovfcheck(other_num / self.num)
         except OverflowError:
         return term.Number(res)
 
     def arith_div_bigint(self, other_value):
+        if self.num == 0:
+            error.throw_evaluation_error("zero_divisor")
         return make_int(term.BigInt(other_value.div(rbigint.fromint(self.num))))
 
     def arith_div_float(self, other_float):
+        if self.num == 0:
+            error.throw_evaluation_error("zero_divisor")
         return term.Float(other_float / float(self.num))
 
     def arith_floordiv(self, other):
         return other.arith_floordiv_number(self.num)
 
     def arith_floordiv_number(self, other_num):
+        if self.num == 0:
+            error.throw_evaluation_error("zero_divisor")
         try:
             res = rarithmetic.ovfcheck(other_num // self.num)
         except OverflowError:
         return term.Number(res)
 
     def arith_floordiv_bigint(self, other_value):
+        if self.num == 0:
+            error.throw_evaluation_error("zero_divisor")
         return make_int(term.BigInt(other_value.floordiv(rbigint.fromint(self.num))))
 
     def arith_floordiv_float(self, other_float):
         return other.arith_mod_number(self.num)
 
     def arith_mod_number(self, other_num):
+        if self.num == 0:
+            error.throw_evaluation_error("zero_divisor")
         return term.Number(other_num % self.num)
 
     def arith_mod_bigint(self, other_value):
+        if self.num == 0:
+            error.throw_evaluation_error("zero_divisor")
         return make_int(term.BigInt(other_value.mod(rbigint.fromint(self.num))))
 
     # ------------------ inversion ------------------
         return other.arith_div_float(self.floatval)
 
     def arith_div_number(self, other_num):
+        if self.floatval == 0.0:
+            error.throw_evaluation_error("zero_divisor")
         return term.Float(float(other_num) / self.floatval)
 
     def arith_div_bigint(self, other_value):
+        if self.floatval == 0.0:
+            error.throw_evaluation_error("zero_divisor")
         return term.Float(other_value.tofloat() / self.floatval)
 
     def arith_div_float(self, other_float):
+        if self.floatval == 0.0:
+            error.throw_evaluation_error("zero_divisor")
         return term.Float(other_float / self.floatval)
 
     def arith_floordiv(self, other_float):
         return make_int(term.BigInt(rbigint.fromint(other_num).div(self.value)))
 
     def arith_div_bigint(self, other_value):
-        return make_int(term.BigInt(other_value.div(self.value)))
+        try:
+            return make_int(term.BigInt(other_value.div(self.value)))
+        except ZeroDivisionError:
+            error.throw_evaluation_error("zero_divisor")
 
     def arith_div_float(self, other_float):
         return term.Float(other_float / self.value.tofloat())
         return make_int(term.BigInt(rbigint.fromint(other_num).div(self.value)))
 
     def arith_floordiv_bigint(self, other_value):
-        return make_int(term.BigInt(other_value.div(self.value)))
+        try:
+            return make_int(term.BigInt(other_value.div(self.value)))
+        except ZeroDivisionError:
+            error.throw_evaluation_error("zero_divisor")
 
     def arith_floordiv_float(self, other_float):
         error.throw_type_error("integer", other_float)
         return other.arith_mod_bigint(self.value)
 
     def arith_mod_number(self, other_num):
-        return make_int(term.BigInt(rbigint.fromint(other_num).mod(self.value)))
+        try:
+            return make_int(term.BigInt(rbigint.fromint(other_num).mod(self.value)))
+        except ZeroDivisionError:
+            error.throw_evaluation_error("zero_divisor")
 
     def arith_mod_bigint(self, other_value):
-        return make_int(term.BigInt(other_value.mod(self.value)))
+        try:
+            return make_int(term.BigInt(other_value.mod(self.value)))
+        except ZeroDivisionError:
+            error.throw_evaluation_error("zero_divisor")
 
     # ------------------ inversion ------------------ 
     def arith_not(self):

File prolog/interpreter/error.py

         term.Callable.build("permission_error", [term.Callable.build(operation),
                                        term.Callable.build(permission_type),
                                        obj]))
+
+def throw_evaluation_error(error):
+    from prolog.interpreter import term
+    raise wrap_error(
+        term.Callable.build("evaluation_error", [term.Callable.build(error)]))
+

File prolog/interpreter/test/test_arithmetic.py

         assert Number(5).arith_div(BigInt(rbigint.fromdecimalstr('5'))).num == 1
         assert BigInt(rbigint.fromdecimalstr('5')).arith_div(Number(5)).num == 1
 
-        py.test.raises(ZeroDivisionError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_div(BigInt(rbigint.fromdecimalstr(\'0\')))')
-        py.test.raises(ZeroDivisionError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_div(Number(0))')
-        py.test.raises(ZeroDivisionError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_div(Float(0))')
-        py.test.raises(ZeroDivisionError, 'Float(1).arith_div(Number(0))')
-        py.test.raises(ZeroDivisionError, 'Number(1).arith_div(Number(0))')
-        py.test.raises(ZeroDivisionError, 'Number(1).arith_div(Float(0))')
+        py.test.raises(error.CatchableError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_div(BigInt(rbigint.fromdecimalstr(\'0\')))')
+        py.test.raises(error.CatchableError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_div(Number(0))')
+        py.test.raises(error.CatchableError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_div(Float(0))')
+        py.test.raises(error.CatchableError, 'Float(1).arith_div(Number(0))')
+        py.test.raises(error.CatchableError, 'Number(1).arith_div(Number(0))')
+        py.test.raises(error.CatchableError, 'Number(1).arith_div(Float(0))')
 
     def test_floordiv(self):
         assert Number(5).arith_floordiv(Number(2)).num == 2
         assert Number(5).arith_floordiv(BigInt(rbigint.fromdecimalstr('5'))).num == 1
         assert BigInt(rbigint.fromdecimalstr('5')).arith_floordiv(Number(5)).num == 1
 
-        py.test.raises(ZeroDivisionError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_floordiv(BigInt(rbigint.fromdecimalstr(\'0\')))')
-        py.test.raises(ZeroDivisionError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_floordiv(Number(0))')
-        py.test.raises(ZeroDivisionError, 'Number(1).arith_floordiv(Number(0))')
+        py.test.raises(error.CatchableError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_floordiv(BigInt(rbigint.fromdecimalstr(\'0\')))')
+        py.test.raises(error.CatchableError, 'BigInt(rbigint.fromdecimalstr(\'1\')).arith_floordiv(Number(0))')
+        py.test.raises(error.CatchableError, 'Number(1).arith_floordiv(Number(0))')
 
     def test_power(self):
         assert Number(5).arith_pow(Number(2)).num == 25
         assert BigInt(rbigint.fromint(46546)).arith_mod(Number(33)).num == 16
         assert Number(46546).arith_mod(BigInt(rbigint.fromint(33))).num == 16
 
-        py.test.raises(ZeroDivisionError, 'BigInt(rbigint.fromdecimalstr("12342424234")).arith_mod(BigInt(rbigint.fromint(0)))')
-        py.test.raises(ZeroDivisionError, 'Number(34535).arith_mod(BigInt(rbigint.fromint(0)))')
-        py.test.raises(ZeroDivisionError, 'BigInt(rbigint.fromdecimalstr("12342424234")).arith_mod(Number(0))')
+        py.test.raises(error.CatchableError, 'BigInt(rbigint.fromdecimalstr("12342424234")).arith_mod(BigInt(rbigint.fromint(0)))')
+        py.test.raises(error.CatchableError, 'Number(34535).arith_mod(BigInt(rbigint.fromint(0)))')
+        py.test.raises(error.CatchableError, 'BigInt(rbigint.fromdecimalstr("12342424234")).arith_mod(Number(0))')
 
     def test_invert(self):
         assert Number(2345).arith_not().num == -2346