diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 262cc3a8..f794e424 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -18,10 +18,8 @@ typedef struct py_Error { /// Native function signature. /// @param argc number of arguments. /// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument. -/// @param out output reference to the result. Please note that `out` could overlap with `argv`. -/// Always set `out` after using `argv`. /// @return true if the function is successful. -typedef bool (*py_CFunction)(int argc, py_TValue* argv, py_TValue* out); +typedef bool (*py_CFunction)(int argc, py_TValue* argv); typedef enum BindType { BindType_FUNCTION, diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 8465aad8..fe1ff0a2 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -11,6 +11,8 @@ int NameError(py_Name name) { return -1; } #define AttributeError(obj, name) false #define BinaryOptError(op) false +static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop); + #define DISPATCH() \ do { \ frame->ip++; \ @@ -259,9 +261,10 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__); if(magic) { if(magic->type == tp_nativefunc) { - bool ok = magic->_cfunc(2, SECOND(), SECOND()); + bool ok = magic->_cfunc(2, SECOND()); if(!ok) goto __ERROR; POP(); + *TOP() = self->last_retval; } else { INSERT_THIRD(); // [?, a, b] *THIRD() = *magic; // [__getitem__, a, b] @@ -311,9 +314,10 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__); if(magic) { if(magic->type == tp_nativefunc) { - bool ok = magic->_cfunc(3, THIRD(), FOURTH()); + bool ok = magic->_cfunc(3, THIRD()); if(!ok) goto __ERROR; - STACK_SHRINK(4); + STACK_SHRINK(3); + *TOP() = self->last_retval; } else { INSERT_THIRD(); // [?, a, b] *FOURTH() = *magic; // [__selitem__, a, b, val] @@ -380,9 +384,10 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__); if(magic) { if(magic->type == tp_nativefunc) { - bool ok = magic->_cfunc(2, SECOND(), SECOND()); + bool ok = magic->_cfunc(2, SECOND()); if(!ok) goto __ERROR; - STACK_SHRINK(2); + POP(); + *TOP() = self->last_retval; } else { INSERT_THIRD(); // [?, a, b] *THIRD() = *magic; // [__delitem__, a, b] @@ -492,67 +497,11 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { /*****************************/ case OP_BINARY_OP: { py_Name op = byte.arg & 0xFF; - // [a, b] - py_Ref _0 = py_tpfindmagic(SECOND()->type, op); - py_Ref _1; - py_TValue tmp; - if(_0) { - if(_0->type == tp_nativefunc) { - bool ok = _0->_cfunc(2, SECOND(), &tmp); - if(!ok) goto __ERROR; - if(tmp.type != tp_not_implemented_type) { - POP(); - *TOP() = tmp; - DISPATCH(); - } - } else { - // standard call - bool ok = py_call(_0, 2, SECOND()); - if(!ok) goto __ERROR; - if(self->last_retval.type != tp_not_implemented_type) { - POP(); - *TOP() = self->last_retval; - DISPATCH(); - } - } - } - // try reverse operation - op = byte.arg >> 8; - if(op) { - // [a, b] -> [b, a] - tmp = *TOP(); - *TOP() = *SECOND(); - *SECOND() = tmp; - _1 = py_tpfindmagic(SECOND()->type, op); - if(_1) { - if(_1->type == tp_nativefunc) { - bool ok = _1->_cfunc(2, SECOND(), &tmp); - if(!ok) goto __ERROR; - if(tmp.type != tp_not_implemented_type) { - POP(); - *TOP() = tmp; - DISPATCH(); - } - } else { - // standard call - bool ok = py_call(_1, 2, SECOND()); - if(!ok) goto __ERROR; - if(self->last_retval.type != tp_not_implemented_type) { - POP(); - *TOP() = self->last_retval; - DISPATCH(); - } - } - } - } - // eq/ne op never fails - if(op == __eq__ || op == __ne__) { - POP(); - *TOP() = (op == __eq__) ? self->False : self->True; - DISPATCH(); - } - BinaryOptError(byte.arg); - goto __ERROR; + py_Name rop = byte.arg >> 8; + if(!stack_binaryop(self, op, rop)) goto __ERROR; + POP(); + *TOP() = self->last_retval; + DISPATCH(); } case OP_IS_OP: { bool res = py_isidentical(SECOND(), TOP()); @@ -566,7 +515,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__); if(magic) { if(magic->type == tp_nativefunc) { - bool ok = magic->_cfunc(2, SECOND(), SECOND()); + bool ok = magic->_cfunc(2, SECOND()); if(!ok) goto __ERROR; POP(); *TOP() = self->last_retval; @@ -667,29 +616,22 @@ 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); +/// Assumes [a, b] are on the stack, performs a binary op. +/// The result is stored in `self->last_retval`. +/// The stack remains unchanged. +static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop) { // [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); + py_Ref magic = py_tpfindmagic(SECOND()->type, op); + if(magic) { + if(magic->type == tp_nativefunc) { + bool ok = magic->_cfunc(2, SECOND()); if(!ok) return false; - if(self->last_retval.type != tp_not_implemented_type) { - STACK_SHRINK(2); - return true; - } + if(self->last_retval.type != tp_not_implemented_type) return true; } else { // standard call - bool ok = py_call(_0, 2, SECOND()); + bool ok = py_call(magic, 2, SECOND()); if(!ok) return false; - if(self->last_retval.type != tp_not_implemented_type) { - STACK_SHRINK(2); - return true; - } + if(self->last_retval.type != tp_not_implemented_type) return true; } } // try reverse operation @@ -698,31 +640,31 @@ bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop) { 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); + magic = py_tpfindmagic(SECOND()->type, rop); + if(magic) { + if(magic->type == tp_nativefunc) { + bool ok = magic->_cfunc(2, SECOND()); if(!ok) return false; - if(tmp.type != tp_not_implemented_type) { - STACK_SHRINK(2); - return true; - } + if(self->last_retval.type != tp_not_implemented_type) return true; } else { // standard call - bool ok = py_call(_1, 2, SECOND()); + bool ok = py_call(magic, 2, SECOND()); if(!ok) return false; - if(self->last_retval.type != tp_not_implemented_type) { - STACK_SHRINK(2); - return true; - } + if(self->last_retval.type != tp_not_implemented_type) 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; } return BinaryOptError(byte.arg); } + +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); + return stack_binaryop(self, op, rop); +} \ No newline at end of file diff --git a/src/interpreter/py_number.c b/src/interpreter/py_number.c index 4d32824d..8b06643d 100644 --- a/src/interpreter/py_number.c +++ b/src/interpreter/py_number.c @@ -40,29 +40,29 @@ // } #define DEF_NUM_BINARY_OP(name, op, rint, rfloat) \ - static bool _py_int##name(int argc, py_Ref argv, py_Ref out) { \ + static bool _py_int##name(int argc, py_Ref argv) { \ py_checkargc(2); \ if(py_isint(&argv[1])) { \ int64_t lhs = py_toint(&argv[0]); \ int64_t rhs = py_toint(&argv[1]); \ - rint(out, lhs op rhs); \ + rint(py_lastretval(), lhs op rhs); \ } else if(py_isfloat(&argv[1])) { \ int64_t lhs = py_toint(&argv[0]); \ double rhs = py_tofloat(&argv[1]); \ - rfloat(out, lhs op rhs); \ + rfloat(py_lastretval(), lhs op rhs); \ } else { \ - py_newnotimplemented(out); \ + py_newnotimplemented(py_lastretval()); \ } \ return true; \ } \ - static bool _py_float##name(int argc, py_Ref argv, py_Ref out) { \ + static bool _py_float##name(int argc, py_Ref argv) { \ py_checkargc(2); \ double lhs = py_tofloat(&argv[0]); \ double rhs; \ if(py_castfloat(&argv[1], &rhs)) { \ - rfloat(out, lhs op rhs); \ + rfloat(py_lastretval(), lhs op rhs); \ } else { \ - py_newnotimplemented(out); \ + py_newnotimplemented(py_lastretval()); \ } \ return true; \ } @@ -80,47 +80,47 @@ DEF_NUM_BINARY_OP(__ge__, >=, py_newbool, py_newbool) #undef DEF_NUM_BINARY_OP -static bool _py_int__neg__(int argc, py_Ref argv, py_Ref out) { +static bool _py_int__neg__(int argc, py_Ref argv) { py_checkargc(1); int64_t val = py_toint(&argv[0]); - py_newint(out, -val); + py_newint(py_lastretval(), -val); return true; } -static bool _py_float__neg__(int argc, py_Ref argv, py_Ref out) { +static bool _py_float__neg__(int argc, py_Ref argv) { py_checkargc(1); double val = py_tofloat(&argv[0]); - py_newfloat(out, -val); + py_newfloat(py_lastretval(), -val); return true; } -static bool _py_int__truediv__(int argc, py_Ref argv, py_Ref out) { +static bool _py_int__truediv__(int argc, py_Ref argv) { py_checkargc(2); int64_t lhs = py_toint(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { - py_newfloat(out, lhs / rhs); + py_newfloat(py_lastretval(), lhs / rhs); } else { - py_newnotimplemented(out); + py_newnotimplemented(py_lastretval()); } return true; } -static bool _py_float__truediv__(int argc, py_Ref argv, py_Ref out) { +static bool _py_float__truediv__(int argc, py_Ref argv) { py_checkargc(2); double lhs = py_tofloat(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { - py_newfloat(out, lhs / rhs); + py_newfloat(py_lastretval(), lhs / rhs); } else { - py_newnotimplemented(out); + py_newnotimplemented(py_lastretval()); } return true; } #define ZeroDivisionError(msg) false -static bool _py_number__pow__(int argc, py_Ref argv, py_Ref out) { +static bool _py_number__pow__(int argc, py_Ref argv) { py_checkargc(2); if(py_isint(&argv[0]) && py_isint(&argv[1])) { int64_t lhs = py_toint(&argv[0]); @@ -129,7 +129,7 @@ static bool _py_number__pow__(int argc, py_Ref argv, py_Ref out) { if(lhs == 0) { return ZeroDivisionError("0.0 cannot be raised to a negative power"); } else { - py_newfloat(out, pow(lhs, rhs)); + py_newfloat(py_lastretval(), pow(lhs, rhs)); } } else { int64_t ret = 1; @@ -138,54 +138,54 @@ static bool _py_number__pow__(int argc, py_Ref argv, py_Ref out) { lhs *= lhs; rhs >>= 1; } - py_newint(out, ret); + py_newint(py_lastretval(), ret); } } else { double lhs, rhs; py_castfloat(&argv[0], &lhs); if(py_castfloat(&argv[1], &rhs)) { - py_newfloat(out, pow(lhs, rhs)); + py_newfloat(py_lastretval(), pow(lhs, rhs)); } else { - py_newnotimplemented(out); + py_newnotimplemented(py_lastretval()); } } return true; } -static bool _py_int__floordiv__(int argc, py_Ref argv, py_Ref out) { +static bool _py_int__floordiv__(int argc, py_Ref argv) { py_checkargc(2); int64_t lhs = py_toint(&argv[0]); if(py_isint(&argv[1])) { int64_t rhs = py_toint(&argv[1]); if(rhs == 0) return -1; - py_newint(out, lhs / rhs); + py_newint(py_lastretval(), lhs / rhs); } else { - py_newnotimplemented(out); + py_newnotimplemented(py_lastretval()); } return true; } -static bool _py_int__mod__(int argc, py_Ref argv, py_Ref out) { +static bool _py_int__mod__(int argc, py_Ref argv) { py_checkargc(2); int64_t lhs = py_toint(&argv[0]); if(py_isint(&argv[1])) { int64_t rhs = py_toint(&argv[1]); if(rhs == 0) return ZeroDivisionError("integer division or modulo by zero"); - py_newint(out, lhs % rhs); + py_newint(py_lastretval(), lhs % rhs); } else { - py_newnotimplemented(out); + py_newnotimplemented(py_lastretval()); } return true; } -static bool _py_int__invert__(int argc, py_Ref argv, py_Ref out) { +static bool _py_int__invert__(int argc, py_Ref argv) { py_checkargc(1); int64_t val = py_toint(&argv[0]); - py_newint(out, ~val); + py_newint(py_lastretval(), ~val); return true; } -static bool _py_int__bit_length(int argc, py_Ref argv, py_Ref out) { +static bool _py_int__bit_length(int argc, py_Ref argv) { py_checkargc(1); int64_t x = py_toint(py_arg(0)); if(x < 0) x = -x; @@ -194,19 +194,19 @@ static bool _py_int__bit_length(int argc, py_Ref argv, py_Ref out) { x >>= 1; bits++; } - py_newint(out, bits); + py_newint(py_lastretval(), bits); return true; } #define DEF_INT_BITWISE_OP(name, op) \ - static bool _py_int##name(int argc, py_Ref argv, py_Ref out) { \ + static bool _py_int##name(int argc, py_Ref argv) { \ py_checkargc(2); \ int64_t lhs = py_toint(&argv[0]); \ if(py_isint(&argv[1])) { \ int64_t rhs = py_toint(&argv[1]); \ - py_newint(out, lhs op rhs); \ + py_newint(py_lastretval(), lhs op rhs); \ } else { \ - py_newnotimplemented(out); \ + py_newnotimplemented(py_lastretval()); \ } \ return true; \ } diff --git a/src/public/vm.c b/src/public/vm.c index ab7929db..1b3d56f6 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -91,6 +91,6 @@ bool py_callmagic(py_Name name, int argc, py_Ref argv) { assert(argc >= 1); py_Ref tmp = py_tpfindmagic(argv->type, name); if(!tmp) return TypeError(name); - if(tmp->type == tp_nativefunc) { return tmp->_cfunc(argc, argv, &pk_current_vm->last_retval); } + if(tmp->type == tp_nativefunc) { return tmp->_cfunc(argc, argv); } return py_call(tmp, argc, argv); } \ No newline at end of file