some refactor

This commit is contained in:
blueloveTH 2025-06-22 00:31:19 +08:00
parent 02b27b66c5
commit 0f8c7d6d11
15 changed files with 278 additions and 331 deletions

View File

@ -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

View File

@ -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);

View File

@ -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());

View File

@ -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
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;
}

View File

@ -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, "<class '%t'>", 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, "<module '%v'>", 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);
}

127
src/interpreter/vmx.c Normal file
View File

@ -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, "<class '%t'>", 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, "<module '%v'>", 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));
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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 {

View File

@ -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);

45
src/public/typecast.c Normal file
View File

@ -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;
}