mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-23 21:10:19 +00:00
Compare commits
5 Commits
4bb0ae3035
...
f64885f4ca
Author | SHA1 | Date | |
---|---|---|---|
|
f64885f4ca | ||
|
9cad7b3d58 | ||
|
790710b1a4 | ||
|
0f8c7d6d11 | ||
|
02b27b66c5 |
8
.github/workflows/main.yml
vendored
8
.github/workflows/main.yml
vendored
@ -56,8 +56,14 @@ jobs:
|
||||
- name: Setup Clang
|
||||
uses: egor-tensin/setup-clang@v1
|
||||
with:
|
||||
version: 15
|
||||
version: 17
|
||||
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
|
||||
run: bash run_tests.sh
|
||||
- name: Upload coverage reports to Codecov
|
||||
|
@ -20,6 +20,11 @@ if(MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ox")
|
||||
add_definitions(-DNDEBUG)
|
||||
endif()
|
||||
|
||||
# if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
# message(">> Enable Address Sanitizer")
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Zi")
|
||||
# endif()
|
||||
else()
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
@ -99,6 +104,9 @@ if(PK_ENABLE_DETERMINISM)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} Threads::Threads)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(NOT PK_ENABLE_DETERMINISM)
|
||||
# use platform libm
|
||||
|
@ -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
|
@ -29,14 +29,19 @@ 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_TValue builtins; // builtins module
|
||||
py_TValue main; // __main__ module
|
||||
py_GlobalRef builtins; // builtins module
|
||||
py_GlobalRef main; // __main__ module
|
||||
|
||||
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__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);
|
||||
|
||||
@ -152,7 +157,7 @@ py_Type pk_generator__register();
|
||||
py_Type pk_namedict__register();
|
||||
py_Type pk_code__register();
|
||||
|
||||
py_TValue pk_builtins__register();
|
||||
py_GlobalRef pk_builtins__register();
|
||||
|
||||
/* mappingproxy */
|
||||
void pk_mappingproxy__namedict(py_Ref out, py_Ref object);
|
@ -118,6 +118,8 @@ PK_API void py_setvmctx(void* ctx);
|
||||
PK_API void py_sys_setargv(int argc, char** argv);
|
||||
/// Set the trace function for the current VM.
|
||||
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.
|
||||
PK_API py_Callbacks* py_callbacks();
|
||||
|
||||
|
@ -255,7 +255,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
if(res == -1) goto __ERROR;
|
||||
// builtins
|
||||
py_Ref tmp = py_getdict(&self->builtins, name);
|
||||
py_Ref tmp = py_getdict(self->builtins, name);
|
||||
if(tmp != NULL) {
|
||||
PUSH(tmp);
|
||||
DISPATCH();
|
||||
@ -277,7 +277,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
if(res == -1) goto __ERROR;
|
||||
|
||||
tmp = py_getdict(&self->builtins, name);
|
||||
tmp = py_getdict(self->builtins, name);
|
||||
if(tmp != NULL) {
|
||||
PUSH(tmp);
|
||||
DISPATCH();
|
||||
@ -293,7 +293,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
DISPATCH();
|
||||
}
|
||||
if(res == -1) goto __ERROR;
|
||||
py_Ref tmp = py_getdict(&self->builtins, name);
|
||||
py_Ref tmp = py_getdict(self->builtins, name);
|
||||
if(tmp != NULL) {
|
||||
PUSH(tmp);
|
||||
DISPATCH();
|
||||
@ -325,7 +325,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
DISPATCH();
|
||||
}
|
||||
if(res == -1) goto __ERROR;
|
||||
tmp = py_getdict(&self->builtins, name);
|
||||
tmp = py_getdict(self->builtins, name);
|
||||
if(tmp) {
|
||||
PUSH(tmp);
|
||||
DISPATCH();
|
||||
@ -505,7 +505,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
/*****************************************/
|
||||
case OP_BUILD_IMAG: {
|
||||
// [x]
|
||||
py_Ref f = py_getdict(&self->builtins, py_name("complex"));
|
||||
py_Ref f = py_getdict(self->builtins, py_name("complex"));
|
||||
assert(f != NULL);
|
||||
py_TValue tmp = *TOP();
|
||||
*TOP() = *f; // [complex]
|
||||
@ -558,7 +558,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
case OP_BUILD_SET: {
|
||||
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);
|
||||
py_push(typeobject_set);
|
||||
py_pushnil();
|
||||
@ -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);
|
||||
@ -1079,8 +1079,6 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
case OP_STORE_CLASS_ATTR: {
|
||||
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];
|
||||
// TOP() can be a function, classmethod or custom decorator
|
||||
py_Ref actual_func = TOP();
|
||||
@ -1098,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());
|
||||
|
@ -194,7 +194,7 @@ const char* py_Frame_sourceloc(py_Frame* self, int* lineno) {
|
||||
|
||||
void py_Frame_newglobals(py_Frame* frame, py_OutRef out) {
|
||||
if(!frame) {
|
||||
pk_mappingproxy__namedict(out, &pk_current_vm->main);
|
||||
pk_mappingproxy__namedict(out, pk_current_vm->main);
|
||||
return;
|
||||
}
|
||||
if(frame->globals->type == tp_module) {
|
||||
|
@ -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;
|
||||
}
|
@ -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,10 +53,10 @@ 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 = *py_NIL();
|
||||
self->main = *py_NIL();
|
||||
self->builtins = NULL;
|
||||
self->main = NULL;
|
||||
|
||||
self->callbacks.importfile = pk_default_importfile;
|
||||
self->callbacks.print = pk_default_print;
|
||||
@ -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));
|
||||
@ -175,8 +148,8 @@ void VM__ctor(VM* self) {
|
||||
// inject some builtin exceptions
|
||||
#define INJECT_BUILTIN_EXC(name, TBase) \
|
||||
do { \
|
||||
py_Type type = pk_newtype(#name, TBase, &self->builtins, NULL, false, true); \
|
||||
py_setdict(&self->builtins, py_name(#name), py_tpobject(type)); \
|
||||
py_Type type = pk_newtype(#name, TBase, self->builtins, NULL, false, true); \
|
||||
py_setdict(self->builtins, py_name(#name), py_tpobject(type)); \
|
||||
validate(tp_##name, type); \
|
||||
} while(0)
|
||||
|
||||
@ -184,7 +157,7 @@ void VM__ctor(VM* self) {
|
||||
INJECT_BUILTIN_EXC(KeyboardInterrupt, tp_BaseException);
|
||||
|
||||
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(RecursionError, tp_Exception);
|
||||
@ -229,11 +202,11 @@ 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_setdict(&self->builtins, ti->name, &ti->self);
|
||||
py_TypeInfo* ti = pk_typeinfo(public_types[i]);
|
||||
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_array2d();
|
||||
@ -266,7 +239,7 @@ void VM__ctor(VM* self) {
|
||||
// add python builtins
|
||||
do {
|
||||
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;
|
||||
break;
|
||||
__ABORT:
|
||||
@ -274,7 +247,7 @@ void VM__ctor(VM* self) {
|
||||
c11__abort("failed to load python builtins!");
|
||||
} while(0);
|
||||
|
||||
self->main = *py_newmodule("__main__");
|
||||
self->main = py_newmodule("__main__");
|
||||
}
|
||||
|
||||
void VM__dtor(VM* self) {
|
||||
@ -287,11 +260,11 @@ void VM__dtor(VM* self) {
|
||||
while(self->top_frame)
|
||||
VM__pop_frame(self);
|
||||
BinTree__dtor(&self->modules);
|
||||
TypeList__dtor(&self->types);
|
||||
FixedMemoryPool__dtor(&self->pool_frame);
|
||||
ValueStack__dtor(&self->stack);
|
||||
CachedNames__dtor(&self->cached_names);
|
||||
NameDict__dtor(&self->compile_time_funcs);
|
||||
c11_vector__dtor(&self->types);
|
||||
}
|
||||
|
||||
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_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
127
src/interpreter/vmx.c
Normal 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));
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#include "pocketpy/pocketpy.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);
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
int res = ManagedHeap__collect(heap);
|
||||
@ -9,7 +9,7 @@ static bool gc_collect(int argc, py_Ref argv){
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gc_enable(int argc, py_Ref argv){
|
||||
static bool gc_enable(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
heap->gc_enabled = true;
|
||||
@ -17,7 +17,7 @@ static bool gc_enable(int argc, py_Ref argv){
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gc_disable(int argc, py_Ref argv){
|
||||
static bool gc_disable(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
heap->gc_enabled = false;
|
||||
@ -25,7 +25,7 @@ static bool gc_disable(int argc, py_Ref argv){
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gc_isenabled(int argc, py_Ref argv){
|
||||
static bool gc_isenabled(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
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, "disable", gc_disable);
|
||||
py_bindfunc(mod, "isenabled", gc_isenabled);
|
||||
}
|
||||
|
||||
int py_gc_collect() {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
return ManagedHeap__collect(heap);
|
||||
}
|
@ -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_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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -49,7 +49,7 @@ bool py_compile(const char* source,
|
||||
|
||||
bool pk_exec(CodeObject* co, py_Ref module) {
|
||||
VM* vm = pk_current_vm;
|
||||
if(!module) module = &vm->main;
|
||||
if(!module) module = vm->main;
|
||||
assert(module->type == tp_module);
|
||||
|
||||
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) {
|
||||
VM* vm = pk_current_vm;
|
||||
if(!module) module = &vm->main;
|
||||
if(!module) module = vm->main;
|
||||
assert(module->type == tp_module);
|
||||
|
||||
py_StackRef sp = vm->stack.sp;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -16,11 +16,11 @@ py_Ref py_getmodule(const char* 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) {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
@ -608,7 +608,7 @@ static bool builtins_eval(int argc, py_Ref argv) {
|
||||
|
||||
static bool
|
||||
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
|
||||
py_newdict(py_pushtmp()); // locals
|
||||
bool ok = py_compile(source, "<string>", mode, true);
|
||||
@ -716,8 +716,8 @@ static bool NotImplementedType__repr__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
py_TValue pk_builtins__register() {
|
||||
py_Ref builtins = py_newmodule("builtins");
|
||||
py_GlobalRef pk_builtins__register() {
|
||||
py_GlobalRef builtins = py_newmodule("builtins");
|
||||
py_bindfunc(builtins, "exit", builtins_exit);
|
||||
py_bindfunc(builtins, "input", builtins_input);
|
||||
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_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__);
|
||||
py_setdict(py_tpobject(tp_NotImplementedType), __hash__, py_None());
|
||||
return *builtins;
|
||||
return builtins;
|
||||
}
|
||||
|
||||
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) {
|
||||
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));
|
||||
|
@ -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 {
|
||||
|
@ -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
45
src/public/typecast.c
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user