diff --git a/include/pocketpy/interpreter/typeinfo.h b/include/pocketpy/interpreter/typeinfo.h index 958ff3a1..340920fc 100644 --- a/include/pocketpy/interpreter/typeinfo.h +++ b/include/pocketpy/interpreter/typeinfo.h @@ -4,10 +4,9 @@ #include "pocketpy/common/vector.h" #include "pocketpy/objects/object.h" -#define PK_MAX_CHUNK_LENGTH 256 - typedef struct py_TypeInfo { py_Name name; + py_Type index; py_Type base; struct py_TypeInfo* base_ti; @@ -17,20 +16,13 @@ typedef struct py_TypeInfo { bool is_python; // is it a python class? (not derived from c object) bool is_sealed; // can it be subclassed? - void (*dtor)(void*); + py_Dtor dtor; // destructor for this type, NULL if no dtor py_TValue annotations; void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module } py_TypeInfo; -typedef struct TypeList { - int length; - py_TypeInfo* chunks[PK_MAX_CHUNK_LENGTH]; -} TypeList; - -void TypeList__ctor(TypeList* self); -void TypeList__dtor(TypeList* self); -py_TypeInfo* TypeList__get(TypeList* self, py_Type index); -py_TypeInfo* TypeList__emplace(TypeList* self); -void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx); +py_TypeInfo* pk_typeinfo(py_Type type); +py_ItemRef pk_tpfindname(py_TypeInfo* ti, py_Name name); +#define pk_tpfindmagic pk_tpfindname \ No newline at end of file diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 61c30880..3592fea5 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -29,11 +29,16 @@ typedef struct WatchdogInfo { clock_t max_reset_time; } WatchdogInfo; +typedef struct TypePointer { + py_TypeInfo* ti; + py_Dtor dtor; +} TypePointer; + typedef struct VM { py_Frame* top_frame; BinTree modules; - TypeList types; + c11_vector /*TypePointer*/ types; py_GlobalRef builtins; // builtins module py_GlobalRef main; // __main__ module @@ -80,7 +85,7 @@ bool pk__parse_int_slice(py_Ref slice, bool pk__normalize_index(int* index, int length); bool pk__object_new(int argc, py_Ref argv); -py_TypeInfo* pk__type_info(py_Type type); +py_TypeInfo* pk_typeinfo(py_Type type); bool pk_wrapper__self(int argc, py_Ref argv); diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index cf355cd0..5c391e40 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -1036,7 +1036,7 @@ FrameResult VM__run_top_frame(VM* self) { } POP(); - py_TypeInfo* base_ti = TypeList__get(&self->types, base); + py_TypeInfo* base_ti = pk_typeinfo(base); if(base_ti->is_sealed) { TypeError("type '%t' is not an acceptable base type", base); goto __ERROR; @@ -1059,7 +1059,7 @@ FrameResult VM__run_top_frame(VM* self) { if(py_istype(TOP(), tp_type)) { // call on_end_subclass - py_TypeInfo* ti = TypeList__get(&self->types, py_totype(TOP())); + py_TypeInfo* ti = py_touserdata(TOP()); if(ti->base != tp_object) { py_TypeInfo* base_ti = ti->base_ti; if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti); @@ -1096,8 +1096,7 @@ FrameResult VM__run_top_frame(VM* self) { case OP_ADD_CLASS_ANNOTATION: { assert(self->curr_class); // [type_hint string] - py_Type type = py_totype(self->curr_class); - py_TypeInfo* ti = TypeList__get(&self->types, type); + py_TypeInfo* ti = py_touserdata(self->curr_class); if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations); py_Name name = co_names[byte.arg]; bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP()); diff --git a/src/interpreter/typeinfo.c b/src/interpreter/typeinfo.c index 7d352ae6..db543c01 100644 --- a/src/interpreter/typeinfo.c +++ b/src/interpreter/typeinfo.c @@ -1,51 +1,49 @@ -#include "pocketpy/interpreter/typeinfo.h" -#include "pocketpy/common/utils.h" +#include "pocketpy/interpreter/vm.h" -#define CHUNK_SIZE 128 -#define LOG2_CHUNK_SIZE 7 - -void TypeList__ctor(TypeList* self) { - self->length = 0; - memset(self->chunks, 0, sizeof(self->chunks)); +py_ItemRef pk_tpfindname(py_TypeInfo* ti, py_Name name) { + assert(ti != NULL); + do { + py_Ref res = py_getdict(&ti->self, name); + if(res) return res; + ti = ti->base_ti; + } while(ti); + return NULL; } -void TypeList__dtor(TypeList* self) { - for(py_Type t = 0; t < self->length; t++) { - py_TypeInfo* info = TypeList__get(self, t); - (void)info; - } - for(int i = 0; i < PK_MAX_CHUNK_LENGTH; i++) { - if(self->chunks[i]) PK_FREE(self->chunks[i]); - } +py_ItemRef py_tpfindname(py_Type type, py_Name name) { + py_TypeInfo* ti = pk_typeinfo(type); + return pk_tpfindname(ti, name); } -py_TypeInfo* TypeList__get(TypeList* self, py_Type index) { - assert(index < self->length); - int chunk = index >> LOG2_CHUNK_SIZE; - int offset = index & (CHUNK_SIZE - 1); - return self->chunks[chunk] + offset; +py_Ref py_tpfindmagic(py_Type t, py_Name name) { + // assert(py_ismagicname(name)); + return py_tpfindname(t, name); } -py_TypeInfo* TypeList__emplace(TypeList* self) { - int chunk = self->length >> LOG2_CHUNK_SIZE; - int offset = self->length & (CHUNK_SIZE - 1); - if(self->chunks[chunk] == NULL) { - if(chunk >= PK_MAX_CHUNK_LENGTH) { - c11__abort("TypeList__emplace(): max chunk length exceeded"); - } - self->chunks[chunk] = PK_MALLOC(sizeof(py_TypeInfo) * CHUNK_SIZE); - memset(self->chunks[chunk], 0, sizeof(py_TypeInfo) * CHUNK_SIZE); - } - self->length++; - return self->chunks[chunk] + offset; +py_Type py_tpbase(py_Type t) { + assert(t); + py_TypeInfo* ti = pk_typeinfo(t); + return ti->base; } -void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx) { - for(int i = 0; i < self->length; i++) { - py_TypeInfo* info = TypeList__get(self, i); - f(info, ctx); - } +PK_DEPRECATED py_Ref py_tpgetmagic(py_Type type, py_Name name) { + // assert(py_ismagicname(name)); + py_TypeInfo* ti = pk_typeinfo(type); + py_Ref retval = py_getdict(&ti->self, name); + return retval != NULL ? retval : py_NIL(); } -#undef CHUNK_SIZE -#undef LOG2_CHUNK_SIZE \ No newline at end of file +py_Ref py_tpobject(py_Type type) { + assert(type); + return &pk_typeinfo(type)->self; +} + +const char* py_tpname(py_Type type) { + if(!type) return "nil"; + py_Name name = pk_typeinfo(type)->name; + return py_name2str(name); +} + +py_TypeInfo* pk_typeinfo(py_Type type) { + return c11__getitem(TypePointer, &pk_current_vm->types, type).ti; +} \ No newline at end of file diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 952e873b..fa3771fa 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -39,40 +39,12 @@ void LineProfiler__tracefunc(py_Frame* frame, enum py_TraceEvent event) { if(self->enabled && event == TRACE_EVENT_LINE) { LineProfiler__tracefunc_line(self, frame); } } -static void py_TypeInfo__ctor(py_TypeInfo* self, - py_Name name, - py_Type index, - py_Type base, - py_TypeInfo* base_ti, - py_GlobalRef module) { - memset(self, 0, sizeof(py_TypeInfo)); - - self->name = name; - self->base = base; - self->base_ti = base_ti; - - // create type object with __dict__ - ManagedHeap* heap = &pk_current_vm->heap; - PyObject* typeobj = ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type)); - *(py_Type*)PyObject__userdata(typeobj) = index; - self->self = (py_TValue){ - .type = typeobj->type, - .is_ptr = true, - ._obj = typeobj, - }; - - self->module = module; - self->annotations = *py_NIL(); -} - static int BinTree__cmp_cstr(void* lhs, void* rhs) { const char* l = (const char*)lhs; const char* r = (const char*)rhs; return strcmp(l, r); } -static int BinTree__cmp_voidp(void* lhs, void* rhs) { return lhs < rhs ? -1 : (lhs > rhs ? 1 : 0); } - void VM__ctor(VM* self) { self->top_frame = NULL; @@ -81,7 +53,7 @@ void VM__ctor(VM* self) { .need_free_key = true, }; BinTree__ctor(&self->modules, c11_strdup(""), py_NIL(), &modules_config); - TypeList__ctor(&self->types); + c11_vector__ctor(&self->types, sizeof(TypePointer)); self->builtins = NULL; self->main = NULL; @@ -116,14 +88,15 @@ void VM__ctor(VM* self) { /* Init Builtin Types */ // 0: unused - void* placeholder = TypeList__emplace(&self->types); - memset(placeholder, 0, sizeof(py_TypeInfo)); + TypePointer* placeholder = c11_vector__emplace(&self->types); + placeholder->ti = NULL; + placeholder->dtor = NULL; #define validate(t, expr) \ if(t != (expr)) abort() - validate(tp_object, pk_newtype("object", 0, NULL, NULL, true, false)); - validate(tp_type, pk_newtype("type", 1, NULL, NULL, false, true)); + validate(tp_object, pk_newtype("object", tp_nil, NULL, NULL, true, false)); + validate(tp_type, pk_newtype("type", tp_object, NULL, NULL, false, true)); pk_object__register(); validate(tp_int, pk_newtype("int", tp_object, NULL, NULL, false, true)); @@ -229,7 +202,7 @@ void VM__ctor(VM* self) { }; for(int i = 0; i < c11__count_array(public_types); i++) { - py_TypeInfo* ti = pk__type_info(public_types[i]); + py_TypeInfo* ti = pk_typeinfo(public_types[i]); py_setdict(self->builtins, ti->name, &ti->self); } @@ -287,7 +260,7 @@ void VM__dtor(VM* self) { while(self->top_frame) VM__pop_frame(self); BinTree__dtor(&self->modules); - TypeList__dtor(&self->types); + c11_vector__dtor(&self->types); FixedMemoryPool__dtor(&self->pool_frame); ValueStack__dtor(&self->stack); CachedNames__dtor(&self->cached_names); @@ -398,16 +371,30 @@ py_Type pk_newtype(const char* name, bool is_python, bool is_sealed) { py_Type index = pk_current_vm->types.length; - py_TypeInfo* ti = TypeList__emplace(&pk_current_vm->types); - py_TypeInfo* base_ti = base ? pk__type_info(base) : NULL; + py_TypeInfo* self = py_newobject(py_retval(), tp_type, -1, sizeof(py_TypeInfo)); + py_TypeInfo* base_ti = base ? pk_typeinfo(base) : NULL; if(base_ti && base_ti->is_sealed) { c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name)); } - py_TypeInfo__ctor(ti, py_name(name), index, base, base_ti, module ? module : py_NIL()); + + memset(self, 0, sizeof(py_TypeInfo)); + self->name = py_name(name); + self->index = index; + self->base = base; + self->base_ti = base_ti; + + self->self = *py_retval(); + self->module = module ? module : py_NIL(); + self->annotations = *py_NIL(); + if(!dtor && base) dtor = base_ti->dtor; - ti->dtor = dtor; - ti->is_python = is_python; - ti->is_sealed = is_sealed; + self->is_python = is_python; + self->is_sealed = is_sealed; + self->dtor = dtor; + + TypePointer* pointer = c11_vector__emplace(&pk_current_vm->types); + pointer->ti = self; + pointer->dtor = dtor; return index; } @@ -628,12 +615,6 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall } /****************************************/ -void PyObject__dtor(PyObject* self) { - py_TypeInfo* ti = pk__type_info(self->type); - if(ti->dtor) ti->dtor(PyObject__userdata(self)); - if(self->slots == -1) NameDict__dtor(PyObject__dict(self)); -} - void FuncDecl__gc_mark(const FuncDecl* self, c11_vector* p_stack) { CodeObject__gc_mark(&self->code, p_stack); for(int j = 0; j < self->kwargs.length; j++) { @@ -684,10 +665,8 @@ void ManagedHeap__mark(ManagedHeap* self) { int types_length = vm->types.length; // 0-th type is placeholder for(py_Type i = 1; i < types_length; i++) { - py_TypeInfo* ti = TypeList__get(&vm->types, i); - // mark type object + py_TypeInfo* ti = c11__getitem(TypePointer, &vm->types, i).ti; pk__mark_value(&ti->self); - // mark type annotations pk__mark_value(&ti->annotations); } // mark frame @@ -763,125 +742,3 @@ void ManagedHeap__mark(ManagedHeap* self) { } } } - -void pk_print_stack(VM* self, py_Frame* frame, Bytecode byte) { - return; - if(frame == NULL || py_isnil(self->main)) return; - - py_TValue* sp = self->stack.sp; - c11_sbuf buf; - c11_sbuf__ctor(&buf); - for(py_Ref p = self->stack.begin; p != sp; p++) { - switch(p->type) { - case tp_nil: c11_sbuf__write_cstr(&buf, "nil"); break; - case tp_int: c11_sbuf__write_i64(&buf, p->_i64); break; - case tp_float: c11_sbuf__write_f64(&buf, p->_f64, -1); break; - case tp_bool: c11_sbuf__write_cstr(&buf, p->_bool ? "True" : "False"); break; - case tp_NoneType: c11_sbuf__write_cstr(&buf, "None"); break; - case tp_list: { - pk_sprintf(&buf, "list(%d)", py_list_len(p)); - break; - } - case tp_tuple: { - pk_sprintf(&buf, "tuple(%d)", py_tuple_len(p)); - break; - } - case tp_function: { - Function* ud = py_touserdata(p); - c11_sbuf__write_cstr(&buf, ud->decl->code.name->data); - c11_sbuf__write_cstr(&buf, "()"); - break; - } - case tp_type: { - pk_sprintf(&buf, "", py_totype(p)); - break; - } - case tp_str: { - pk_sprintf(&buf, "%q", py_tosv(p)); - break; - } - case tp_module: { - py_Ref path = py_getdict(p, __path__); - pk_sprintf(&buf, "", py_tosv(path)); - break; - } - default: { - pk_sprintf(&buf, "(%t)", p->type); - break; - } - } - if(p != &sp[-1]) c11_sbuf__write_cstr(&buf, ", "); - } - c11_string* stack_str = c11_sbuf__submit(&buf); - - printf("%s:%-3d: %-25s %-6d [%s]\n", - frame->co->src->filename->data, - Frame__lineno(frame), - pk_opname(byte.op), - byte.arg, - stack_str->data); - c11_string__delete(stack_str); -} - -bool pk_wrapper__self(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - py_assign(py_retval(), argv); - return true; -} - -py_TypeInfo* pk__type_info(py_Type type) { return TypeList__get(&pk_current_vm->types, type); } - -int py_replinput(char* buf, int max_size) { - buf[0] = '\0'; // reset first char because we check '@' at the beginning - - int size = 0; - bool multiline = false; - printf(">>> "); - - while(true) { - int c = pk_current_vm->callbacks.getchr(); - if(c == EOF) return -1; - - if(c == '\n') { - char last = '\0'; - if(size > 0) last = buf[size - 1]; - if(multiline) { - if(last == '\n') { - break; // 2 consecutive newlines to end multiline input - } else { - printf("... "); - } - } else { - if(last == ':' || last == '(' || last == '[' || last == '{' || buf[0] == '@') { - printf("... "); - multiline = true; - } else { - break; - } - } - } - - if(size == max_size - 1) { - buf[size] = '\0'; - return size; - } - - buf[size++] = c; - } - - buf[size] = '\0'; - return size; -} - -py_Ref py_name2ref(py_Name name) { - assert(name != NULL); - CachedNames* d = &pk_current_vm->cached_names; - py_Ref res = CachedNames__try_get(d, name); - if(res != NULL) return res; - // not found, create a new one - py_StackRef tmp = py_pushtmp(); - py_newstrv(tmp, py_name2sv(name)); - CachedNames__set(d, name, tmp); - py_pop(); - return CachedNames__try_get(d, name); -} \ No newline at end of file diff --git a/src/interpreter/vmx.c b/src/interpreter/vmx.c new file mode 100644 index 00000000..e9b25876 --- /dev/null +++ b/src/interpreter/vmx.c @@ -0,0 +1,127 @@ +#include "pocketpy/interpreter/vm.h" + +void pk_print_stack(VM* self, py_Frame* frame, Bytecode byte) { + return; + if(frame == NULL || py_isnil(self->main)) return; + + py_TValue* sp = self->stack.sp; + c11_sbuf buf; + c11_sbuf__ctor(&buf); + for(py_Ref p = self->stack.begin; p != sp; p++) { + switch(p->type) { + case tp_nil: c11_sbuf__write_cstr(&buf, "nil"); break; + case tp_int: c11_sbuf__write_i64(&buf, p->_i64); break; + case tp_float: c11_sbuf__write_f64(&buf, p->_f64, -1); break; + case tp_bool: c11_sbuf__write_cstr(&buf, p->_bool ? "True" : "False"); break; + case tp_NoneType: c11_sbuf__write_cstr(&buf, "None"); break; + case tp_list: { + pk_sprintf(&buf, "list(%d)", py_list_len(p)); + break; + } + case tp_tuple: { + pk_sprintf(&buf, "tuple(%d)", py_tuple_len(p)); + break; + } + case tp_function: { + Function* ud = py_touserdata(p); + c11_sbuf__write_cstr(&buf, ud->decl->code.name->data); + c11_sbuf__write_cstr(&buf, "()"); + break; + } + case tp_type: { + pk_sprintf(&buf, "", py_totype(p)); + break; + } + case tp_str: { + pk_sprintf(&buf, "%q", py_tosv(p)); + break; + } + case tp_module: { + py_Ref path = py_getdict(p, __path__); + pk_sprintf(&buf, "", py_tosv(path)); + break; + } + default: { + pk_sprintf(&buf, "(%t)", p->type); + break; + } + } + if(p != &sp[-1]) c11_sbuf__write_cstr(&buf, ", "); + } + c11_string* stack_str = c11_sbuf__submit(&buf); + + printf("%s:%-3d: %-25s %-6d [%s]\n", + frame->co->src->filename->data, + Frame__lineno(frame), + pk_opname(byte.op), + byte.arg, + stack_str->data); + c11_string__delete(stack_str); +} + +bool pk_wrapper__self(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + py_assign(py_retval(), argv); + return true; +} + +int py_replinput(char* buf, int max_size) { + buf[0] = '\0'; // reset first char because we check '@' at the beginning + + int size = 0; + bool multiline = false; + printf(">>> "); + + while(true) { + int c = pk_current_vm->callbacks.getchr(); + if(c == EOF) return -1; + + if(c == '\n') { + char last = '\0'; + if(size > 0) last = buf[size - 1]; + if(multiline) { + if(last == '\n') { + break; // 2 consecutive newlines to end multiline input + } else { + printf("... "); + } + } else { + if(last == ':' || last == '(' || last == '[' || last == '{' || buf[0] == '@') { + printf("... "); + multiline = true; + } else { + break; + } + } + } + + if(size == max_size - 1) { + buf[size] = '\0'; + return size; + } + + buf[size++] = c; + } + + buf[size] = '\0'; + return size; +} + +py_Ref py_name2ref(py_Name name) { + assert(name != NULL); + CachedNames* d = &pk_current_vm->cached_names; + py_Ref res = CachedNames__try_get(d, name); + if(res != NULL) return res; + // not found, create a new one + py_StackRef tmp = py_pushtmp(); + py_newstrv(tmp, py_name2sv(name)); + CachedNames__set(d, name, tmp); + py_pop(); + return CachedNames__try_get(d, name); +} + +void PyObject__dtor(PyObject* self) { + py_Dtor dtor = c11__getitem(TypePointer, &pk_current_vm->types, self->type).dtor; + if(dtor) dtor(PyObject__userdata(self)); + if(self->slots == -1) NameDict__dtor(PyObject__dict(self)); +} \ No newline at end of file diff --git a/src/modules/enum.c b/src/modules/enum.c index f63fa3a1..9c7a5659 100644 --- a/src/modules/enum.c +++ b/src/modules/enum.c @@ -86,5 +86,5 @@ void pk__add_module_enum() { py_bindproperty(type, "name", Enum__name, NULL); py_bindproperty(type, "value", Enum__value, NULL); - pk__type_info(type)->on_end_subclass = Enum__on_end_subclass; + pk_typeinfo(type)->on_end_subclass = Enum__on_end_subclass; } \ No newline at end of file diff --git a/src/modules/pickle.c b/src/modules/pickle.c index 3777371c..1c8f92b2 100644 --- a/src/modules/pickle.c +++ b/src/modules/pickle.c @@ -61,7 +61,7 @@ static void PickleObject__write_bytes(PickleObject* buf, const void* data, int s } static void c11_sbuf__write_type_path(c11_sbuf* path_buf, py_Type type) { - py_TypeInfo* ti = pk__type_info(type); + py_TypeInfo* ti = pk_typeinfo(type); if(py_isnil(ti->module)) { c11_sbuf__write_cstr(path_buf, py_name2str(ti->name)); return; @@ -349,7 +349,7 @@ static bool pkl__write_object(PickleObject* buf, py_TValue* obj) { // try memo for `is_ptr=true` objects if(pkl__try_memo(buf, obj->_obj)) return true; - py_TypeInfo* ti = pk__type_info(obj->type); + py_TypeInfo* ti = pk_typeinfo(obj->type); py_Ref f_reduce = py_tpfindmagic(obj->type, __reduce__); if(f_reduce != NULL) { if(!py_call(f_reduce, 1, obj)) return false; diff --git a/src/modules/pkpy.c b/src/modules/pkpy.c index 397f71d9..58bbc8a6 100644 --- a/src/modules/pkpy.c +++ b/src/modules/pkpy.c @@ -60,7 +60,7 @@ static bool pkpy_memory_usage(int argc, py_Ref argv) { static bool pkpy_is_user_defined_type(int argc, py_Ref argv) { PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_type); - py_TypeInfo* ti = pk__type_info(py_totype(argv)); + py_TypeInfo* ti = py_touserdata(argv); py_newbool(py_retval(), ti->is_python); return true; } diff --git a/src/public/cast.c b/src/public/cast.c index dd1b44bb..4deabef1 100644 --- a/src/public/cast.c +++ b/src/public/cast.c @@ -45,49 +45,11 @@ bool py_tobool(py_Ref self) { py_Type py_totype(py_Ref self) { assert(self->type == tp_type); - py_Type* ud = py_touserdata(self); - return *ud; + py_TypeInfo* ud = py_touserdata(self); + return ud->index; } void* py_touserdata(py_Ref self) { assert(self && self->is_ptr); return PyObject__userdata(self->_obj); } - -bool py_istype(py_Ref self, py_Type type) { return self->type == type; } - -bool py_checktype(py_Ref self, py_Type type) { - if(self->type == type) return true; - return TypeError("expected '%t', got '%t'", type, self->type); -} - -bool py_checkinstance(py_Ref self, py_Type type) { - if(py_isinstance(self, type)) return true; - return TypeError("expected '%t' or its subclass, got '%t'", type, self->type); -} - -bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); } - -bool py_issubclass(py_Type derived, py_Type base) { - TypeList* types = &pk_current_vm->types; - do { - if(derived == base) return true; - derived = TypeList__get(types, derived)->base; - } while(derived); - return false; -} - -py_Type py_typeof(py_Ref self) { return self->type; } - -py_Type py_gettype(const char* module, py_Name name) { - py_Ref mod; - if(module != NULL) { - mod = py_getmodule(module); - if(!mod) return 0; - } else { - mod = pk_current_vm->builtins; - } - py_Ref object = py_getdict(mod, name); - if(object && py_istype(object, tp_type)) return py_totype(object); - return 0; -} \ No newline at end of file diff --git a/src/public/internal.c b/src/public/internal.c index 8a9628d5..c7be8853 100644 --- a/src/public/internal.c +++ b/src/public/internal.c @@ -238,7 +238,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) { break; case tp_classmethod: self[0] = *py_getslot(cls_var, 0); - self[1] = pk__type_info(type)->self; + self[1] = pk_typeinfo(type)->self; break; default: c11__unreachable(); } @@ -247,45 +247,6 @@ bool pk_loadmethod(py_StackRef self, py_Name name) { return false; } -py_Ref py_tpfindmagic(py_Type t, py_Name name) { - // assert(py_ismagicname(name)); - return py_tpfindname(t, name); -} - -py_Ref py_tpfindname(py_Type t, py_Name name) { - py_TypeInfo* ti = pk__type_info(t); - do { - py_Ref res = py_getdict(&ti->self, name); - if(res) return res; - ti = ti->base_ti; - } while(ti); - return NULL; -} - -py_Type py_tpbase(py_Type t) { - assert(t); - py_TypeInfo* ti = pk__type_info(t); - return ti->base; -} - -PK_DEPRECATED py_Ref py_tpgetmagic(py_Type type, py_Name name) { - // assert(py_ismagicname(name)); - py_TypeInfo* ti = pk__type_info(type); - py_Ref retval = py_getdict(&ti->self, name); - return retval != NULL ? retval : py_NIL(); -} - -py_Ref py_tpobject(py_Type type) { - assert(type); - return &pk__type_info(type)->self; -} - -const char* py_tpname(py_Type type) { - if(!type) return "nil"; - py_Name name = pk__type_info(type)->name; - return py_name2str(name); -} - bool py_tpcall(py_Type type, int argc, py_Ref argv) { return py_call(py_tpobject(type), argc, argv); } diff --git a/src/public/modules.c b/src/public/modules.c index a1d0d98d..8ffa0348 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -843,7 +843,7 @@ static bool super__new__(int argc, py_Ref argv) { if(callable->type == tp_function) { Function* func = py_touserdata(callable); if(func->clazz != NULL) { - class_arg = *(py_Type*)PyObject__userdata(func->clazz); + class_arg = ((py_TypeInfo*)PyObject__userdata(func->clazz))->index; if(frame->co->nlocals > 0) { self_arg = &frame->locals[0]; } } } @@ -851,7 +851,7 @@ static bool super__new__(int argc, py_Ref argv) { if(class_arg == 0 || self_arg == NULL) return RuntimeError("super(): no arguments"); if(self_arg->type == tp_type) { // f(cls, ...) - class_arg = pk__type_info(class_arg)->base; + class_arg = pk_typeinfo(class_arg)->base; if(class_arg == 0) return RuntimeError("super(): base class is invalid"); py_assign(py_retval(), py_tpobject(class_arg)); return true; @@ -868,7 +868,7 @@ static bool super__new__(int argc, py_Ref argv) { return TypeError("super() takes 0 or 2 arguments"); } - class_arg = pk__type_info(class_arg)->base; + class_arg = pk_typeinfo(class_arg)->base; if(class_arg == 0) return RuntimeError("super(): base class is invalid"); py_Type* p_class_arg = py_newobject(py_retval(), tp_super, 1, sizeof(py_Type)); diff --git a/src/public/py_object.c b/src/public/py_object.c index c056642e..6ed83760 100644 --- a/src/public/py_object.c +++ b/src/public/py_object.c @@ -4,8 +4,8 @@ bool pk__object_new(int argc, py_Ref argv) { if(argc == 0) return TypeError("object.__new__(): not enough arguments"); - py_Type cls = py_totype(py_arg(0)); - py_TypeInfo* ti = pk__type_info(cls); + py_TypeInfo* ti = py_touserdata(argv); + py_Type cls = ti->index; if(!ti->is_python) { return TypeError("object.__new__(%t) is not safe, use %t.__new__() instead", cls, cls); } @@ -72,7 +72,7 @@ static bool type__new__(int argc, py_Ref argv) { static bool type__base__(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - py_TypeInfo* ti = pk__type_info(py_totype(argv)); + py_TypeInfo* ti = py_touserdata(argv); if(ti->base) { py_assign(py_retval(), &ti->base_ti->self); } else { @@ -83,7 +83,7 @@ static bool type__base__(int argc, py_Ref argv) { static bool type__name__(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - py_TypeInfo* ti = pk__type_info(py_totype(argv)); + py_TypeInfo* ti = py_touserdata(argv); py_assign(py_retval(), py_name2ref(ti->name)); return true; } @@ -100,7 +100,7 @@ static bool type__or__(int argc, py_Ref argv) { static bool type__module__(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - py_TypeInfo* ti = pk__type_info(py_totype(argv)); + py_TypeInfo* ti = py_touserdata(argv); if(py_isnil(ti->module)) { py_newnone(py_retval()); } else { @@ -112,7 +112,7 @@ static bool type__module__(int argc, py_Ref argv) { static bool type__annotations__(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - py_TypeInfo* ti = pk__type_info(py_totype(argv)); + py_TypeInfo* ti = py_touserdata(argv); if(py_isnil(&ti->annotations)) { py_newdict(py_retval()); } else { diff --git a/src/public/py_ops.c b/src/public/py_ops.c index ed643c86..a6a60214 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -52,7 +52,7 @@ int py_bool(py_Ref val) { } bool py_hash(py_Ref val, int64_t* out) { - py_TypeInfo* ti = pk__type_info(val->type); + py_TypeInfo* ti = pk_typeinfo(val->type); do { py_Ref slot_hash = py_getdict(&ti->self, __hash__); if(slot_hash && py_isnone(slot_hash)) break; @@ -93,8 +93,8 @@ int py_next(py_Ref val) { bool py_getattr(py_Ref self, py_Name name) { // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance - py_Type type = self->type; - py_Ref cls_var = py_tpfindname(type, name); + py_TypeInfo* ti = pk_typeinfo(self->type); + py_Ref cls_var = pk_tpfindname(ti, name); if(cls_var) { // handle descriptor if(py_istype(cls_var, tp_property)) { @@ -111,8 +111,9 @@ bool py_getattr(py_Ref self, py_Name name) { return true; } } else { - py_Type* inner_type = py_touserdata(self); - py_Ref res = py_tpfindname(*inner_type, name); + // self is a type object + py_TypeInfo* inner_type = py_touserdata(self); + py_Ref res = pk_tpfindname(inner_type, name); if(res) { if(py_istype(res, tp_staticmethod)) { res = py_getslot(res, 0); @@ -145,7 +146,7 @@ bool py_getattr(py_Ref self, py_Name name) { return true; } case tp_classmethod: { - py_newboundmethod(py_retval(), py_tpobject(type), py_getslot(cls_var, 0)); + py_newboundmethod(py_retval(), &ti->self, py_getslot(cls_var, 0)); return true; } default: { @@ -156,7 +157,7 @@ bool py_getattr(py_Ref self, py_Name name) { } } - py_Ref fallback = py_tpfindmagic(type, __getattr__); + py_Ref fallback = pk_tpfindmagic(ti, __getattr__); if(fallback) { py_push(fallback); py_push(self); diff --git a/src/public/typecast.c b/src/public/typecast.c new file mode 100644 index 00000000..a00fd491 --- /dev/null +++ b/src/public/typecast.c @@ -0,0 +1,45 @@ +#include "pocketpy/objects/base.h" +#include "pocketpy/pocketpy.h" + +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +bool py_istype(py_Ref self, py_Type type) { return self->type == type; } + +bool py_checktype(py_Ref self, py_Type type) { + if(self->type == type) return true; + return TypeError("expected '%t', got '%t'", type, self->type); +} + +bool py_checkinstance(py_Ref self, py_Type type) { + if(py_isinstance(self, type)) return true; + return TypeError("expected '%t' or its subclass, got '%t'", type, self->type); +} + +bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); } + +bool py_issubclass(py_Type derived, py_Type base) { + assert(derived != 0 && base != 0); + py_TypeInfo* derived_ti = pk_typeinfo(derived); + py_TypeInfo* base_ti = pk_typeinfo(base); + do { + if(derived_ti == base_ti) return true; + derived_ti = derived_ti->base_ti; + } while(derived_ti); + return false; +} + +py_Type py_typeof(py_Ref self) { return self->type; } + +py_Type py_gettype(const char* module, py_Name name) { + py_Ref mod; + if(module != NULL) { + mod = py_getmodule(module); + if(!mod) return tp_nil; + } else { + mod = pk_current_vm->builtins; + } + py_Ref object = py_getdict(mod, name); + if(object && py_istype(object, tp_type)) return py_totype(object); + return tp_nil; +} \ No newline at end of file