From 25ceed2703a78294352701b27995995931043c69 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 30 Jun 2024 22:44:51 +0800 Subject: [PATCH] backup --- include/pocketpy/interpreter/frame.h | 35 +++--- include/pocketpy/interpreter/vm.h | 32 ++--- include/pocketpy/objects/base.h | 29 +++-- include/pocketpy/pocketpy.h | 64 +++++++--- include/pocketpy/xmacros/opcodes.h | 24 +--- src/common/strname.c | 33 ++--- src/compiler/compiler.c | 86 ++++++------- src/interpreter/ceval.c | 173 +++++++++++++++++++-------- src/interpreter/py_number.c | 102 +++++++--------- src/interpreter/vm.c | 5 +- src/public/py_list.c | 8 ++ src/public/py_ops.c | 13 -- src/public/values.c | 31 +++-- src/public/vm.c | 63 +++++++--- 14 files changed, 391 insertions(+), 307 deletions(-) diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index 4c1aef70..a31321c7 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/include/pocketpy/interpreter/frame.h @@ -15,7 +15,8 @@ py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co); typedef struct ValueStack { - // We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`. + // We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == + // true`. py_TValue* sp; py_TValue* end; py_TValue begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128]; @@ -34,44 +35,44 @@ UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset); void UnwindTarget__delete(UnwindTarget* self); typedef struct Frame { - struct Frame* f_back; // TODO: set this + struct Frame* f_back; const Bytecode* ip; const CodeObject* co; PyObject* module; - PyObject* function; // a function object or NULL (global scope) - py_TValue* p0; // unwinding base - py_TValue* locals; // locals base + PyObject* function; // a function object or NULL (global scope) + py_TValue* p0; // unwinding base + py_TValue* locals; // locals base const CodeObject* locals_co; UnwindTarget* uw_list; } Frame; - -Frame* Frame__new(const CodeObject* co, const py_TValue* module, const py_TValue* function, py_TValue* p0, py_TValue* locals, const CodeObject* locals_co); +Frame* Frame__new(const CodeObject* co, + const py_TValue* module, + const py_TValue* function, + py_TValue* p0, + py_TValue* locals, + const CodeObject* locals_co); void Frame__delete(Frame* self); -PK_INLINE int Frame__ip(const Frame* self){ - return self->ip - (Bytecode*)self->co->codes.data; -} +PK_INLINE int Frame__ip(const Frame* self) { return self->ip - (Bytecode*)self->co->codes.data; } -PK_INLINE int Frame__lineno(const Frame* self){ +PK_INLINE int Frame__lineno(const Frame* self) { int ip = Frame__ip(self); return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).lineno; } -PK_INLINE int Frame__iblock(const Frame* self){ +PK_INLINE int Frame__iblock(const Frame* self) { int ip = Frame__ip(self); return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).iblock; } -PK_INLINE pk_NameDict* Frame__f_globals(Frame* self){ - return PyObject__dict(self->module); -} +PK_INLINE pk_NameDict* Frame__f_globals(Frame* self) { return PyObject__dict(self->module); } -PK_INLINE py_TValue* Frame__f_globals_try_get(Frame* self, py_Name name){ +PK_INLINE py_TValue* Frame__f_globals_try_get(Frame* self, py_Name name) { return pk_NameDict__try_get(Frame__f_globals(self), name); } -PK_INLINE py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name){ +PK_INLINE py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name) { return FastLocals__try_get_by_name(self->locals, self->locals_co, name); } diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index e6bc6aa5..12c2bacb 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -21,21 +21,22 @@ typedef struct pk_TypeInfo{ c11_vector/*T=StrName*/ annotated_fields; + py_CFunction on_end_subclass; // backdoor for enum module + /* Magic Caches */ - // unary operators - py_CFunction m__repr__, m__str__, m__hash__, m__len__; - py_CFunction m__iter__, m__next__, m__neg__, m__invert__; - // binary operators - py_CFunction m__eq__, m__lt__, m__le__, m__gt__, m__ge__, m__contains__; - py_CFunction m__add__, m__sub__, m__mul__, m__truediv__, m__floordiv__; - py_CFunction m__mod__, m__pow__, m__matmul__; - py_CFunction m__lshift__, m__rshift__, m__and__, m__xor__, m__or__; - // indexer - py_CFunction m__getitem__, m__setitem__, m__delitem__; - // attribute access (internal use only) - py_CFunction m__getattr__, m__setattr__, m__delattr__; - // backdoors - py_CFunction on_end_subclass; // for enum module + py_TValue magic[64]; + // // unary operators + // py_CFunction m__repr__, m__str__, m__hash__, m__len__; + // py_CFunction m__iter__, m__next__, m__neg__, m__invert__; + // // binary operators + // py_CFunction m__eq__, m__lt__, m__le__, m__gt__, m__ge__, m__contains__; + // py_CFunction m__add__, m__sub__, m__mul__, m__truediv__, m__floordiv__; + // py_CFunction m__mod__, m__pow__, m__matmul__; + // py_CFunction m__lshift__, m__rshift__, m__and__, m__xor__, m__or__; + // // indexer + // py_CFunction m__getitem__, m__setitem__, m__delitem__; + // // attribute access (internal use only) + // py_CFunction m__getattr__, m__setattr__, m__delattr__; } pk_TypeInfo; void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, py_Type base, PyObject* obj, const py_TValue* module, bool subclass_enabled); @@ -91,6 +92,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self); py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const py_TValue* module, bool subclass_enabled); +// type registration +py_Type pk_list__register(); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/include/pocketpy/objects/base.h b/include/pocketpy/objects/base.h index dc859640..8d2811f4 100644 --- a/include/pocketpy/objects/base.h +++ b/include/pocketpy/objects/base.h @@ -16,35 +16,38 @@ extern "C" { typedef int16_t py_Type; typedef struct PyObject PyObject; -typedef struct py_TValue{ +typedef struct py_TValue { py_Type type; bool is_ptr; int extra; + union { int64_t _i64; double _f64; PyObject* _obj; void* _ptr; + py_CFunction _cfunc; // Vec2 }; } py_TValue; // 16 bytes to make py_arg() macro work +static_assert(sizeof(py_CFunction) <= 8, "sizeof(py_CFunction) > 8"); static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16"); /* predefined vars */ -static const py_Type tp_object = {1}, tp_type = {2}; -static const py_Type tp_int = {3}, tp_float = {4}, tp_bool = {5}, tp_str = {6}; -static const py_Type tp_list = {7}, tp_tuple = {8}; -static const py_Type tp_slice = {9}, tp_range = {10}, tp_module = {11}; -static const py_Type tp_function = {12}, tp_nativefunc = {13}, tp_bound_method = {14}; -static const py_Type tp_super = {15}, tp_exception = {16}, tp_bytes = {17}, tp_mappingproxy = {18}; -static const py_Type tp_dict = {19}, tp_property = {20}, tp_star_wrapper = {21}; -static const py_Type tp_staticmethod = {22}, tp_classmethod = {23}; -static const py_Type tp_none_type = {24}, tp_not_implemented_type = {25}; -static const py_Type tp_ellipsis = {26}; -static const py_Type tp_op_call = {27}, tp_op_yield = {28}; -static const py_Type tp_syntax_error = {29}, tp_stop_iteration = {30}; +const static py_Type tp_object = {1}, tp_type = {2}; +const static py_Type tp_int = {3}, tp_float = {4}, tp_bool = {5}, tp_str = {6}; +const static py_Type tp_list = {7}, tp_tuple = {8}; +const static py_Type tp_slice = {9}, tp_range = {10}, tp_module = {11}; +const static py_Type tp_function = {12}, tp_nativefunc = {13}, tp_bound_method = {14}; +const static py_Type tp_super = {15}, tp_exception = {16}, tp_bytes = {17}, tp_mappingproxy = {18}; +const static py_Type tp_dict = {19}, tp_property = {20}, tp_star_wrapper = {21}; +const static py_Type tp_staticmethod = {22}, tp_classmethod = {23}; +const static py_Type tp_none_type = {24}, tp_not_implemented_type = {25}; +const static py_Type tp_ellipsis = {26}; +const static py_Type tp_op_call = {27}, tp_op_yield = {28}; +const static py_Type tp_syntax_error = {29}, tp_stop_iteration = {30}; extern py_TValue PY_NULL, PY_OP_CALL, PY_OP_YIELD; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 95ddbf10..f5cfdc64 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -18,7 +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. +/// @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); @@ -74,13 +75,7 @@ void py_newfunction2(py_Ref out, const char* docstring, const py_Ref upvalue); // old style argc-based function -void py_newnativefunc(py_Ref out, py_CFunction, int argc); -void py_newnativefunc2(py_Ref out, - py_CFunction, - int argc, - BindType bt, - const char* docstring, - const py_Ref upvalue); +void py_newnativefunc(py_Ref out, py_CFunction); void py_newnotimplemented(py_Ref out); @@ -110,7 +105,21 @@ 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 TypeError(x) false +#define py_arg(i) (py_Ref)((char*)argv + ((i) << 4)) +#define py_checkargc(n) \ + if(argc != n) return TypeError() + +py_Ref py_tpmagic(py_Type type, py_Name name); +#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f)) + +// new style decl-based bindings +py_Ref py_bind(py_Ref obj, const char* sig, py_CFunction f); +py_Ref py_bind2(py_Ref obj, const char* sig, py_CFunction f, BindType bt, const char* docstring, const py_Ref upvalue); +// old style argc-based bindings +void py_bindmethod(py_Type type, const char* name, py_CFunction f); +void py_bindmethod2(py_Type type, const char* name, py_CFunction f, BindType bt); +void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f); py_Ref py_reg(int i); @@ -126,7 +135,11 @@ void py_setupvalue(py_Ref self, const py_Ref val); /// Gets the attribute of the object. 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); +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. bool py_setattr(py_Ref self, py_Name name, const py_Ref val); /// Deletes the attribute of the object. @@ -177,21 +190,29 @@ int py_eq(const py_Ref, const py_Ref); int py_le(const py_Ref, const py_Ref); bool py_hash(const py_Ref, int64_t* out); -bool py_str(const py_Ref, py_Ref out); -bool py_repr(const py_Ref, py_Ref out); - /// A stack operation that calls a function. -/// It consumes `argc + kwargc` arguments from the stack. +/// It assumes `argc + kwargc` arguments are already pushed to the stack. /// The result will be set to `vm->last_retval`. -int pk_vectorcall(int argc, int kwargc, bool op_call); +/// The stack size will be reduced by `argc + kwargc`. +bool pk_vectorcall(int argc, int kwargc, bool op_call); /// Call a function. /// It prepares the stack and then performs a `vectorcall(argc, 0, false)`. /// The result will be set to `vm->last_retval`. +/// The stack remains unchanged after the operation. bool py_call(py_Ref f, int argc, py_Ref argv); -/// Call a method. +/// Call a non-magic method. /// It prepares the stack and then performs a `vectorcall(argc+1, 0, false)`. /// The result will be set to `vm->last_retval`. -bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv); +/// The stack remains unchanged after the operation. +bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv); +/// Call a magic method. +/// The result will be set to `vm->last_retval`. +/// The stack remains unchanged after the operation. +bool py_callmagic(py_Name name, int argc, py_Ref argv); + +#define py_repr(self) py_callmagic(__repr__, 1, self) +#define py_str(self) py_callmagic(__str__, 1, self) + /// The return value of the most recent vectorcall. py_Ref py_lastretval(); @@ -217,6 +238,15 @@ void py_list__insert(py_Ref self, int i, const py_Ref val); typedef struct pk_TypeInfo pk_TypeInfo; pk_TypeInfo* pk_tpinfo(const py_Ref self); +/// Search the magic method from the given type to the base type. +/// Returns the reference or NULL if not found. +/// @lifespan: Permanent. +py_Ref py_tpfindmagic(py_Type, py_Name name); + +/// Get the type object of the given type. +/// @lifespan: Permanent. +py_Ref py_tpobject(py_Type type); + #ifdef __cplusplus } #endif diff --git a/include/pocketpy/xmacros/opcodes.h b/include/pocketpy/xmacros/opcodes.h index 18138968..cb9dbc0d 100644 --- a/include/pocketpy/xmacros/opcodes.h +++ b/include/pocketpy/xmacros/opcodes.h @@ -52,19 +52,7 @@ OPCODE(BUILD_SET) OPCODE(BUILD_SLICE) OPCODE(BUILD_STRING) /**************************/ -OPCODE(BUILD_TUPLE_UNPACK) -OPCODE(BUILD_LIST_UNPACK) -OPCODE(BUILD_DICT_UNPACK) -OPCODE(BUILD_SET_UNPACK) -/**************************/ -OPCODE(BINARY_TRUEDIV) -OPCODE(BINARY_POW) - -OPCODE(BINARY_ADD) -OPCODE(BINARY_SUB) -OPCODE(BINARY_MUL) -OPCODE(BINARY_FLOORDIV) -OPCODE(BINARY_MOD) +OPCODE(BINARY_OP) OPCODE(COMPARE_LT) OPCODE(COMPARE_LE) @@ -73,14 +61,6 @@ OPCODE(COMPARE_NE) OPCODE(COMPARE_GT) OPCODE(COMPARE_GE) -OPCODE(BITWISE_LSHIFT) -OPCODE(BITWISE_RSHIFT) -OPCODE(BITWISE_AND) -OPCODE(BITWISE_OR) -OPCODE(BITWISE_XOR) - -OPCODE(BINARY_MATMUL) - OPCODE(IS_OP) OPCODE(IS_NOT_OP) OPCODE(IN_OP) @@ -101,7 +81,7 @@ OPCODE(GOTO) OPCODE(FSTRING_EVAL) OPCODE(REPR) OPCODE(CALL) -OPCODE(CALL_TP) +OPCODE(CALL_VARGS) OPCODE(RETURN_VALUE) OPCODE(YIELD_VALUE) /**************************/ diff --git a/src/common/strname.c b/src/common/strname.c index 008c07c0..3ab4db1f 100644 --- a/src/common/strname.c +++ b/src/common/strname.c @@ -7,13 +7,13 @@ // TODO: use a more efficient data structure static c11_smallmap_s2n _interned; -static c11_vector/*T=char* */ _r_interned; +static c11_vector /*T=char* */ _r_interned; static bool _initialized = false; -void pk_StrName__initialize(){ +void pk_StrName__initialize() { if(_initialized) return; c11_smallmap_s2n__ctor(&_interned); - for(int i=0; i<_r_interned.count; i++){ + for(int i = 0; i < _r_interned.count; i++) { free(c11__at(char*, &_r_interned, i)); } c11_vector__ctor(&_r_interned, sizeof(c11_string)); @@ -75,33 +75,36 @@ void pk_StrName__initialize(){ pk_id_set = pk_StrName__map("set"); pk_id_long = pk_StrName__map("long"); pk_id_complex = pk_StrName__map("complex"); + + // // print all names + // for(int i = 0; i < _interned.count; i++) { + // printf("%d: %s\n", i+1, c11__getitem(char*, &_r_interned, i)); + // } } -void pk_StrName__finalize(){ +void pk_StrName__finalize() { if(!_initialized) return; // free all char* - for(int i=0; i<_r_interned.count; i++){ + for(int i = 0; i < _r_interned.count; i++) { free(c11__getitem(char*, &_r_interned, i)); } c11_smallmap_s2n__dtor(&_interned); c11_vector__dtor(&_r_interned); } -uint16_t pk_StrName__map(const char* name){ +uint16_t pk_StrName__map(const char* name) { return pk_StrName__map2((c11_string){name, strlen(name)}); } -uint16_t pk_StrName__map2(c11_string name){ +uint16_t pk_StrName__map2(c11_string name) { // TODO: PK_GLOBAL_SCOPE_LOCK() - if(!_initialized){ - pk_StrName__initialize(); // lazy init + if(!_initialized) { + pk_StrName__initialize(); // lazy init } uint16_t index = c11_smallmap_s2n__get(&_interned, name, 0); if(index != 0) return index; // generate new index - if(_interned.count > 65530){ - PK_FATAL_ERROR("StrName index overflow\n"); - } + if(_interned.count > 65530) { PK_FATAL_ERROR("StrName index overflow\n"); } // NOTE: we must allocate the string in the heap so iterators are not invalidated char* p = malloc(name.size + 1); memcpy(p, name.data, name.size); @@ -114,19 +117,17 @@ uint16_t pk_StrName__map2(c11_string name){ return index; } -const char* pk_StrName__rmap(uint16_t index){ +const char* pk_StrName__rmap(uint16_t index) { assert(_initialized); assert(index > 0 && index <= _interned.count); return c11__getitem(char*, &_r_interned, index - 1); } -c11_string pk_StrName__rmap2(uint16_t index){ +c11_string pk_StrName__rmap2(uint16_t index) { const char* p = pk_StrName__rmap(index); return (c11_string){p, strlen(p)}; } - - // unary operators uint16_t __repr__; uint16_t __str__; diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index b1c2efab..3f122058 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -898,15 +898,18 @@ static void BinaryExpr__emit_(Expr* self_, Ctx* ctx) { } vtemit_(self->rhs, ctx); - Opcode opcode; + + Opcode opcode = OP_BINARY_OP; + uint16_t arg = BC_NOARG; + switch(self->op) { - case TK_ADD: opcode = OP_BINARY_ADD; break; - case TK_SUB: opcode = OP_BINARY_SUB; break; - case TK_MUL: opcode = OP_BINARY_MUL; break; - case TK_DIV: opcode = OP_BINARY_TRUEDIV; break; - case TK_FLOORDIV: opcode = OP_BINARY_FLOORDIV; break; - case TK_MOD: opcode = OP_BINARY_MOD; break; - case TK_POW: opcode = OP_BINARY_POW; break; + case TK_ADD: arg = __add__ | (__radd__ << 8); break; + case TK_SUB: arg = __sub__ | (__rsub__ << 8); break; + case TK_MUL: arg = __mul__ | (__rmul__ << 8); break; + case TK_DIV: arg = __truediv__; break; + case TK_FLOORDIV: arg = __floordiv__; break; + case TK_MOD: arg = __mod__; break; + case TK_POW: arg = __pow__; break; case TK_LT: opcode = OP_COMPARE_LT; break; case TK_LE: opcode = OP_COMPARE_LE; break; @@ -920,17 +923,16 @@ static void BinaryExpr__emit_(Expr* self_, Ctx* ctx) { case TK_IS: opcode = OP_IS_OP; break; case TK_IS_NOT: opcode = OP_IS_NOT_OP; break; - case TK_LSHIFT: opcode = OP_BITWISE_LSHIFT; break; - case TK_RSHIFT: opcode = OP_BITWISE_RSHIFT; break; - case TK_AND: opcode = OP_BITWISE_AND; break; - case TK_OR: opcode = OP_BITWISE_OR; break; - case TK_XOR: opcode = OP_BITWISE_XOR; break; - - case TK_DECORATOR: opcode = OP_BINARY_MATMUL; break; + case TK_LSHIFT: arg = __lshift__; break; + case TK_RSHIFT: arg = __rshift__; break; + case TK_AND: arg = __and__; break; + case TK_OR: arg = __or__; break; + case TK_XOR: arg = __xor__; break; + case TK_DECORATOR: arg = __matmul__; break; default: assert(false); } - Ctx__emit_(ctx, opcode, BC_NOARG, self->line); + Ctx__emit_(ctx, opcode, arg, self->line); c11__foreach(int, &jmps, i) { Ctx__patch_jump(ctx, *i); } } @@ -1137,8 +1139,8 @@ void CallExpr__dtor(Expr* self_) { void CallExpr__emit_(Expr* self_, Ctx* ctx) { CallExpr* self = (CallExpr*)self_; - bool vargs = false; - bool vkwargs = false; + bool vargs = false; // whether there is *args as input + bool vkwargs = false; // whether there is **kwargs as input c11__foreach(Expr*, &self->args, e) { if((*e)->vt->is_starred) vargs = true; } @@ -1147,7 +1149,6 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) { } // if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` - // proxy if(self->callable->vt->is_attrib) { AttribExpr* p = (AttribExpr*)self->callable; vtemit_(p->child, ctx); @@ -1157,41 +1158,22 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) { Ctx__emit_(ctx, OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE); } - c11__foreach(Expr*, &self->args, e) { vtemit_(*e, ctx); } - + Opcode opcode = OP_CALL; if(vargs || vkwargs) { - Ctx__emit_(ctx, OP_BUILD_TUPLE_UNPACK, (uint16_t)self->args.count, self->line); - - if(self->kwargs.count != 0) { - c11__foreach(CallExprKwArg, &self->kwargs, e) { - if(e->val->vt->is_starred) { - // **kwargs - StarredExpr* se = (StarredExpr*)e->val; - assert(se->level == 2 && e->key == 0); - vtemit_(e->val, ctx); - } else { - // k=v - int index = Ctx__add_const_string(ctx, pk_StrName__rmap2(e->key)); - Ctx__emit_(ctx, OP_LOAD_CONST, index, self->line); - vtemit_(e->val, ctx); - Ctx__emit_(ctx, OP_BUILD_TUPLE, 2, self->line); - } - } - Ctx__emit_(ctx, OP_BUILD_DICT_UNPACK, self->kwargs.count, self->line); - Ctx__emit_(ctx, OP_CALL_TP, 1, self->line); - } else { - Ctx__emit_(ctx, OP_CALL_TP, 0, self->line); - } - } else { - // vectorcall protocol - c11__foreach(CallExprKwArg, &self->kwargs, e) { - Ctx__emit_int(ctx, e->key, self->line); - vtemit_(e->val, ctx); - } - int KWARGC = self->kwargs.count; - int ARGC = self->args.count; - Ctx__emit_(ctx, OP_CALL, (KWARGC << 8) | ARGC, self->line); + // in this case, there is at least one *args or **kwargs as StarredExpr + // OP_CALL_VARGS needs to unpack them via __vectorcall_buffer + opcode = OP_CALL_VARGS; } + + c11__foreach(Expr*, &self->args, e) { vtemit_(*e, ctx); } + c11__foreach(CallExprKwArg, &self->kwargs, e) { + Ctx__emit_int(ctx, e->key, self->line); + vtemit_(e->val, ctx); + } + int KWARGC = self->kwargs.count; + int ARGC = self->args.count; + assert(KWARGC < 256 && ARGC < 256); + Ctx__emit_(ctx, opcode, (KWARGC << 8) | ARGC, self->line); } CallExpr* CallExpr__new(int line, Expr* callable) { diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 2dbfe86f..864bd622 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -9,6 +9,7 @@ int UnboundLocalError(py_Name name) { return -1; } int NameError(py_Name name) { return -1; } #define AttributeError(obj, name) +#define BinaryOptError(op) #define DISPATCH() \ do { \ @@ -38,6 +39,13 @@ int NameError(py_Name name) { return -1; } #define POPX() (*--self->stack.sp) #define SP() (self->stack.sp) +// [a, b] -> [?, a, b] +#define INSERT_THIRD() \ + do { \ + PUSH(TOP()); \ + *SECOND() = *THIRD(); \ + } while(0) + #define vectorcall_opcall(n) \ do { \ pk_FrameResult res = pk_vectorcall(n, 0, true); \ @@ -104,8 +112,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_PRINT_EXPR: if(TOP()->type != tp_none_type) { - py_TValue tmp; - if(py_repr(TOP(), &tmp)) self->_stdout("%s\n", py_tostr(&tmp)); + bool ok = py_repr(TOP()); + if(!ok) goto __ERROR; + self->_stdout("%s\n", py_tostr(&self->last_retval)); } POP(); DISPATCH(); @@ -247,19 +256,21 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_LOAD_SUBSCR: { // [a, b] -> a[b] - pk_TypeInfo* ti = pk_tpinfo(SECOND()); - if(ti->m__getitem__) { - if(!ti->m__getitem__(2, SECOND(), SECOND())) goto __ERROR; - } else { - // [a, b] -> [?, a, b] - PUSH(TOP()); // [a, b, b] - *SECOND() = *THIRD(); // [a, a, b] - bool ok = py_getunboundmethod(SECOND(), __getitem__, false, THIRD(), SECOND()); - // [__getitem__, self, b] - if(!ok) goto __ERROR; - vectorcall_opcall(2); + py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__); + if(magic) { + if(magic->type == tp_nativefunc) { + bool ok = magic->_cfunc(2, SECOND(), SECOND()); + if(!ok) goto __ERROR; + POP(); + } else { + INSERT_THIRD(); // [?, a, b] + *THIRD() = *magic; // [__getitem__, a, b] + vectorcall_opcall(2); + } + DISPATCH(); } - DISPATCH(); + TypeError(); + goto __ERROR; } case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH(); case OP_STORE_NAME: { @@ -296,19 +307,23 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_STORE_SUBSCR: { // [val, a, b] -> a[b] = val - pk_TypeInfo* ti = pk_tpinfo(SECOND()); PUSH(THIRD()); // [val, a, b, val] - 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 + py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__); + if(magic) { + if(magic->type == tp_nativefunc) { + bool ok = magic->_cfunc(3, THIRD(), FOURTH()); + if(!ok) goto __ERROR; + STACK_SHRINK(4); + } else { + INSERT_THIRD(); // [?, a, b] + *FOURTH() = *magic; // [__selitem__, a, b, val] + vectorcall_opcall(3); + POP(); // discard retval + } + DISPATCH(); } - DISPATCH(); + TypeError(); + goto __ERROR; } case OP_DELETE_FAST: { py_Ref tmp = &frame->locals[byte.arg]; @@ -362,22 +377,23 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { case OP_DELETE_SUBSCR: { // [a, b] -> del a[b] - 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 + py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__); + if(magic) { + if(magic->type == tp_nativefunc) { + bool ok = magic->_cfunc(2, SECOND(), SECOND()); + if(!ok) goto __ERROR; + STACK_SHRINK(2); + } else { + INSERT_THIRD(); // [?, a, b] + *THIRD() = *magic; // [__delitem__, a, b] + vectorcall_opcall(2); + POP(); // discard retval + } + DISPATCH(); } - DISPATCH(); + TypeError(); + goto __ERROR; } - /*****************************************/ case OP_BUILD_LONG: { @@ -394,11 +410,11 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_Ref f = py_getdict(&self->builtins, pk_id_complex); assert(f != NULL); py_TValue tmp = *TOP(); - *TOP() = *f; // [complex] - py_newnull(SP()++); // [complex, NULL] - py_newint(SP()++, 0); // [complex, NULL, 0] - *SP()++ = tmp; // [complex, NULL, 0, x] - vectorcall_opcall(2); // [complex(x, 0)] + *TOP() = *f; // [complex] + py_newnull(SP()++); // [complex, NULL] + py_newint(SP()++, 0); // [complex, NULL, 0] + *SP()++ = tmp; // [complex, NULL, 0, x] + vectorcall_opcall(2); // [complex(x)] DISPATCH(); } case OP_BUILD_BYTES: { @@ -462,20 +478,77 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } case OP_BUILD_STRING: { py_TValue* begin = SP() - byte.arg; - py_Ref tmp = py_pushtmp(); pk_SStream ss; pk_SStream__ctor(&ss); for(int i = 0; i < byte.arg; i++) { - if(!py_str(begin + i, tmp)) goto __ERROR; - py_Str* item = py_touserdata(tmp); + if(!py_str(begin + i)) goto __ERROR; + py_Str* item = py_touserdata(&self->last_retval); pk_SStream__write_Str(&ss, item); } SP() = begin; - py_newStr_(tmp, pk_SStream__submit(&ss)); - PUSH(tmp); + py_newStr_(SP()++, pk_SStream__submit(&ss)); DISPATCH(); } - /**************************** */ + /*****************************/ + 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(); + } + } + } + } + BinaryOptError(byte.arg); + goto __ERROR; + } + case OP_RETURN_VALUE: { self->last_retval = byte.arg == BC_NOARG ? POPX() : self->None; pk_VM__pop_frame(self); diff --git a/src/interpreter/py_number.c b/src/interpreter/py_number.c index e9c76882..fa562f60 100644 --- a/src/interpreter/py_number.c +++ b/src/interpreter/py_number.c @@ -41,6 +41,7 @@ #define DEF_NUM_BINARY_OP(name, op) \ static bool _py_int##name(int argc, py_Ref argv, py_Ref out) { \ + py_checkargc(2); \ if(py_isint(&argv[1])) { \ int64_t lhs = py_toint(&argv[0]); \ int64_t rhs = py_toint(&argv[1]); \ @@ -55,6 +56,7 @@ return true; \ } \ static bool _py_float##name(int argc, py_Ref argv, py_Ref out) { \ + py_checkargc(2); \ double lhs = py_tofloat(&argv[0]); \ double rhs; \ if(py_castfloat(&argv[1], &rhs)) { \ @@ -78,18 +80,21 @@ DEF_NUM_BINARY_OP(__ge__, >=) #undef DEF_NUM_BINARY_OP static bool _py_int__neg__(int argc, py_Ref argv, py_Ref out) { + py_checkargc(1); int64_t val = py_toint(&argv[0]); py_newint(out, -val); return true; } static bool _py_float__neg__(int argc, py_Ref argv, py_Ref out) { + py_checkargc(1); double val = py_tofloat(&argv[0]); py_newfloat(out, -val); return true; } static bool _py_int__truediv__(int argc, py_Ref argv, py_Ref out) { + py_checkargc(2); int64_t lhs = py_toint(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { @@ -101,6 +106,7 @@ static bool _py_int__truediv__(int argc, py_Ref argv, py_Ref out) { } static bool _py_float__truediv__(int argc, py_Ref argv, py_Ref out) { + py_checkargc(2); double lhs = py_tofloat(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { @@ -114,6 +120,7 @@ static bool _py_float__truediv__(int argc, py_Ref argv, py_Ref out) { #define ZeroDivisionError(msg) false static bool _py_number__pow__(int argc, py_Ref argv, py_Ref out) { + py_checkargc(2); if(py_isint(&argv[0]) && py_isint(&argv[1])) { int64_t lhs = py_toint(&argv[0]); int64_t rhs = py_toint(&argv[1]); @@ -145,6 +152,7 @@ static bool _py_number__pow__(int argc, py_Ref argv, py_Ref out) { } static bool _py_int__floordiv__(int argc, py_Ref argv, py_Ref out) { + py_checkargc(2); int64_t lhs = py_toint(&argv[0]); if(py_isint(&argv[1])) { int64_t rhs = py_toint(&argv[1]); @@ -157,6 +165,7 @@ static bool _py_int__floordiv__(int argc, py_Ref argv, py_Ref out) { } static bool _py_int__mod__(int argc, py_Ref argv, py_Ref out) { + py_checkargc(2); int64_t lhs = py_toint(&argv[0]); if(py_isint(&argv[1])) { int64_t rhs = py_toint(&argv[1]); @@ -169,12 +178,14 @@ static bool _py_int__mod__(int argc, py_Ref argv, py_Ref out) { } static bool _py_int__invert__(int argc, py_Ref argv, py_Ref out) { + py_checkargc(1); int64_t val = py_toint(&argv[0]); py_newint(out, ~val); return true; } static bool _py_int__bit_length(int argc, py_Ref argv, py_Ref out) { + py_checkargc(1); int64_t x = py_toint(py_arg(0)); if(x < 0) x = -x; int bits = 0; @@ -188,6 +199,7 @@ static bool _py_int__bit_length(int argc, py_Ref argv, py_Ref out) { #define DEF_INT_BITWISE_OP(name, op) \ static bool _py_int##name(int argc, py_Ref argv, py_Ref out) { \ + py_checkargc(2); \ int64_t lhs = py_toint(&argv[0]); \ if(py_isint(&argv[1])) { \ int64_t rhs = py_toint(&argv[1]); \ @@ -208,81 +220,53 @@ DEF_INT_BITWISE_OP(__rshift__, >>) void pk_VM__init_builtins(pk_VM* self) { /****** tp_int & tp_float ******/ - py_Ref tmp = py_pushtmp(); - py_Ref int_type = py_pushtmp(); - *int_type = *py_getdict(&self->builtins, py_name("int")); - py_Ref float_type = py_pushtmp(); - *float_type = *py_getdict(&self->builtins, py_name("float")); + py_bindmagic(tp_int, __add__, _py_int__add__); + py_bindmagic(tp_float, __add__, _py_float__add__); + py_bindmagic(tp_int, __sub__, _py_int__sub__); + py_bindmagic(tp_float, __sub__, _py_float__sub__); + py_bindmagic(tp_int, __mul__, _py_int__mul__); + py_bindmagic(tp_float, __mul__, _py_float__mul__); -#define BIND_INT_BINARY_OP(name) \ - py_newnativefunc(tmp, _py_int##name, 2); \ - py_setdict(int_type, name, tmp); - -#define BIND_FLOAT_BINARY_OP(name) \ - py_newnativefunc(tmp, _py_float##name, 2); \ - py_setdict(float_type, name, tmp); - - BIND_INT_BINARY_OP(__add__); - BIND_FLOAT_BINARY_OP(__add__); - BIND_INT_BINARY_OP(__sub__); - BIND_FLOAT_BINARY_OP(__sub__); - BIND_INT_BINARY_OP(__mul__); - BIND_FLOAT_BINARY_OP(__mul__); - - BIND_INT_BINARY_OP(__eq__); - BIND_FLOAT_BINARY_OP(__eq__); - BIND_INT_BINARY_OP(__lt__); - BIND_FLOAT_BINARY_OP(__lt__); - BIND_INT_BINARY_OP(__le__); - BIND_FLOAT_BINARY_OP(__le__); - BIND_INT_BINARY_OP(__gt__); - BIND_FLOAT_BINARY_OP(__gt__); - BIND_INT_BINARY_OP(__ge__); - BIND_FLOAT_BINARY_OP(__ge__); + py_bindmagic(tp_int, __eq__, _py_int__eq__); + py_bindmagic(tp_float, __eq__, _py_float__eq__); + py_bindmagic(tp_int, __lt__, _py_int__lt__); + py_bindmagic(tp_float, __lt__, _py_float__lt__); + py_bindmagic(tp_int, __le__, _py_int__le__); + py_bindmagic(tp_float, __le__, _py_float__le__); + py_bindmagic(tp_int, __gt__, _py_int__gt__); + py_bindmagic(tp_float, __gt__, _py_float__gt__); + py_bindmagic(tp_int, __ge__, _py_int__ge__); + py_bindmagic(tp_float, __ge__, _py_float__ge__); // __neg__ - py_newnativefunc(tmp, _py_int__neg__, 1); - py_setdict(int_type, __neg__, tmp); - py_newnativefunc(tmp, _py_float__neg__, 1); - py_setdict(float_type, __neg__, tmp); + py_bindmagic(tp_int, __neg__, _py_int__neg__); + py_bindmagic(tp_float, __neg__, _py_float__neg__); // TODO: __repr__, __new__, __hash__ // __truediv__ - py_newnativefunc(tmp, _py_int__truediv__, 2); - py_setdict(int_type, __truediv__, tmp); - py_newnativefunc(tmp, _py_float__truediv__, 2); - py_setdict(float_type, __truediv__, tmp); + py_bindmagic(tp_int, __truediv__, _py_int__truediv__); + py_bindmagic(tp_float, __truediv__, _py_float__truediv__); // __pow__ - py_newnativefunc(tmp, _py_number__pow__, 2); - py_setdict(int_type, __pow__, tmp); - py_setdict(float_type, __pow__, tmp); + py_bindmagic(tp_int, __pow__, _py_number__pow__); + py_bindmagic(tp_float, __pow__, _py_number__pow__); // __floordiv__ & __mod__ - py_newnativefunc(tmp, _py_int__floordiv__, 2); - py_setdict(int_type, __floordiv__, tmp); - py_newnativefunc(tmp, _py_int__mod__, 2); - py_setdict(int_type, __mod__, tmp); + py_bindmagic(tp_int, __floordiv__, _py_int__floordiv__); + py_bindmagic(tp_int, __mod__, _py_int__mod__); // int.__invert__ & int. - py_newnativefunc(tmp, _py_int__invert__, 1); - py_setdict(int_type, __invert__, tmp); + py_bindmagic(tp_int, __invert__, _py_int__invert__); - BIND_INT_BINARY_OP(__and__); - BIND_INT_BINARY_OP(__or__); - BIND_INT_BINARY_OP(__xor__); - BIND_INT_BINARY_OP(__lshift__); - BIND_INT_BINARY_OP(__rshift__); + py_bindmagic(tp_int, __and__, _py_int__and__); + py_bindmagic(tp_int, __or__, _py_int__or__); + py_bindmagic(tp_int, __xor__, _py_int__xor__); + py_bindmagic(tp_int, __lshift__, _py_int__lshift__); + py_bindmagic(tp_int, __rshift__, _py_int__rshift__); // int.bit_length - py_newnativefunc(tmp, _py_int__bit_length, 1); - py_setdict(int_type, py_name("bit_length"), tmp); - -#undef BIND_INT_BINARY_OP -#undef BIND_FLOAT_BINARY_OP - - py_poptmp(3); + py_bindmethod(tp_int, "bit_length", _py_int__bit_length); // py_Ref builtins = py_getmodule("builtins"); // py_newfunction(py_reg(0), _py_print, diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 1bbd6319..6e106499 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -108,10 +108,7 @@ void pk_VM__ctor(pk_VM* self) { validate(tp_bool, pk_VM__new_type(self, "bool", tp_object, NULL, false)); validate(tp_str, pk_VM__new_type(self, "str", tp_object, NULL, false)); - validate(tp_list, pk_VM__new_type(self, "list", tp_object, NULL, false)); - pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, tp_list); - ti->dtor = (void (*)(void*))c11_vector__dtor; - + validate(tp_list, pk_list__register()); validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false)); validate(tp_slice, pk_VM__new_type(self, "slice", tp_object, NULL, false)); diff --git a/src/public/py_list.c b/src/public/py_list.c index 71e4c36b..ccc34e17 100644 --- a/src/public/py_list.c +++ b/src/public/py_list.c @@ -6,6 +6,14 @@ typedef c11_vector List; +py_Type pk_list__register() { + pk_VM* vm = pk_current_vm; + py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false); + pk_TypeInfo* ti = c11__at(pk_TypeInfo, &vm->types, type); + ti->dtor = (void (*)(void*))c11_vector__dtor; + return type; +} + void py_newlist(py_Ref out) { pk_VM* vm = pk_current_vm; PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_list, 0, sizeof(List)); diff --git a/src/public/py_ops.c b/src/public/py_ops.c index a6062318..9ed35739 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -7,19 +7,6 @@ int py_le(const py_Ref lhs, const py_Ref rhs) { return 0; } bool py_hash(const py_Ref val, int64_t* out) { return 0; } -bool py_str(const py_Ref val, py_Ref out) { return 0; } - -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__, 0, NULL); - 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_setattr(py_Ref self, py_Name name, const py_Ref val) { return -1; } diff --git a/src/public/values.c b/src/public/values.c index 9205f4bc..e4a35f1f 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -39,7 +39,7 @@ void py_newstrn(py_Ref out, const char* data, int size) { out->_obj = obj; } -void py_newStr_(py_Ref out, py_Str input){ +void py_newStr_(py_Ref out, py_Str input) { pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, sizeof(py_Str)); py_Str* userdata = PyObject__value(obj); @@ -79,30 +79,39 @@ void py_newfunction2(py_Ref out, const char* docstring, const py_Ref upvalue) {} -void py_newnativefunc(py_Ref out, py_CFunction f, int argc) { - py_newnativefunc2(out, f, argc, BindType_FUNCTION, NULL, NULL); +void py_newnativefunc(py_Ref out, py_CFunction f) { + } -void py_newnativefunc2(py_Ref out, - py_CFunction f, - int argc, - BindType bt, - const char* docstring, - const py_Ref upvalue) {} +void py_bindmethod(py_Type type, const char *name, py_CFunction f){ + py_bindmethod2(type, name, f, BindType_FUNCTION); +} + +void py_bindmethod2(py_Type type, const char *name, py_CFunction f, BindType bt){ + py_TValue tmp; + py_newnativefunc(&tmp, f); + py_setdict(py_tpobject(type), py_name(name), &tmp); +} + +void py_bindnativefunc(py_Ref obj, const char *name, py_CFunction f){ + py_TValue tmp; + py_newnativefunc(&tmp, f); + py_setdict(obj, py_name(name), &tmp); +} void py_newnotimplemented(py_Ref out) { pk_VM* vm = pk_current_vm; *out = vm->NotImplemented; } -void py_newslice(py_Ref out, const py_Ref start, const py_Ref stop, const py_Ref step){ +void py_newslice(py_Ref out, const py_Ref start, const py_Ref stop, const py_Ref step) { py_newobject(out, tp_slice, 3, 0); py_setslot(out, 0, start); py_setslot(out, 1, stop); py_setslot(out, 2, step); } -void py_newobject(py_Ref out, py_Type type, int slots, int udsize){ +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); out->type = type; diff --git a/src/public/vm.c b/src/public/vm.c index 4b36afe5..a310e8a4 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -40,35 +40,60 @@ int py_eval(const char* source, py_Ref out) { CodeObject__dtor(&co); PK_DECREF(src); if(res == RES_ERROR) return vm->last_error->type; - if(res == RES_RETURN){ + if(res == RES_RETURN) { *out = vm->last_retval; return 0; } PK_UNREACHABLE(); } -bool py_call(py_Ref f, int argc, py_Ref argv){ +bool py_call(py_Ref f, int argc, py_Ref argv) { return -1; } + +bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1; } + +bool pk_vectorcall(int argc, int kwargc, bool op_call) { return -1; } + +py_Ref py_lastretval() { return &pk_current_vm->last_retval; } + +bool py_getunboundmethod(const py_Ref self, + py_Name name, + bool fallback, + py_Ref out, + py_Ref out_self) { return -1; } -bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv){ - return -1; -} - -int pk_vectorcall(int argc, int kwargc, bool op_call){ - return -1; -} - -py_Ref py_lastretval(){ - return &pk_current_vm->last_retval; -} - -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_TypeInfo* pk_tpinfo(const py_Ref self) { pk_VM* vm = pk_current_vm; return c11__at(pk_TypeInfo, &vm->types, self->type); } +py_Ref py_tpfindmagic(py_Type t, py_Name name) { + assert(name < 64); + pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data; + do { + py_Ref f = &types[t].magic[name]; + if(!py_isnull(f)) return f; + t = types[t].base; + } while(t); + return NULL; +} + +py_Ref py_tpmagic(py_Type type, py_Name name) { + assert(name < 64); + pk_VM* vm = pk_current_vm; + return &c11__at(pk_TypeInfo, &vm->types, type)->magic[name]; +} + +py_Ref py_tpobject(py_Type type) { + pk_VM* vm = pk_current_vm; + return &c11__at(pk_TypeInfo, &vm->types, type)->self; +} + +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); } + return py_call(tmp, argc, argv); +} \ No newline at end of file