diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 3e88daf..dd1f880 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -396,10 +396,9 @@ namespace chaiscript m->add(user_type(), "runtime_error"); m->add(chaiscript::base_class()); - m->add(constructor(), "runtime_error"); - m->add(fun(std::function(&what)), "what"); + m->add(fun(std::function(&what)), "what"); m->add(user_type(), "Dynamic_Object"); m->add(constructor(), "Dynamic_Object"); @@ -487,7 +486,12 @@ namespace chaiscript m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); - m->add(chaiscript::base_class()); + m->add(chaiscript::user_type(), "eval_error"); + m->add(chaiscript::base_class()); + + m->add(chaiscript::user_type(), "arithmetic_error"); + m->add(chaiscript::base_class()); + // chaiscript::bootstrap::standard_library::vector_type > >("AST_NodeVector", m); diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index 557a20a..a0ad6aa 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -22,6 +22,18 @@ namespace chaiscript { class Type_Conversions; } // namespace chaiscript +namespace chaiscript +{ + namespace exception + { + struct arithmetic_error : public std::runtime_error + { + arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {} + virtual ~arithmetic_error() CHAISCRIPT_NOEXCEPT {} + }; + } +} + namespace chaiscript { @@ -37,6 +49,21 @@ namespace chaiscript class Boxed_Number { private: + template + static void check_divide_by_zero(T t, typename std::enable_if::value>::type* = 0) + { +#ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO + if (t == 0) { + throw chaiscript::exception::arithmetic_error("divide by zero"); + } +#endif + } + + template + static void check_divide_by_zero(T, typename std::enable_if::value>::type* = 0) + { + } + struct boolean { @@ -61,7 +88,7 @@ namespace chaiscript case Operators::not_equal: return const_var(t != u); default: - throw chaiscript::detail::exception::bad_any_cast(); + throw chaiscript::detail::exception::bad_any_cast(); } } }; @@ -89,13 +116,14 @@ namespace chaiscript t += u; break; case Operators::assign_quotient: + check_divide_by_zero(u); t /= u; break; case Operators::assign_difference: t -= u; break; default: - throw chaiscript::detail::exception::bad_any_cast(); + throw chaiscript::detail::exception::bad_any_cast(); } return t_lhs; @@ -122,13 +150,14 @@ namespace chaiscript t >>= u; break; case Operators::assign_remainder: + check_divide_by_zero(u); t %= u; break; case Operators::assign_bitwise_xor: t ^= u; break; default: - throw chaiscript::detail::exception::bad_any_cast(); + throw chaiscript::detail::exception::bad_any_cast(); } return t_lhs; } @@ -146,6 +175,7 @@ namespace chaiscript case Operators::shift_right: return const_var(t >> u); case Operators::remainder: + check_divide_by_zero(u); return const_var(t % u); case Operators::bitwise_and: return const_var(t & u); @@ -156,7 +186,7 @@ namespace chaiscript case Operators::bitwise_complement: return const_var(~t); default: - throw chaiscript::detail::exception::bad_any_cast(); + throw chaiscript::detail::exception::bad_any_cast(); } } }; @@ -171,6 +201,7 @@ namespace chaiscript case Operators::sum: return const_var(t + u); case Operators::quotient: + check_divide_by_zero(u); return const_var(t / u); case Operators::product: return const_var(t * u); @@ -181,7 +212,7 @@ namespace chaiscript case Operators::unary_plus: return const_var(+t); default: - throw chaiscript::detail::exception::bad_any_cast(); + throw chaiscript::detail::exception::bad_any_cast(); } } }; @@ -327,7 +358,6 @@ namespace chaiscript return oss.str(); } - public: Boxed_Number() : bv(Boxed_Value(0)) @@ -843,12 +873,12 @@ namespace chaiscript struct Cast_Helper : Cast_Helper { }; - + /// Cast_Helper for converting from Boxed_Value to Boxed_Number template<> struct Cast_Helper : Cast_Helper { - }; + }; } #ifdef CHAISCRIPT_MSVC diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index be9aabc..eafb84b 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -93,6 +93,8 @@ namespace chaiscript // If it's an arithmetic operation we want to short circuit dispatch try{ return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs); + } catch (const chaiscript::exception::arithmetic_error &) { + throw; } catch (...) { throw exception::eval_error("Error with numeric operator calling: " + t_oper_string); } diff --git a/unittests/divide_by_zero_protection.chai b/unittests/divide_by_zero_protection.chai new file mode 100644 index 0000000..db648fc --- /dev/null +++ b/unittests/divide_by_zero_protection.chai @@ -0,0 +1,9 @@ +try { + 3/0 + assert_true(false); // should never get here +} catch (e) { + assert_equal("Arithmetic error: divide by zero", e.what()) +} + +assert_equal(3/0.0, Infinity) + diff --git a/unittests/future.chai b/unittests/future.chai index afb9afe..750c27d 100644 --- a/unittests/future.chai +++ b/unittests/future.chai @@ -1,6 +1,6 @@ var func = fun(){ var ret = 0; - for (var i = 0; i < 1000000; ++i) { + for (var i = 0; i < 50000; ++i) { ret += i; } return ret; @@ -9,9 +9,7 @@ var func = fun(){ var fut1 := async(func); var fut2 := async(func); -var fut3 := async(func); -var fut4 := async(func); // simply executing without crashing is good enough for this test -print(" ${fut1.get()} ${fut2.get()} ${fut3.get()} ${fut4.get()}") +print(" ${fut1.get()} ${fut2.get()} ")