diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 7a2d9185..8cc17c35 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -149,6 +149,23 @@ bool py_getitem(const py_Ref self, const py_Ref key, py_Ref out); bool py_setitem(py_Ref self, const py_Ref key, const py_Ref val); bool py_delitem(py_Ref self, const py_Ref key); +bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop); + +#define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__) +#define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__) +#define py_binarymul(lhs, rhs) py_binaryop(lhs, rhs, __mul__, __rmul__) +#define py_binarytruediv(lhs, rhs) py_binaryop(lhs, rhs, __truediv__, __rtruediv__) +#define py_binaryfloordiv(lhs, rhs) py_binaryop(lhs, rhs, __floordiv__, __rfloordiv__) +#define py_binarymod(lhs, rhs) py_binaryop(lhs, rhs, __mod__, __rmod__) +#define py_binarypow(lhs, rhs) py_binaryop(lhs, rhs, __pow__, __rpow__) + +#define py_binarylshift(lhs, rhs) py_binaryop(lhs, rhs, __lshift__, 0) +#define py_binaryrshift(lhs, rhs) py_binaryop(lhs, rhs, __rshift__, 0) +#define py_binaryand(lhs, rhs) py_binaryop(lhs, rhs, __and__, 0) +#define py_binaryor(lhs, rhs) py_binaryop(lhs, rhs, __or__, 0) +#define py_binaryxor(lhs, rhs) py_binaryop(lhs, rhs, __xor__, 0) +#define py_binarymatmul(lhs, rhs) py_binaryop(lhs, rhs, __matmul__, 0) + /// Equivalent to `*dst = *src`. void py_assign(py_Ref dst, const py_Ref src); @@ -187,8 +204,14 @@ void py_Error__print(py_Error*); /************* Operators *************/ bool py_bool(const py_Ref); + int py_eq(const py_Ref, const py_Ref); +int py_ne(const py_Ref, const py_Ref); int py_le(const py_Ref, const py_Ref); +int py_lt(const py_Ref, const py_Ref); +int py_ge(const py_Ref, const py_Ref); +int py_gt(const py_Ref, const py_Ref); + bool py_hash(const py_Ref, int64_t* out); /// Compare two objects without using magic methods. diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 09cbc5dd..8fc9d611 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -666,3 +666,64 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { return RES_RETURN; } + +bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop) { + pk_VM* self = pk_current_vm; + PUSH(lhs); + PUSH(rhs); + // [a, b] + py_Ref _0 = py_tpfindmagic(SECOND()->type, op); + py_Ref _1; + if(_0) { + if(_0->type == tp_nativefunc) { + bool ok = _0->_cfunc(2, SECOND(), &self->last_retval); + if(!ok) return false; + if(self->last_retval.type != tp_not_implemented_type) { + STACK_SHRINK(2); + return true; + } + } else { + // standard call + bool ok = py_call(_0, 2, SECOND()); + if(!ok) return false; + if(self->last_retval.type != tp_not_implemented_type) { + STACK_SHRINK(2); + return true; + } + } + } + // try reverse operation + if(rop) { + // [a, b] -> [b, a] + py_TValue tmp = *TOP(); + *TOP() = *SECOND(); + *SECOND() = tmp; + _1 = py_tpfindmagic(SECOND()->type, rop); + if(_1) { + if(_1->type == tp_nativefunc) { + bool ok = _1->_cfunc(2, SECOND(), &self->last_retval); + if(!ok) return false; + if(tmp.type != tp_not_implemented_type) { + STACK_SHRINK(2); + return true; + } + } else { + // standard call + bool ok = py_call(_1, 2, SECOND()); + if(!ok) return false; + if(self->last_retval.type != tp_not_implemented_type) { + STACK_SHRINK(2); + return true; + } + } + } + } + // eq/ne op never fails + if(op == __eq__ || op == __ne__) { + STACK_SHRINK(2); + self->last_retval = (op == __eq__) ? self->False : self->True; + return true; + } + BinaryOptError(byte.arg); + return false; +} diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 4f0b7b4e..bdde6979 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -1,10 +1,6 @@ #include "pocketpy/interpreter/vm.h" #include "pocketpy/pocketpy.h" -int py_eq(const py_Ref lhs, const py_Ref rhs) { return 0; } - -int py_le(const py_Ref lhs, const py_Ref rhs) { return 0; } - bool py_isidentical(const py_Ref lhs, const py_Ref rhs){ if(lhs->is_ptr && rhs->is_ptr){ return lhs->_obj == rhs->_obj; @@ -26,4 +22,40 @@ bool py_getitem(const py_Ref self, const py_Ref key, py_Ref out) { return -1; } bool py_setitem(py_Ref self, const py_Ref key, const py_Ref val) { return -1; } -bool py_delitem(py_Ref self, const py_Ref key) { return -1; } \ No newline at end of file +bool py_delitem(py_Ref self, const py_Ref key) { return -1; } + +int py_eq(const py_Ref lhs, const py_Ref rhs) { + bool ok = py_binaryop(lhs, rhs, __eq__, __eq__); + if(!ok) return -1; + return py_tobool(py_lastretval()); +} + +int py_ne(const py_Ref lhs, const py_Ref rhs) { + bool ok = py_binaryop(lhs, rhs, __ne__, __ne__); + if(!ok) return -1; + return py_tobool(py_lastretval()); +} + +int py_lt(const py_Ref lhs, const py_Ref rhs) { + bool ok = py_binaryop(lhs, rhs, __lt__, __gt__); + if(!ok) return -1; + return py_tobool(py_lastretval()); +} + +int py_gt(const py_Ref lhs, const py_Ref rhs) { + bool ok = py_binaryop(lhs, rhs, __gt__, __lt__); + if(!ok) return -1; + return py_tobool(py_lastretval()); +} + +int py_ge(const py_Ref lhs, const py_Ref rhs) { + bool ok = py_binaryop(lhs, rhs, __ge__, __le__); + if(!ok) return -1; + return py_tobool(py_lastretval()); +} + +int py_le(const py_Ref lhs, const py_Ref rhs) { + bool ok = py_binaryop(lhs, rhs, __le__, __ge__); + if(!ok) return -1; + return py_tobool(py_lastretval()); +}