diff --git a/docs/features/ub.md b/docs/features/ub.md index 28923e80..e382deda 100644 --- a/docs/features/ub.md +++ b/docs/features/ub.md @@ -10,4 +10,5 @@ These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined i 3. Use goto statement to jump out of a context block. 4. Type `T`'s `__new__` returns an object that is not an instance of `T`. 5. Call `__new__` with a type that is not a subclass of `type`. -6. `__eq__`, `__ne__` or `__contains__`, etc.. returns a value that is not a boolean. \ No newline at end of file +6. `__eq__`, `__ne__` or `__contains__`, etc.. returns a value that is not a boolean. +7. Division by zero. \ No newline at end of file diff --git a/src/ceval.h b/src/ceval.h index 60483870..262ef246 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -271,6 +271,14 @@ __NEXT_STEP:; PUSH(VAR(ss.str())); } DISPATCH(); /*****************************************/ +#define PREDICT_INT_OP(op) \ + if(is_both_int(TOP(), SECOND())){ \ + _1 = POPX(); \ + _0 = TOP(); \ + TOP() = VAR(_CAST(i64, _0) op _CAST(i64, _1)); \ + DISPATCH(); \ + } + #define BINARY_OP_SPECIAL(func) \ _1 = POPX(); \ _0 = TOP(); \ @@ -282,30 +290,35 @@ __NEXT_STEP:; } TARGET(BINARY_TRUEDIV) + if(is_tagged(SECOND())){ + f64 lhs = num_to_float(SECOND()); + f64 rhs = num_to_float(TOP()); + POP(); + TOP() = VAR(lhs / rhs); + DISPATCH(); + } BINARY_OP_SPECIAL(__truediv__); DISPATCH(); TARGET(BINARY_POW) BINARY_OP_SPECIAL(__pow__); DISPATCH(); TARGET(BINARY_ADD) - if(is_both_int(TOP(), SECOND())){ - _1 = POPX(); - _0 = TOP(); - TOP() = VAR(_CAST(i64, _0) + _CAST(i64, _1)); - DISPATCH(); - } + PREDICT_INT_OP(+); BINARY_OP_SPECIAL(__add__); DISPATCH() TARGET(BINARY_SUB) + PREDICT_INT_OP(-); BINARY_OP_SPECIAL(__sub__); DISPATCH() TARGET(BINARY_MUL) BINARY_OP_SPECIAL(__mul__); DISPATCH() TARGET(BINARY_FLOORDIV) + PREDICT_INT_OP(/); BINARY_OP_SPECIAL(__floordiv__); DISPATCH() TARGET(BINARY_MOD) + PREDICT_INT_OP(%); BINARY_OP_SPECIAL(__mod__); DISPATCH() TARGET(COMPARE_LT) @@ -331,18 +344,23 @@ __NEXT_STEP:; BINARY_OP_SPECIAL(__ge__); DISPATCH() TARGET(BITWISE_LSHIFT) + PREDICT_INT_OP(<<); BINARY_OP_SPECIAL(__lshift__); DISPATCH() TARGET(BITWISE_RSHIFT) + PREDICT_INT_OP(>>); BINARY_OP_SPECIAL(__rshift__); DISPATCH() TARGET(BITWISE_AND) + PREDICT_INT_OP(&); BINARY_OP_SPECIAL(__and__); DISPATCH() TARGET(BITWISE_OR) + PREDICT_INT_OP(|); BINARY_OP_SPECIAL(__or__); DISPATCH() TARGET(BITWISE_XOR) + PREDICT_INT_OP(^); BINARY_OP_SPECIAL(__xor__); DISPATCH() TARGET(BINARY_MATMUL) diff --git a/src/pocketpy.h b/src/pocketpy.h index 464f44bb..f4d4f366 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -107,7 +107,6 @@ inline void init_builtins(VM* _vm) { _vm->bind_builtin_func<2>("divmod", [](VM* vm, ArgsView args) { i64 lhs = CAST(i64, args[0]); i64 rhs = CAST(i64, args[1]); - if(rhs == 0) vm->ZeroDivisionError(); return VAR(Tuple({VAR(lhs/rhs), VAR(lhs%rhs)})); }); @@ -233,13 +232,11 @@ inline void init_builtins(VM* _vm) { _vm->bind__truediv__(_vm->tp_float, [](VM* vm, PyObject* lhs, PyObject* rhs) { f64 value = VAR_F(rhs); - if (value == 0) vm->ZeroDivisionError(); return VAR(_CAST(f64, lhs) / value); }); _vm->bind__truediv__(_vm->tp_int, [](VM* vm, PyObject* lhs, PyObject* rhs) { f64 value = VAR_F(rhs); - if (value == 0) vm->ZeroDivisionError(); return VAR(_CAST(i64, lhs) / value); }); @@ -287,13 +284,11 @@ inline void init_builtins(VM* _vm) { _vm->bind__floordiv__(_vm->tp_int, [](VM* vm, PyObject* lhs_, PyObject* rhs_) { i64 rhs = CAST(i64, rhs_); - if(rhs == 0) vm->ZeroDivisionError(); return VAR(_CAST(i64, lhs_) / rhs); }); _vm->bind__mod__(_vm->tp_int, [](VM* vm, PyObject* lhs_, PyObject* rhs_) { i64 rhs = CAST(i64, rhs_); - if(rhs == 0) vm->ZeroDivisionError(); return VAR(_CAST(i64, lhs_) % rhs); }); diff --git a/src/vm.h b/src/vm.h index 70a881aa..ac673392 100644 --- a/src/vm.h +++ b/src/vm.h @@ -518,7 +518,6 @@ public: void IOError(const Str& msg) { _error("IOError", msg); } void NotImplementedError(){ _error("NotImplementedError", ""); } void TypeError(const Str& msg){ _error("TypeError", msg); } - void ZeroDivisionError(){ _error("ZeroDivisionError", "division by zero"); } void IndexError(const Str& msg){ _error("IndexError", msg); } void ValueError(const Str& msg){ _error("ValueError", msg); } void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }