Compare commits

...

5 Commits

Author SHA1 Message Date
blueloveTH
f64885f4ca Update main.yml 2025-06-22 01:32:27 +08:00
blueloveTH
9cad7b3d58 Update main.yml 2025-06-22 01:29:02 +08:00
blueloveTH
790710b1a4 backup 2025-06-22 01:12:39 +08:00
blueloveTH
0f8c7d6d11 some refactor 2025-06-22 00:31:19 +08:00
blueloveTH
02b27b66c5 some builtin changes 2025-06-21 20:33:47 +08:00
22 changed files with 333 additions and 367 deletions

View File

@ -56,8 +56,14 @@ jobs:
- name: Setup Clang - name: Setup Clang
uses: egor-tensin/setup-clang@v1 uses: egor-tensin/setup-clang@v1
with: with:
version: 15 version: 17
platform: x64 platform: x64
- name: Run Sanitizers
run: |
sudo apt-get install -y libclang-rt-17-dev
bash build_g.sh
bash run_tests.sh
rm -rf ./main
- name: Unit Test with Coverage - name: Unit Test with Coverage
run: bash run_tests.sh run: bash run_tests.sh
- name: Upload coverage reports to Codecov - name: Upload coverage reports to Codecov

View File

@ -20,6 +20,11 @@ if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ox") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ox")
add_definitions(-DNDEBUG) add_definitions(-DNDEBUG)
endif() endif()
# if(CMAKE_BUILD_TYPE STREQUAL "Debug")
# message(">> Enable Address Sanitizer")
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Zi")
# endif()
else() else()
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
@ -99,6 +104,9 @@ if(PK_ENABLE_DETERMINISM)
endif() endif()
endif() endif()
find_package(Threads REQUIRED)
target_link_libraries(${PROJECT_NAME} Threads::Threads)
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
if(NOT PK_ENABLE_DETERMINISM) if(NOT PK_ENABLE_DETERMINISM)
# use platform libm # use platform libm

View File

@ -4,10 +4,9 @@
#include "pocketpy/common/vector.h" #include "pocketpy/common/vector.h"
#include "pocketpy/objects/object.h" #include "pocketpy/objects/object.h"
#define PK_MAX_CHUNK_LENGTH 256
typedef struct py_TypeInfo { typedef struct py_TypeInfo {
py_Name name; py_Name name;
py_Type index;
py_Type base; py_Type base;
struct py_TypeInfo* base_ti; 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_python; // is it a python class? (not derived from c object)
bool is_sealed; // can it be subclassed? bool is_sealed; // can it be subclassed?
void (*dtor)(void*); py_Dtor dtor; // destructor for this type, NULL if no dtor
py_TValue annotations; py_TValue annotations;
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
} py_TypeInfo; } py_TypeInfo;
typedef struct TypeList { py_TypeInfo* pk_typeinfo(py_Type type);
int length; py_ItemRef pk_tpfindname(py_TypeInfo* ti, py_Name name);
py_TypeInfo* chunks[PK_MAX_CHUNK_LENGTH]; #define pk_tpfindmagic pk_tpfindname
} 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);

View File

@ -29,14 +29,19 @@ typedef struct WatchdogInfo {
clock_t max_reset_time; clock_t max_reset_time;
} WatchdogInfo; } WatchdogInfo;
typedef struct TypePointer {
py_TypeInfo* ti;
py_Dtor dtor;
} TypePointer;
typedef struct VM { typedef struct VM {
py_Frame* top_frame; py_Frame* top_frame;
BinTree modules; BinTree modules;
TypeList types; c11_vector /*TypePointer*/ types;
py_TValue builtins; // builtins module py_GlobalRef builtins; // builtins module
py_TValue main; // __main__ module py_GlobalRef main; // __main__ module
py_Callbacks callbacks; py_Callbacks callbacks;
@ -80,7 +85,7 @@ bool pk__parse_int_slice(py_Ref slice,
bool pk__normalize_index(int* index, int length); bool pk__normalize_index(int* index, int length);
bool pk__object_new(int argc, py_Ref argv); 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); bool pk_wrapper__self(int argc, py_Ref argv);
@ -152,7 +157,7 @@ py_Type pk_generator__register();
py_Type pk_namedict__register(); py_Type pk_namedict__register();
py_Type pk_code__register(); py_Type pk_code__register();
py_TValue pk_builtins__register(); py_GlobalRef pk_builtins__register();
/* mappingproxy */ /* mappingproxy */
void pk_mappingproxy__namedict(py_Ref out, py_Ref object); void pk_mappingproxy__namedict(py_Ref out, py_Ref object);

View File

@ -118,6 +118,8 @@ PK_API void py_setvmctx(void* ctx);
PK_API void py_sys_setargv(int argc, char** argv); PK_API void py_sys_setargv(int argc, char** argv);
/// Set the trace function for the current VM. /// Set the trace function for the current VM.
PK_API void py_sys_settrace(py_TraceFunc func, bool reset); PK_API void py_sys_settrace(py_TraceFunc func, bool reset);
/// Invoke the garbage collector.
PK_API int py_gc_collect();
/// Setup the callbacks for the current VM. /// Setup the callbacks for the current VM.
PK_API py_Callbacks* py_callbacks(); PK_API py_Callbacks* py_callbacks();

View File

@ -255,7 +255,7 @@ FrameResult VM__run_top_frame(VM* self) {
} }
if(res == -1) goto __ERROR; if(res == -1) goto __ERROR;
// builtins // builtins
py_Ref tmp = py_getdict(&self->builtins, name); py_Ref tmp = py_getdict(self->builtins, name);
if(tmp != NULL) { if(tmp != NULL) {
PUSH(tmp); PUSH(tmp);
DISPATCH(); DISPATCH();
@ -277,7 +277,7 @@ FrameResult VM__run_top_frame(VM* self) {
} }
if(res == -1) goto __ERROR; if(res == -1) goto __ERROR;
tmp = py_getdict(&self->builtins, name); tmp = py_getdict(self->builtins, name);
if(tmp != NULL) { if(tmp != NULL) {
PUSH(tmp); PUSH(tmp);
DISPATCH(); DISPATCH();
@ -293,7 +293,7 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH(); DISPATCH();
} }
if(res == -1) goto __ERROR; if(res == -1) goto __ERROR;
py_Ref tmp = py_getdict(&self->builtins, name); py_Ref tmp = py_getdict(self->builtins, name);
if(tmp != NULL) { if(tmp != NULL) {
PUSH(tmp); PUSH(tmp);
DISPATCH(); DISPATCH();
@ -325,7 +325,7 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH(); DISPATCH();
} }
if(res == -1) goto __ERROR; if(res == -1) goto __ERROR;
tmp = py_getdict(&self->builtins, name); tmp = py_getdict(self->builtins, name);
if(tmp) { if(tmp) {
PUSH(tmp); PUSH(tmp);
DISPATCH(); DISPATCH();
@ -505,7 +505,7 @@ FrameResult VM__run_top_frame(VM* self) {
/*****************************************/ /*****************************************/
case OP_BUILD_IMAG: { case OP_BUILD_IMAG: {
// [x] // [x]
py_Ref f = py_getdict(&self->builtins, py_name("complex")); py_Ref f = py_getdict(self->builtins, py_name("complex"));
assert(f != NULL); assert(f != NULL);
py_TValue tmp = *TOP(); py_TValue tmp = *TOP();
*TOP() = *f; // [complex] *TOP() = *f; // [complex]
@ -558,7 +558,7 @@ FrameResult VM__run_top_frame(VM* self) {
} }
case OP_BUILD_SET: { case OP_BUILD_SET: {
py_TValue* begin = SP() - byte.arg; py_TValue* begin = SP() - byte.arg;
py_Ref typeobject_set = py_getdict(&self->builtins, py_name("set")); py_Ref typeobject_set = py_getdict(self->builtins, py_name("set"));
assert(typeobject_set != NULL); assert(typeobject_set != NULL);
py_push(typeobject_set); py_push(typeobject_set);
py_pushnil(); py_pushnil();
@ -1036,7 +1036,7 @@ FrameResult VM__run_top_frame(VM* self) {
} }
POP(); POP();
py_TypeInfo* base_ti = TypeList__get(&self->types, base); py_TypeInfo* base_ti = pk_typeinfo(base);
if(base_ti->is_sealed) { if(base_ti->is_sealed) {
TypeError("type '%t' is not an acceptable base type", base); TypeError("type '%t' is not an acceptable base type", base);
goto __ERROR; goto __ERROR;
@ -1059,7 +1059,7 @@ FrameResult VM__run_top_frame(VM* self) {
if(py_istype(TOP(), tp_type)) { if(py_istype(TOP(), tp_type)) {
// call on_end_subclass // 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) { if(ti->base != tp_object) {
py_TypeInfo* base_ti = ti->base_ti; py_TypeInfo* base_ti = ti->base_ti;
if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti); if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
@ -1079,8 +1079,6 @@ FrameResult VM__run_top_frame(VM* self) {
} }
case OP_STORE_CLASS_ATTR: { case OP_STORE_CLASS_ATTR: {
assert(self->curr_class); assert(self->curr_class);
py_Type type = py_totype(self->curr_class);
py_TypeInfo* ti = TypeList__get(&self->types, type);
py_Name name = co_names[byte.arg]; py_Name name = co_names[byte.arg];
// TOP() can be a function, classmethod or custom decorator // TOP() can be a function, classmethod or custom decorator
py_Ref actual_func = TOP(); py_Ref actual_func = TOP();
@ -1098,8 +1096,7 @@ FrameResult VM__run_top_frame(VM* self) {
case OP_ADD_CLASS_ANNOTATION: { case OP_ADD_CLASS_ANNOTATION: {
assert(self->curr_class); assert(self->curr_class);
// [type_hint string] // [type_hint string]
py_Type type = py_totype(self->curr_class); py_TypeInfo* ti = py_touserdata(self->curr_class);
py_TypeInfo* ti = TypeList__get(&self->types, type);
if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations); if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations);
py_Name name = co_names[byte.arg]; py_Name name = co_names[byte.arg];
bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP()); bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP());

View File

@ -194,7 +194,7 @@ const char* py_Frame_sourceloc(py_Frame* self, int* lineno) {
void py_Frame_newglobals(py_Frame* frame, py_OutRef out) { void py_Frame_newglobals(py_Frame* frame, py_OutRef out) {
if(!frame) { if(!frame) {
pk_mappingproxy__namedict(out, &pk_current_vm->main); pk_mappingproxy__namedict(out, pk_current_vm->main);
return; return;
} }
if(frame->globals->type == tp_module) { if(frame->globals->type == tp_module) {

View File

@ -1,51 +1,49 @@
#include "pocketpy/interpreter/typeinfo.h" #include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/utils.h"
#define CHUNK_SIZE 128 py_ItemRef pk_tpfindname(py_TypeInfo* ti, py_Name name) {
#define LOG2_CHUNK_SIZE 7 assert(ti != NULL);
do {
void TypeList__ctor(TypeList* self) { py_Ref res = py_getdict(&ti->self, name);
self->length = 0; if(res) return res;
memset(self->chunks, 0, sizeof(self->chunks)); ti = ti->base_ti;
} while(ti);
return NULL;
} }
void TypeList__dtor(TypeList* self) { py_ItemRef py_tpfindname(py_Type type, py_Name name) {
for(py_Type t = 0; t < self->length; t++) { py_TypeInfo* ti = pk_typeinfo(type);
py_TypeInfo* info = TypeList__get(self, t); return pk_tpfindname(ti, name);
(void)info;
}
for(int i = 0; i < PK_MAX_CHUNK_LENGTH; i++) {
if(self->chunks[i]) PK_FREE(self->chunks[i]);
}
} }
py_TypeInfo* TypeList__get(TypeList* self, py_Type index) { py_Ref py_tpfindmagic(py_Type t, py_Name name) {
assert(index < self->length); // assert(py_ismagicname(name));
int chunk = index >> LOG2_CHUNK_SIZE; return py_tpfindname(t, name);
int offset = index & (CHUNK_SIZE - 1);
return self->chunks[chunk] + offset;
} }
py_TypeInfo* TypeList__emplace(TypeList* self) { py_Type py_tpbase(py_Type t) {
int chunk = self->length >> LOG2_CHUNK_SIZE; assert(t);
int offset = self->length & (CHUNK_SIZE - 1); py_TypeInfo* ti = pk_typeinfo(t);
if(self->chunks[chunk] == NULL) { return ti->base;
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;
} }
void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx) { PK_DEPRECATED py_Ref py_tpgetmagic(py_Type type, py_Name name) {
for(int i = 0; i < self->length; i++) { // assert(py_ismagicname(name));
py_TypeInfo* info = TypeList__get(self, i); py_TypeInfo* ti = pk_typeinfo(type);
f(info, ctx); py_Ref retval = py_getdict(&ti->self, name);
} return retval != NULL ? retval : py_NIL();
} }
#undef CHUNK_SIZE py_Ref py_tpobject(py_Type type) {
#undef LOG2_CHUNK_SIZE 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); } 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) { static int BinTree__cmp_cstr(void* lhs, void* rhs) {
const char* l = (const char*)lhs; const char* l = (const char*)lhs;
const char* r = (const char*)rhs; const char* r = (const char*)rhs;
return strcmp(l, r); 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) { void VM__ctor(VM* self) {
self->top_frame = NULL; self->top_frame = NULL;
@ -81,10 +53,10 @@ void VM__ctor(VM* self) {
.need_free_key = true, .need_free_key = true,
}; };
BinTree__ctor(&self->modules, c11_strdup(""), py_NIL(), &modules_config); BinTree__ctor(&self->modules, c11_strdup(""), py_NIL(), &modules_config);
TypeList__ctor(&self->types); c11_vector__ctor(&self->types, sizeof(TypePointer));
self->builtins = *py_NIL(); self->builtins = NULL;
self->main = *py_NIL(); self->main = NULL;
self->callbacks.importfile = pk_default_importfile; self->callbacks.importfile = pk_default_importfile;
self->callbacks.print = pk_default_print; self->callbacks.print = pk_default_print;
@ -116,14 +88,15 @@ void VM__ctor(VM* self) {
/* Init Builtin Types */ /* Init Builtin Types */
// 0: unused // 0: unused
void* placeholder = TypeList__emplace(&self->types); TypePointer* placeholder = c11_vector__emplace(&self->types);
memset(placeholder, 0, sizeof(py_TypeInfo)); placeholder->ti = NULL;
placeholder->dtor = NULL;
#define validate(t, expr) \ #define validate(t, expr) \
if(t != (expr)) abort() if(t != (expr)) abort()
validate(tp_object, pk_newtype("object", 0, NULL, NULL, true, false)); validate(tp_object, pk_newtype("object", tp_nil, NULL, NULL, true, false));
validate(tp_type, pk_newtype("type", 1, NULL, NULL, false, true)); validate(tp_type, pk_newtype("type", tp_object, NULL, NULL, false, true));
pk_object__register(); pk_object__register();
validate(tp_int, pk_newtype("int", tp_object, NULL, NULL, false, true)); validate(tp_int, pk_newtype("int", tp_object, NULL, NULL, false, true));
@ -175,8 +148,8 @@ void VM__ctor(VM* self) {
// inject some builtin exceptions // inject some builtin exceptions
#define INJECT_BUILTIN_EXC(name, TBase) \ #define INJECT_BUILTIN_EXC(name, TBase) \
do { \ do { \
py_Type type = pk_newtype(#name, TBase, &self->builtins, NULL, false, true); \ py_Type type = pk_newtype(#name, TBase, self->builtins, NULL, false, true); \
py_setdict(&self->builtins, py_name(#name), py_tpobject(type)); \ py_setdict(self->builtins, py_name(#name), py_tpobject(type)); \
validate(tp_##name, type); \ validate(tp_##name, type); \
} while(0) } while(0)
@ -184,7 +157,7 @@ void VM__ctor(VM* self) {
INJECT_BUILTIN_EXC(KeyboardInterrupt, tp_BaseException); INJECT_BUILTIN_EXC(KeyboardInterrupt, tp_BaseException);
validate(tp_StopIteration, pk_StopIteration__register()); validate(tp_StopIteration, pk_StopIteration__register());
py_setdict(&self->builtins, py_name("StopIteration"), py_tpobject(tp_StopIteration)); py_setdict(self->builtins, py_name("StopIteration"), py_tpobject(tp_StopIteration));
INJECT_BUILTIN_EXC(SyntaxError, tp_Exception); INJECT_BUILTIN_EXC(SyntaxError, tp_Exception);
INJECT_BUILTIN_EXC(RecursionError, tp_Exception); INJECT_BUILTIN_EXC(RecursionError, tp_Exception);
@ -229,11 +202,11 @@ void VM__ctor(VM* self) {
}; };
for(int i = 0; i < c11__count_array(public_types); i++) { 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); py_setdict(self->builtins, ti->name, &ti->self);
} }
py_newnotimplemented(py_emplacedict(&self->builtins, py_name("NotImplemented"))); py_newnotimplemented(py_emplacedict(self->builtins, py_name("NotImplemented")));
pk__add_module_vmath(); pk__add_module_vmath();
pk__add_module_array2d(); pk__add_module_array2d();
@ -266,7 +239,7 @@ void VM__ctor(VM* self) {
// add python builtins // add python builtins
do { do {
bool ok; bool ok;
ok = py_exec(kPythonLibs_builtins, "<builtins>", EXEC_MODE, &self->builtins); ok = py_exec(kPythonLibs_builtins, "<builtins>", EXEC_MODE, self->builtins);
if(!ok) goto __ABORT; if(!ok) goto __ABORT;
break; break;
__ABORT: __ABORT:
@ -274,7 +247,7 @@ void VM__ctor(VM* self) {
c11__abort("failed to load python builtins!"); c11__abort("failed to load python builtins!");
} while(0); } while(0);
self->main = *py_newmodule("__main__"); self->main = py_newmodule("__main__");
} }
void VM__dtor(VM* self) { void VM__dtor(VM* self) {
@ -287,11 +260,11 @@ void VM__dtor(VM* self) {
while(self->top_frame) while(self->top_frame)
VM__pop_frame(self); VM__pop_frame(self);
BinTree__dtor(&self->modules); BinTree__dtor(&self->modules);
TypeList__dtor(&self->types);
FixedMemoryPool__dtor(&self->pool_frame); FixedMemoryPool__dtor(&self->pool_frame);
ValueStack__dtor(&self->stack); ValueStack__dtor(&self->stack);
CachedNames__dtor(&self->cached_names); CachedNames__dtor(&self->cached_names);
NameDict__dtor(&self->compile_time_funcs); NameDict__dtor(&self->compile_time_funcs);
c11_vector__dtor(&self->types);
} }
void VM__push_frame(VM* self, py_Frame* frame) { void VM__push_frame(VM* self, py_Frame* frame) {
@ -398,16 +371,30 @@ py_Type pk_newtype(const char* name,
bool is_python, bool is_python,
bool is_sealed) { bool is_sealed) {
py_Type index = pk_current_vm->types.length; py_Type index = pk_current_vm->types.length;
py_TypeInfo* ti = TypeList__emplace(&pk_current_vm->types); py_TypeInfo* self = py_newobject(py_retval(), tp_type, -1, sizeof(py_TypeInfo));
py_TypeInfo* base_ti = base ? pk__type_info(base) : NULL; py_TypeInfo* base_ti = base ? pk_typeinfo(base) : NULL;
if(base_ti && base_ti->is_sealed) { if(base_ti && base_ti->is_sealed) {
c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name)); 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; if(!dtor && base) dtor = base_ti->dtor;
ti->dtor = dtor; self->is_python = is_python;
ti->is_python = is_python; self->is_sealed = is_sealed;
ti->is_sealed = is_sealed; self->dtor = dtor;
TypePointer* pointer = c11_vector__emplace(&pk_current_vm->types);
pointer->ti = self;
pointer->dtor = dtor;
return index; 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) { void FuncDecl__gc_mark(const FuncDecl* self, c11_vector* p_stack) {
CodeObject__gc_mark(&self->code, p_stack); CodeObject__gc_mark(&self->code, p_stack);
for(int j = 0; j < self->kwargs.length; j++) { for(int j = 0; j < self->kwargs.length; j++) {
@ -684,10 +665,8 @@ void ManagedHeap__mark(ManagedHeap* self) {
int types_length = vm->types.length; int types_length = vm->types.length;
// 0-th type is placeholder // 0-th type is placeholder
for(py_Type i = 1; i < types_length; i++) { for(py_Type i = 1; i < types_length; i++) {
py_TypeInfo* ti = TypeList__get(&vm->types, i); py_TypeInfo* ti = c11__getitem(TypePointer, &vm->types, i).ti;
// mark type object
pk__mark_value(&ti->self); pk__mark_value(&ti->self);
// mark type annotations
pk__mark_value(&ti->annotations); pk__mark_value(&ti->annotations);
} }
// mark frame // 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, "name", Enum__name, NULL);
py_bindproperty(type, "value", Enum__value, 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

@ -1,7 +1,7 @@
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
static bool gc_collect(int argc, py_Ref argv){ static bool gc_collect(int argc, py_Ref argv) {
PY_CHECK_ARGC(0); PY_CHECK_ARGC(0);
ManagedHeap* heap = &pk_current_vm->heap; ManagedHeap* heap = &pk_current_vm->heap;
int res = ManagedHeap__collect(heap); int res = ManagedHeap__collect(heap);
@ -9,7 +9,7 @@ static bool gc_collect(int argc, py_Ref argv){
return true; return true;
} }
static bool gc_enable(int argc, py_Ref argv){ static bool gc_enable(int argc, py_Ref argv) {
PY_CHECK_ARGC(0); PY_CHECK_ARGC(0);
ManagedHeap* heap = &pk_current_vm->heap; ManagedHeap* heap = &pk_current_vm->heap;
heap->gc_enabled = true; heap->gc_enabled = true;
@ -17,7 +17,7 @@ static bool gc_enable(int argc, py_Ref argv){
return true; return true;
} }
static bool gc_disable(int argc, py_Ref argv){ static bool gc_disable(int argc, py_Ref argv) {
PY_CHECK_ARGC(0); PY_CHECK_ARGC(0);
ManagedHeap* heap = &pk_current_vm->heap; ManagedHeap* heap = &pk_current_vm->heap;
heap->gc_enabled = false; heap->gc_enabled = false;
@ -25,7 +25,7 @@ static bool gc_disable(int argc, py_Ref argv){
return true; return true;
} }
static bool gc_isenabled(int argc, py_Ref argv){ static bool gc_isenabled(int argc, py_Ref argv) {
PY_CHECK_ARGC(0); PY_CHECK_ARGC(0);
ManagedHeap* heap = &pk_current_vm->heap; ManagedHeap* heap = &pk_current_vm->heap;
py_newbool(py_retval(), heap->gc_enabled); py_newbool(py_retval(), heap->gc_enabled);
@ -39,4 +39,9 @@ void pk__add_module_gc() {
py_bindfunc(mod, "enable", gc_enable); py_bindfunc(mod, "enable", gc_enable);
py_bindfunc(mod, "disable", gc_disable); py_bindfunc(mod, "disable", gc_disable);
py_bindfunc(mod, "isenabled", gc_isenabled); py_bindfunc(mod, "isenabled", gc_isenabled);
}
int py_gc_collect() {
ManagedHeap* heap = &pk_current_vm->heap;
return ManagedHeap__collect(heap);
} }

View File

@ -229,7 +229,7 @@ void pk__add_module_io() {
py_newint(py_emplacedict(mod, py_name("SEEK_CUR")), SEEK_CUR); py_newint(py_emplacedict(mod, py_name("SEEK_CUR")), SEEK_CUR);
py_newint(py_emplacedict(mod, py_name("SEEK_END")), SEEK_END); py_newint(py_emplacedict(mod, py_name("SEEK_END")), SEEK_END);
py_setdict(&pk_current_vm->builtins, py_name("open"), py_tpobject(FileIO)); py_setdict(pk_current_vm->builtins, py_name("open"), py_tpobject(FileIO));
} }
#else #else

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) { 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)) { if(py_isnil(ti->module)) {
c11_sbuf__write_cstr(path_buf, py_name2str(ti->name)); c11_sbuf__write_cstr(path_buf, py_name2str(ti->name));
return; return;
@ -349,7 +349,7 @@ static bool pkl__write_object(PickleObject* buf, py_TValue* obj) {
// try memo for `is_ptr=true` objects // try memo for `is_ptr=true` objects
if(pkl__try_memo(buf, obj->_obj)) return true; 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__); py_Ref f_reduce = py_tpfindmagic(obj->type, __reduce__);
if(f_reduce != NULL) { if(f_reduce != NULL) {
if(!py_call(f_reduce, 1, obj)) return false; 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) { static bool pkpy_is_user_defined_type(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_type); 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); py_newbool(py_retval(), ti->is_python);
return true; return true;
} }

View File

@ -45,49 +45,11 @@ bool py_tobool(py_Ref self) {
py_Type py_totype(py_Ref self) { py_Type py_totype(py_Ref self) {
assert(self->type == tp_type); assert(self->type == tp_type);
py_Type* ud = py_touserdata(self); py_TypeInfo* ud = py_touserdata(self);
return *ud; return ud->index;
} }
void* py_touserdata(py_Ref self) { void* py_touserdata(py_Ref self) {
assert(self && self->is_ptr); assert(self && self->is_ptr);
return PyObject__userdata(self->_obj); 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

@ -49,7 +49,7 @@ bool py_compile(const char* source,
bool pk_exec(CodeObject* co, py_Ref module) { bool pk_exec(CodeObject* co, py_Ref module) {
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
if(!module) module = &vm->main; if(!module) module = vm->main;
assert(module->type == tp_module); assert(module->type == tp_module);
py_StackRef sp = vm->stack.sp; py_StackRef sp = vm->stack.sp;
@ -63,7 +63,7 @@ bool pk_exec(CodeObject* co, py_Ref module) {
bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals) { bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals) {
VM* vm = pk_current_vm; VM* vm = pk_current_vm;
if(!module) module = &vm->main; if(!module) module = vm->main;
assert(module->type == tp_module); assert(module->type == tp_module);
py_StackRef sp = vm->stack.sp; py_StackRef sp = vm->stack.sp;

View File

@ -238,7 +238,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
break; break;
case tp_classmethod: case tp_classmethod:
self[0] = *py_getslot(cls_var, 0); self[0] = *py_getslot(cls_var, 0);
self[1] = pk__type_info(type)->self; self[1] = pk_typeinfo(type)->self;
break; break;
default: c11__unreachable(); default: c11__unreachable();
} }
@ -247,45 +247,6 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
return false; 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) { bool py_tpcall(py_Type type, int argc, py_Ref argv) {
return py_call(py_tpobject(type), argc, argv); return py_call(py_tpobject(type), argc, argv);
} }

View File

@ -16,11 +16,11 @@ py_Ref py_getmodule(const char* path) {
return BinTree__try_get(&vm->modules, (void*)path); return BinTree__try_get(&vm->modules, (void*)path);
} }
py_Ref py_getbuiltin(py_Name name) { return py_getdict(&pk_current_vm->builtins, name); } py_Ref py_getbuiltin(py_Name name) { return py_getdict(pk_current_vm->builtins, name); }
py_Ref py_getglobal(py_Name name) { return py_getdict(&pk_current_vm->main, name); } py_Ref py_getglobal(py_Name name) { return py_getdict(pk_current_vm->main, name); }
void py_setglobal(py_Name name, py_Ref val) { py_setdict(&pk_current_vm->main, name, val); } void py_setglobal(py_Name name, py_Ref val) { py_setdict(pk_current_vm->main, name, val); }
py_Ref py_newmodule(const char* path) { py_Ref py_newmodule(const char* path) {
ManagedHeap* heap = &pk_current_vm->heap; ManagedHeap* heap = &pk_current_vm->heap;
@ -608,7 +608,7 @@ static bool builtins_eval(int argc, py_Ref argv) {
static bool static bool
pk_smartexec(const char* source, py_Ref module, enum py_CompileMode mode, va_list args) { pk_smartexec(const char* source, py_Ref module, enum py_CompileMode mode, va_list args) {
if(module == NULL) module = &pk_current_vm->main; if(module == NULL) module = pk_current_vm->main;
pk_mappingproxy__namedict(py_pushtmp(), module); // globals pk_mappingproxy__namedict(py_pushtmp(), module); // globals
py_newdict(py_pushtmp()); // locals py_newdict(py_pushtmp()); // locals
bool ok = py_compile(source, "<string>", mode, true); bool ok = py_compile(source, "<string>", mode, true);
@ -716,8 +716,8 @@ static bool NotImplementedType__repr__(int argc, py_Ref argv) {
return true; return true;
} }
py_TValue pk_builtins__register() { py_GlobalRef pk_builtins__register() {
py_Ref builtins = py_newmodule("builtins"); py_GlobalRef builtins = py_newmodule("builtins");
py_bindfunc(builtins, "exit", builtins_exit); py_bindfunc(builtins, "exit", builtins_exit);
py_bindfunc(builtins, "input", builtins_input); py_bindfunc(builtins, "input", builtins_input);
py_bindfunc(builtins, "repr", builtins_repr); py_bindfunc(builtins, "repr", builtins_repr);
@ -760,7 +760,7 @@ py_TValue pk_builtins__register() {
py_setdict(py_tpobject(tp_ellipsis), __hash__, py_None()); py_setdict(py_tpobject(tp_ellipsis), __hash__, py_None());
py_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__); py_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__);
py_setdict(py_tpobject(tp_NotImplementedType), __hash__, py_None()); py_setdict(py_tpobject(tp_NotImplementedType), __hash__, py_None());
return *builtins; return builtins;
} }
void function__gc_mark(void* ud, c11_vector* p_stack) { void function__gc_mark(void* ud, c11_vector* p_stack) {
@ -843,7 +843,7 @@ static bool super__new__(int argc, py_Ref argv) {
if(callable->type == tp_function) { if(callable->type == tp_function) {
Function* func = py_touserdata(callable); Function* func = py_touserdata(callable);
if(func->clazz != NULL) { 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]; } 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(class_arg == 0 || self_arg == NULL) return RuntimeError("super(): no arguments");
if(self_arg->type == tp_type) { if(self_arg->type == tp_type) {
// f(cls, ...) // 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"); if(class_arg == 0) return RuntimeError("super(): base class is invalid");
py_assign(py_retval(), py_tpobject(class_arg)); py_assign(py_retval(), py_tpobject(class_arg));
return true; return true;
@ -868,7 +868,7 @@ static bool super__new__(int argc, py_Ref argv) {
return TypeError("super() takes 0 or 2 arguments"); 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"); 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)); 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) { bool pk__object_new(int argc, py_Ref argv) {
if(argc == 0) return TypeError("object.__new__(): not enough arguments"); if(argc == 0) return TypeError("object.__new__(): not enough arguments");
py_Type cls = py_totype(py_arg(0)); py_TypeInfo* ti = py_touserdata(argv);
py_TypeInfo* ti = pk__type_info(cls); py_Type cls = ti->index;
if(!ti->is_python) { if(!ti->is_python) {
return TypeError("object.__new__(%t) is not safe, use %t.__new__() instead", cls, cls); 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) { static bool type__base__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
py_TypeInfo* ti = pk__type_info(py_totype(argv)); py_TypeInfo* ti = py_touserdata(argv);
if(ti->base) { if(ti->base) {
py_assign(py_retval(), &ti->base_ti->self); py_assign(py_retval(), &ti->base_ti->self);
} else { } else {
@ -83,7 +83,7 @@ static bool type__base__(int argc, py_Ref argv) {
static bool type__name__(int argc, py_Ref argv) { static bool type__name__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); 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)); py_assign(py_retval(), py_name2ref(ti->name));
return true; return true;
} }
@ -100,7 +100,7 @@ static bool type__or__(int argc, py_Ref argv) {
static bool type__module__(int argc, py_Ref argv) { static bool type__module__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
py_TypeInfo* ti = pk__type_info(py_totype(argv)); py_TypeInfo* ti = py_touserdata(argv);
if(py_isnil(ti->module)) { if(py_isnil(ti->module)) {
py_newnone(py_retval()); py_newnone(py_retval());
} else { } else {
@ -112,7 +112,7 @@ static bool type__module__(int argc, py_Ref argv) {
static bool type__annotations__(int argc, py_Ref argv) { static bool type__annotations__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
py_TypeInfo* ti = pk__type_info(py_totype(argv)); py_TypeInfo* ti = py_touserdata(argv);
if(py_isnil(&ti->annotations)) { if(py_isnil(&ti->annotations)) {
py_newdict(py_retval()); py_newdict(py_retval());
} else { } else {

View File

@ -52,7 +52,7 @@ int py_bool(py_Ref val) {
} }
bool py_hash(py_Ref val, int64_t* out) { 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 { do {
py_Ref slot_hash = py_getdict(&ti->self, __hash__); py_Ref slot_hash = py_getdict(&ti->self, __hash__);
if(slot_hash && py_isnone(slot_hash)) break; 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) { bool py_getattr(py_Ref self, py_Name name) {
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
py_Type type = self->type; py_TypeInfo* ti = pk_typeinfo(self->type);
py_Ref cls_var = py_tpfindname(type, name); py_Ref cls_var = pk_tpfindname(ti, name);
if(cls_var) { if(cls_var) {
// handle descriptor // handle descriptor
if(py_istype(cls_var, tp_property)) { if(py_istype(cls_var, tp_property)) {
@ -111,8 +111,9 @@ bool py_getattr(py_Ref self, py_Name name) {
return true; return true;
} }
} else { } else {
py_Type* inner_type = py_touserdata(self); // self is a type object
py_Ref res = py_tpfindname(*inner_type, name); py_TypeInfo* inner_type = py_touserdata(self);
py_Ref res = pk_tpfindname(inner_type, name);
if(res) { if(res) {
if(py_istype(res, tp_staticmethod)) { if(py_istype(res, tp_staticmethod)) {
res = py_getslot(res, 0); res = py_getslot(res, 0);
@ -145,7 +146,7 @@ bool py_getattr(py_Ref self, py_Name name) {
return true; return true;
} }
case tp_classmethod: { 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; return true;
} }
default: { 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) { if(fallback) {
py_push(fallback); py_push(fallback);
py_push(self); 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;
}