From 4860c08e03682914bd817d5a921de9b6a431a246 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 30 Jun 2024 14:10:17 +0800 Subject: [PATCH] some test --- include/pocketpy/pocketpy.h | 33 ++++++---- src/interpreter/ceval.c | 127 ++++++++++++++++++------------------ src/interpreter/py_number.c | 102 ++++++++++++++--------------- src/public/py_ops.c | 29 ++++---- src/public/values.c | 9 +-- src/public/vm.c | 11 +++- 6 files changed, 163 insertions(+), 148 deletions(-) diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index e34027dd..c00c210d 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -10,12 +10,18 @@ typedef uint16_t py_Name; typedef int16_t py_Type; typedef py_TValue* py_Ref; typedef struct py_Str py_Str; -typedef int (*py_CFunction)(int argc, py_Ref argv); typedef struct py_Error { py_Type type; } 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. +/// @return true if the function is successful. +typedef bool (*py_CFunction)(int argc, py_TValue* argv, py_TValue* out); + typedef enum BindType { BindType_FUNCTION, BindType_STATICMETHOD, @@ -64,6 +70,8 @@ void py_newnativefunc2(py_Ref out, const char* docstring, const py_Ref upvalue); +void py_newnotimplemented(py_Ref out); + /// Create a new object. /// @param out output reference. /// @param type type of the object. @@ -79,7 +87,6 @@ void py_pushstrn(const char*, int); void py_pushnone(); void py_pushnull(); -void py_push_notimplemented(); /************* Type Cast *************/ int64_t py_toint(const py_Ref); @@ -101,7 +108,7 @@ bool py_istype(const py_Ref, py_Type); // bool py_issubclass(py_Type derived, py_Type base); /************* References *************/ -#define py_arg(i) (py_Ref)((char*)argv+((i)<<4)) +#define py_arg(i) (py_Ref)((char*)argv+((i)<<4)) py_Ref py_getreg(int i); void py_setreg(int i, const py_Ref val); @@ -120,9 +127,9 @@ bool py_getattr(const py_Ref self, py_Name name, py_Ref out); /// Gets the unbound method of the object. bool py_getunboundmethod(const py_Ref self, py_Name name, bool fallback, py_Ref out, py_Ref out_self); /// Sets the attribute of the object. -int py_setattr(py_Ref self, py_Name name, const py_Ref val); +bool py_setattr(py_Ref self, py_Name name, const py_Ref val); /// Deletes the attribute of the object. -int py_delattr(py_Ref self, py_Name name); +bool py_delattr(py_Ref self, py_Name name); /// Equivalent to `*dst = *src`. void py_assign(py_Ref dst, const py_Ref src); @@ -163,14 +170,18 @@ void py_Error__print(py_Error*); /************* Operators *************/ int py_eq(const py_Ref, const py_Ref); int py_le(const py_Ref, const py_Ref); -int py_hash(const py_Ref, int64_t* out); +bool py_hash(const py_Ref, int64_t* out); -int py_str(const py_Ref); -int py_repr(const py_Ref); +bool py_str(const py_Ref, py_Ref out); +bool py_repr(const py_Ref, py_Ref out); -int py_vectorcall(int argc, int kwargc); -int py_call(py_Ref f, ...); -int py_callmethod(py_Ref self, py_Name name, ...); +/// A stack operation that calls a function. +/// It consumes `argc + kwargc` arguments from the stack. +/// The result will be set to `vm->last_retval`. +int pk_vectorcall(int argc, int kwargc, bool op_call); + +bool py_call(py_Ref f, ...); +bool py_callmethod(py_Ref self, py_Name name, ...); #define py_isnull(self) ((self)->type == 0) diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index e547fac1..53aeaf0f 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -38,28 +38,19 @@ int NameError(py_Name name) { return -1; } #define POPX() (*--self->stack.sp) #define SP() (self->stack.sp) -static void pack_stack_values(int n) { - assert(n > 1); - pk_VM* self = pk_current_vm; - py_TValue tmp; - py_newtuple(&tmp, n); - for(int i = 0; i < n; i++) - py_tuple__setitem(&tmp, i, SP() - n + i); - STACK_SHRINK(n); - PUSH(&tmp); -} - -// n == 1 is the most likely result -#define HANDLE_RETVAL(n) \ - if(n != 1) { \ - if(n == 0) { \ - PUSH(&self->None); \ - } else if(n > 1) { \ - pack_stack_values(n); \ - } else { \ - goto __ERROR; \ +#define vectorcall_opcall(n) \ + do { \ + pk_FrameResult res = pk_vectorcall(n, 0, true); \ + switch(res) { \ + case RES_RETURN: PUSH(&self->last_retval); break; \ + case RES_CALL: \ + frame = self->top_frame; \ + PUSH(&self->last_retval); \ + goto __NEXT_FRAME; \ + case RES_ERROR: goto __ERROR; \ + default: PK_UNREACHABLE(); \ } \ - } + } while(0) pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { Frame* frame = self->top_frame; @@ -113,10 +104,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_PRINT_EXPR: if(TOP()->type != tp_none_type) { - int err = py_repr(TOP()); - if(err) goto __ERROR; - self->_stdout("%s\n", py_tostr(TOP())); - POP(); + py_TValue tmp; + if(py_repr(TOP(), &tmp)) self->_stdout("%s\n", py_tostr(&tmp)); } POP(); DISPATCH(); @@ -258,11 +247,21 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_LOAD_SUBSCR: { // [a, b] -> a[b] - int n = py_callmethod(SECOND(), __getitem__, TOP()); - HANDLE_RETVAL(n); - // [a, b, retval] - *THIRD() = *TOP(); // [retval, b, retval] - STACK_SHRINK(2); // [retval] + pk_TypeInfo* ti = pk_tpinfo(SECOND()); + if(ti->m__getitem__) { + if(!ti->m__getitem__(2, SECOND(), SECOND())) goto __ERROR; + } else { + if(!py_callmethod(SECOND(), __getitem__, TOP())) goto __ERROR; + // // [a, b] -> [?, a, b] + // PUSH(TOP()); // [a, b, b] + // *SECOND() = *THIRD(); // [a, a, b] + // bool ok = py_getunboundmethod(SECOND(), __getitem__, false, THIRD(), + // SECOND()); if(!ok) { + // // __getitem__ not found + // goto __ERROR; + // } + // py_vectorcall(2, 0, ); + } DISPATCH(); } case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH(); @@ -300,17 +299,18 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_STORE_SUBSCR: { // [val, a, b] -> a[b] = val - py_TValue* backup = SP(); + pk_TypeInfo* ti = pk_tpinfo(SECOND()); PUSH(THIRD()); // [val, a, b, val] - bool ok = py_getunboundmethod(THIRD(), __setitem__, false, FOURTH(), THIRD()); - if(!ok) { - // __setitem__ not found - goto __ERROR; + if(ti->m__setitem__) { + if(!ti->m__setitem__(3, THIRD(), FOURTH())) goto __ERROR; + STACK_SHRINK(3); // [retval] + } else { + bool ok = py_getunboundmethod(THIRD(), __setitem__, false, FOURTH(), THIRD()); + if(!ok) goto __ERROR; + // [__setitem__, self, b, val] + vectorcall_opcall(3); + POP(); // discard retval } - // [__setitem__, self, b, val] - int n = py_vectorcall(3, 0); - if(n < 0) goto __ERROR; - SP() = backup; // discard retval if any DISPATCH(); } case OP_DELETE_FAST: { @@ -359,32 +359,36 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_DELETE_ATTR: { - int err = py_delattr(TOP(), byte.arg); - if(err) goto __ERROR; - POP(); + if(!py_delattr(TOP(), byte.arg)) goto __ERROR; DISPATCH(); } case OP_DELETE_SUBSCR: { // [a, b] -> del a[b] - py_Ref backup = SP(); - int n = py_callmethod(SECOND(), __delitem__, TOP()); - if(n < 0) { goto __ERROR; } - SP() = backup; // discard retval if any + pk_TypeInfo* ti = pk_tpinfo(SECOND()); + if(ti->m__delitem__) { + if(!ti->m__delitem__(2, SECOND(), SECOND())) goto __ERROR; + POP(); + } else { + PUSH(TOP()); // [a, b, b] + *SECOND() = *THIRD(); // [a, a, b] + bool ok = py_getunboundmethod(SECOND(), __delitem__, false, THIRD(), SECOND()); + // [__delitem__, self, b] + if(!ok) goto __ERROR; + vectorcall_opcall(2); + POP(); // discard retval + } DISPATCH(); } /*****************************************/ case OP_BUILD_LONG: { - py_Ref _0 = py_getdict(&self->builtins, pk_id_long); - assert(_0 != NULL); - int n = py_call(_0, TOP()); - if(n < 0) goto __ERROR; - assert(n == 1); - // [x, long(x)] - *SECOND() = *TOP(); // [long(x), long(x)] - POP(); // [long(x)] + // [x] + py_Ref f = py_getdict(&self->builtins, pk_id_long); + assert(f != NULL); + if(!py_call(f, TOP())) goto __ERROR; + *TOP() = self->last_retval; DISPATCH(); } @@ -393,19 +397,15 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { assert(_0 != NULL); py_TValue zero; py_newint(&zero, 0); - int n = py_call(_0, &zero, TOP()); - if(n < 0) goto __ERROR; - assert(n == 1); - // [x, complex(0, x)] - *SECOND() = *TOP(); // [complex(0, x), complex(0, x)] - POP(); // [complex(0, x)] + if(!py_call(_0, &zero, TOP())) goto __ERROR; + *TOP() = self->last_retval; DISPATCH(); } case OP_BUILD_BYTES: { py_Str* s = py_touserdata(TOP()); unsigned char* p = (unsigned char*)malloc(s->size); memcpy(p, py_Str__data(s), s->size); - py_newbytes(SP()++, p, s->size); + py_newbytes(TOP(), p, s->size); DISPATCH(); } case OP_BUILD_TUPLE: { @@ -461,14 +461,13 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { // } /**************************** */ case OP_RETURN_VALUE: { - py_TValue tmp = byte.arg == BC_NOARG ? POPX() : self->None; + self->last_retval = byte.arg == BC_NOARG ? POPX() : self->None; pk_VM__pop_frame(self); if(frame == base_frame) { // [ frameBase<- ] - self->last_retval = tmp; return RES_RETURN; } else { frame = self->top_frame; - PUSH(&tmp); + PUSH(&self->last_retval); goto __NEXT_FRAME; } DISPATCH(); diff --git a/src/interpreter/py_number.c b/src/interpreter/py_number.c index 01e542c3..e9c76882 100644 --- a/src/interpreter/py_number.c +++ b/src/interpreter/py_number.c @@ -40,29 +40,29 @@ // } #define DEF_NUM_BINARY_OP(name, op) \ - static int _py_int##name(int argc, py_Ref argv) { \ + static bool _py_int##name(int argc, py_Ref argv, py_Ref out) { \ if(py_isint(&argv[1])) { \ int64_t lhs = py_toint(&argv[0]); \ int64_t rhs = py_toint(&argv[1]); \ - py_pushint(lhs op rhs); \ + py_newint(out, lhs op rhs); \ } else if(py_isfloat(&argv[1])) { \ int64_t lhs = py_toint(&argv[0]); \ double rhs = py_tofloat(&argv[1]); \ - py_pushfloat(lhs op rhs); \ + py_newfloat(out, lhs op rhs); \ } else { \ - py_push_notimplemented(); \ + py_newnotimplemented(out); \ } \ - return 1; \ + return true; \ } \ - static int _py_float##name(int argc, py_Ref argv) { \ + static bool _py_float##name(int argc, py_Ref argv, py_Ref out) { \ double lhs = py_tofloat(&argv[0]); \ double rhs; \ if(py_castfloat(&argv[1], &rhs)) { \ - py_pushfloat(lhs op rhs); \ + py_newfloat(out, lhs op rhs); \ } else { \ - py_push_notimplemented(); \ + py_newnotimplemented(out); \ } \ - return 1; \ + return true; \ } DEF_NUM_BINARY_OP(__add__, +) @@ -77,51 +77,51 @@ DEF_NUM_BINARY_OP(__ge__, >=) #undef DEF_NUM_BINARY_OP -static int _py_int__neg__(int argc, py_Ref argv) { +static bool _py_int__neg__(int argc, py_Ref argv, py_Ref out) { int64_t val = py_toint(&argv[0]); - py_pushint(-val); - return 1; + py_newint(out, -val); + return true; } -static int _py_float__neg__(int argc, py_Ref argv) { +static bool _py_float__neg__(int argc, py_Ref argv, py_Ref out) { double val = py_tofloat(&argv[0]); - py_pushfloat(-val); - return 1; + py_newfloat(out, -val); + return true; } -static int _py_int__truediv__(int argc, py_Ref argv) { +static bool _py_int__truediv__(int argc, py_Ref argv, py_Ref out) { int64_t lhs = py_toint(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { - py_pushfloat(lhs / rhs); + py_newfloat(out, lhs / rhs); } else { - py_push_notimplemented(); + py_newnotimplemented(out); } - return 1; + return true; } -static int _py_float__truediv__(int argc, py_Ref argv) { +static bool _py_float__truediv__(int argc, py_Ref argv, py_Ref out) { double lhs = py_tofloat(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { - py_pushfloat(lhs / rhs); + py_newfloat(out, lhs / rhs); } else { - py_push_notimplemented(); + py_newnotimplemented(out); } - return 1; + return true; } -static int _py_number__pow__(int argc, py_Ref argv) { +#define ZeroDivisionError(msg) false + +static bool _py_number__pow__(int argc, py_Ref argv, py_Ref out) { if(py_isint(&argv[0]) && py_isint(&argv[1])) { int64_t lhs = py_toint(&argv[0]); int64_t rhs = py_toint(&argv[1]); if(rhs < 0) { if(lhs == 0) { - // py_pusherror("0.0 cannot be raised to a negative power"); - // TODO: ZeroDivisionError - return -1; + return ZeroDivisionError("0.0 cannot be raised to a negative power"); } else { - py_pushfloat(pow(lhs, rhs)); + py_newfloat(out, pow(lhs, rhs)); } } else { int64_t ret = 1; @@ -130,51 +130,51 @@ static int _py_number__pow__(int argc, py_Ref argv) { lhs *= lhs; rhs >>= 1; } - py_pushint(ret); + py_newint(out, ret); } } else { double lhs, rhs; py_castfloat(&argv[0], &lhs); if(py_castfloat(&argv[1], &rhs)) { - py_pushfloat(pow(lhs, rhs)); + py_newfloat(out, pow(lhs, rhs)); } else { - py_push_notimplemented(); + py_newnotimplemented(out); } } - return 1; + return true; } -static int _py_int__floordiv__(int argc, py_Ref argv) { +static bool _py_int__floordiv__(int argc, py_Ref argv, py_Ref out) { 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_pushint(lhs / rhs); + py_newint(out, lhs / rhs); } else { - py_push_notimplemented(); + py_newnotimplemented(out); } - return 1; + return true; } -static int _py_int__mod__(int argc, py_Ref argv) { +static bool _py_int__mod__(int argc, py_Ref argv, py_Ref out) { 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_pushint(lhs % rhs); + if(rhs == 0) return ZeroDivisionError("integer division or modulo by zero"); + py_newint(out, lhs % rhs); } else { - py_push_notimplemented(); + py_newnotimplemented(out); } - return 1; + return true; } -static int _py_int__invert__(int argc, py_Ref argv) { +static bool _py_int__invert__(int argc, py_Ref argv, py_Ref out) { int64_t val = py_toint(&argv[0]); - py_pushint(~val); - return 1; + py_newint(out, ~val); + return true; } -static int _py_int__bit_length(int argc, py_Ref argv) { +static bool _py_int__bit_length(int argc, py_Ref argv, py_Ref out) { int64_t x = py_toint(py_arg(0)); if(x < 0) x = -x; int bits = 0; @@ -182,20 +182,20 @@ static int _py_int__bit_length(int argc, py_Ref argv) { x >>= 1; bits++; } - py_pushint(bits); - return 1; + py_newint(out, bits); + return true; } #define DEF_INT_BITWISE_OP(name, op) \ - static int _py_int##name(int argc, py_Ref argv) { \ + static bool _py_int##name(int argc, py_Ref argv, py_Ref out) { \ int64_t lhs = py_toint(&argv[0]); \ if(py_isint(&argv[1])) { \ int64_t rhs = py_toint(&argv[1]); \ - py_pushint(lhs op rhs); \ + py_newint(out, lhs op rhs); \ } else { \ - py_push_notimplemented(); \ + py_newnotimplemented(out); \ } \ - return 1; \ + return true; \ } DEF_INT_BITWISE_OP(__and__, &) diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 81686e79..e7842aaa 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -5,24 +5,23 @@ 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; } -int py_hash(const py_Ref val, int64_t* out) { return 0; } +bool py_hash(const py_Ref val, int64_t* out) { return 0; } -int py_str(const py_Ref val) { return 0; } +bool py_str(const py_Ref val, py_Ref out) { return 0; } -int py_repr(const py_Ref val) { - const pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, val->type); - if(ti->m__repr__) return ti->m__repr__(1, val); - return py_callmethod(val, __repr__); +bool py_repr(const py_Ref val, py_Ref out) { + const pk_TypeInfo* ti = pk_tpinfo(val); + if(ti->m__repr__) return ti->m__repr__(1, val, out); + bool ok = py_callmethod(val, __repr__); + if(ok) { + *out = pk_current_vm->last_retval; + return true; + } + return false; } -bool py_getattr(const py_Ref self, py_Name name, py_Ref out){ - return true; -} +bool py_getattr(const py_Ref self, py_Name name, py_Ref out) { return true; } -int py_setattr(py_Ref self, py_Name name, const py_Ref val){ - return -1; -} +bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return -1; } -int py_delattr(py_Ref self, py_Name name){ - return -1; -} +bool py_delattr(py_Ref self, py_Name name) { return -1; } diff --git a/src/public/values.c b/src/public/values.c index 7f35ee64..1611cd39 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -80,6 +80,11 @@ void py_newnativefunc2(py_Ref out, const char* docstring, const py_Ref upvalue) {} +void py_newnotimplemented(py_Ref out) { + pk_VM* vm = pk_current_vm; + *out = vm->NotImplemented; +} + void py_newobject(py_Ref out, py_Type type, int slots, int udsize){ pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = pk_ManagedHeap__gcnew(heap, type, slots, udsize); @@ -103,7 +108,3 @@ void py_pushnone() { py_newnone(pk_current_vm->stack.sp++); } void py_pushnull() { py_newnull(pk_current_vm->stack.sp++); } -void py_push_notimplemented() { - pk_VM* vm = pk_current_vm; - *vm->stack.sp++ = vm->NotImplemented; -} diff --git a/src/public/vm.c b/src/public/vm.c index d073daeb..20d87829 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -47,18 +47,23 @@ int py_eval(const char* source, py_Ref out) { PK_UNREACHABLE(); } -int py_call(py_Ref callable, ...){ +bool py_call(py_Ref callable, ...){ return -1; } -int py_callmethod(py_Ref self, py_Name name, ...){ +bool py_callmethod(py_Ref self, py_Name name, ...){ return -1; } -int py_vectorcall(int argc, int kwargc){ +int pk_vectorcall(int argc, int kwargc, bool op_call){ return -1; } bool py_getunboundmethod(const py_Ref self, py_Name name, bool fallback, py_Ref out, py_Ref out_self){ return -1; +} + +pk_TypeInfo* pk_tpinfo(const py_Ref self){ + pk_VM* vm = pk_current_vm; + return c11__at(pk_TypeInfo, &vm->types, self->type); } \ No newline at end of file