Compare commits

..

11 Commits

Author SHA1 Message Date
blueloveTH
46f9e4ed4f fix pybind11 2025-03-05 02:18:38 +08:00
blueloveTH
19d0cfd4fd plan to implement tracefunc 2025-03-05 02:14:29 +08:00
blueloveTH
7b4994ee35 improve performance 2025-03-05 01:47:05 +08:00
blueloveTH
bd36a53226 Update heap.c 2025-03-05 01:32:55 +08:00
blueloveTH
854f0d9b35 Update config.h 2025-03-05 01:14:00 +08:00
blueloveTH
2572ddd982 remove custom marker 2025-03-05 00:50:53 +08:00
blueloveTH
b3084a5c87 improve performance 2025-03-05 00:37:20 +08:00
blueloveTH
160bc99d04 improve performance 2025-03-04 23:32:14 +08:00
blueloveTH
2fdf09f652 Update main.yml 2025-03-04 22:18:42 +08:00
blueloveTH
0ba04d18d7 Update main.yml 2025-03-04 22:16:13 +08:00
blueloveTH
2061f90a27 Update array2d.c 2025-03-04 22:07:40 +08:00
21 changed files with 176 additions and 147 deletions

View File

@ -48,7 +48,7 @@ jobs:
- name: Benchmark
run: python scripts/run_tests.py benchmark
build_linux:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
@ -58,8 +58,6 @@ jobs:
with:
version: 15
platform: x64
- name: Install dependencies
run: sudo apt-get install -y libclang-rt-15-dev
- name: Unit Test with Coverage
run: bash run_tests.sh
- name: Upload coverage reports to Codecov

View File

@ -9,7 +9,7 @@ typedef struct FixedMemoryPool {
int exceeded_bytes;
char** _free_list;
char** _free_list_end;
int _free_list_length;
} FixedMemoryPool;
void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount);

View File

@ -1,10 +1,10 @@
#pragma once
// clang-format off
#define PK_VERSION "2.0.6"
#define PK_VERSION "2.0.7"
#define PK_VERSION_MAJOR 2
#define PK_VERSION_MINOR 0
#define PK_VERSION_PATCH 6
#define PK_VERSION_PATCH 7
/*************** feature settings ***************/
@ -23,7 +23,7 @@
#if PK_LOW_MEMORY_MODE
#define PK_GC_MIN_THRESHOLD 2048
#else
#define PK_GC_MIN_THRESHOLD 16384
#define PK_GC_MIN_THRESHOLD 32768
#endif
#endif

View File

@ -23,7 +23,6 @@ typedef struct py_TypeInfo {
py_TValue annotations; // type annotations
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
void (*gc_mark)(void* ud);
/* Magic Slots */
py_TValue magic_0[PK_MAGIC_SLOTS_COMMON_LENGTH]; // common magic slots
@ -41,6 +40,6 @@ 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_TValue* TypeList__magic(py_TypeInfo* self, unsigned index);
py_TValue* TypeList__magic_readonly_nullable(py_TypeInfo* self, unsigned index);
py_TValue* TypeList__magic_readonly(py_TypeInfo* self, unsigned index);
#define TypeList__magic_common(ti, index) ((ti)->magic_0 + ((index)-PK_MAGIC_SLOTS_UNCOMMON_LENGTH))

View File

@ -0,0 +1,28 @@
#pragma once
#include "pocketpy/common/vector.h"
#include "pocketpy/objects/base.h"
#define PK_DICT_MAX_COLLISION 4
typedef struct {
uint64_t hash;
py_TValue key;
py_TValue val;
} DictEntry;
typedef struct {
int _[PK_DICT_MAX_COLLISION];
} DictIndex;
typedef struct {
int length;
uint32_t capacity;
DictIndex* indices;
c11_vector /*T=DictEntry*/ entries;
} Dict;
typedef c11_vector List;
void c11_chunked_array2d__mark(void* ud);
void function__gc_mark(void* ud);

View File

@ -8,6 +8,7 @@
#include "pocketpy/interpreter/modules.h"
#include "pocketpy/interpreter/typeinfo.h"
#include "pocketpy/interpreter/name.h"
#include "pocketpy/interpreter/types.h"
// TODO:
// 1. __eq__ and __ne__ fallbacks
@ -32,7 +33,6 @@ typedef struct VM {
py_TValue last_retval;
py_TValue curr_exception;
volatile bool is_signal_interrupted;
bool is_curr_exc_handled; // handled by try-except block but not cleared yet
py_TValue reg[8]; // users' registers
@ -58,8 +58,7 @@ bool pk__parse_int_slice(py_Ref slice, int length, int* restrict start, int* res
bool pk__normalize_index(int* index, int length);
#define pk__mark_value(val) if((val)->is_ptr && !(val)->_obj->gc_marked) PyObject__mark((val)->_obj)
void pk__mark_namedict(NameDict*);
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*));
bool pk__object_new(int argc, py_Ref argv);
py_TypeInfo* pk__type_info(py_Type type);

View File

@ -34,6 +34,33 @@ typedef struct c11_sv {
int size;
} c11_sv;
// An enum for tracing events.
enum py_TraceEvent {
TraceEvent_Line,
TraceEvent_Call,
TraceEvent_Return,
TraceEvent_Exception,
};
/// A struct contains the arguments of the tracing event.
union py_TraceEventArg {
struct {
int _;
} line;
struct {
int _;
} call;
struct {
int _;
} return_;
struct {
int _;
} exception;
};
/// A struct contains the callbacks of the VM.
typedef struct py_Callbacks {
/// Used by `__import__` to load source code of a module.
@ -42,6 +69,8 @@ typedef struct py_Callbacks {
void (*print)(const char*);
/// Used by `input` to get a character.
int (*getchar)();
/// C-style `sys.settrace` function.
void (*tracefunc)(enum py_TraceEvent, union py_TraceEventArg);
} py_Callbacks;
#define PY_RAISE
@ -89,8 +118,6 @@ PK_API void py_resetvm();
PK_API void* py_getvmctx();
/// Set the current VM context. This is used for user-defined data.
PK_API void py_setvmctx(void* ctx);
/// Interrupt the current VM and raise a `KeyboardInterrupt` exception.
PK_API void py_interrupt();
/// Set `sys.argv`. Used for storing command-line arguments.
PK_API void py_sys_setargv(int argc, char** argv);
/// Setup the callbacks for the current VM.
@ -103,9 +130,9 @@ PK_API py_Callbacks* py_callbacks();
/// @param module target module. Use NULL for the main module.
/// @return `true` if the execution is successful or `false` if an exception is raised.
PK_API bool py_exec(const char* source,
const char* filename,
enum py_CompileMode mode,
py_Ref module) PY_RAISE PY_RETURN;
const char* filename,
enum py_CompileMode mode,
py_Ref module) PY_RAISE PY_RETURN;
/// Evaluate a source string. Equivalent to `py_exec(source, "<string>", EVAL_MODE, module)`.
PK_API bool py_eval(const char* source, py_Ref module) PY_RAISE PY_RETURN;
@ -128,9 +155,9 @@ PK_API bool py_smarteval(const char* source, py_Ref module, ...) PY_RAISE PY_RET
/// Compile a source string into a code object.
/// Use python's `exec()` or `eval()` to execute it.
PK_API bool py_compile(const char* source,
const char* filename,
enum py_CompileMode mode,
bool is_dynamic) PY_RAISE PY_RETURN;
const char* filename,
enum py_CompileMode mode,
bool is_dynamic) PY_RAISE PY_RETURN;
/// Python equivalent to `globals()`.
PK_API void py_newglobals(py_OutRef);
@ -190,10 +217,10 @@ PK_API void py_newslice(py_OutRef);
PK_API void py_newnativefunc(py_OutRef, py_CFunction);
/// Create a `function` object.
PK_API py_Name py_newfunction(py_OutRef out,
const char* sig,
py_CFunction f,
const char* docstring,
int slots);
const char* sig,
py_CFunction f,
const char* docstring,
int slots);
/// Create a `boundmethod` object.
PK_API void py_newboundmethod(py_OutRef out, py_Ref self, py_Ref func);
@ -219,10 +246,7 @@ PK_API c11_sv py_name2sv(py_Name);
/// @param base base type.
/// @param module module where the type is defined. Use `NULL` for built-in types.
/// @param dtor destructor function. Use `NULL` if not needed.
PK_API py_Type py_newtype(const char* name,
py_Type base,
const py_GlobalRef module,
py_Dtor dtor);
PK_API py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, py_Dtor dtor);
/// Create a new object.
/// @param out output reference.
@ -478,11 +502,10 @@ PK_API py_StackRef py_pushtmp();
/// If return false: `[self] -> [self]` (no change).
PK_API bool py_pushmethod(py_Name name);
/// Call a callable object via pocketpy's calling convention.
/// You need to prepare the stack using this form: `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`
/// `argc` is the number of positional arguments excluding `self`.
/// `kwargc` is the number of keyword arguments, i.e. the number of key-value pairs.
/// The result will be set to `py_retval()`.
/// The stack size will be reduced by `2 + argc + kwargc * 2`.
/// You need to prepare the stack using this form: `callable, self/nil, arg1, arg2, ..., k1, v1, k2,
/// v2, ...` `argc` is the number of positional arguments excluding `self`. `kwargc` is the number
/// of keyword arguments, i.e. the number of key-value pairs. The result will be set to
/// `py_retval()`. The stack size will be reduced by `2 + argc + kwargc * 2`.
PK_API bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE PY_RETURN;
/// Evaluate an expression and push the result to the stack.
/// This function is used for testing.
@ -536,7 +559,9 @@ PK_API void py_clearexc(py_StackRef p0);
#define AttributeError(self, n) \
py_exception(tp_AttributeError, "'%t' object has no attribute '%n'", (self)->type, (n))
#define UnboundLocalError(n) \
py_exception(tp_UnboundLocalError, "cannot access local variable '%n' where it is not associated with a value", (n))
py_exception(tp_UnboundLocalError, \
"cannot access local variable '%n' where it is not associated with a value", \
(n))
PK_API bool StopIteration() PY_RAISE;
PK_API bool KeyError(py_Ref key) PY_RAISE;
@ -672,15 +697,15 @@ PK_API int py_replinput(char* buf, int max_size);
/// %t: py_Type
/// %n: py_Name
enum py_MagicNames {
py_MagicNames__NULL, // 0 is reserved
enum py_MagicName {
py_MagicName__NULL, // 0 is reserved
#define MAGIC_METHOD(x) x,
#include "pocketpy/xmacros/magics.h"
#undef MAGIC_METHOD
};
enum py_PredefinedTypes {
enum py_PredefinedType {
tp_nil = 0,
tp_object = 1,
tp_type, // py_Type

View File

@ -31,7 +31,7 @@ public:
info.name = name;
py_newfunction(
py_tpgetmagic(this->index(), py_MagicNames::__new__),
py_tpgetmagic(this->index(), __new__),
"__new__(type, *args, **kwargs)",
[](int, py_Ref stack) {
auto cls = py_offset(stack, 0);

View File

@ -11,7 +11,7 @@ void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount)
self->data = PK_MALLOC(BlockSize * BlockCount);
self->data_end = self->data + BlockSize * BlockCount;
self->_free_list = PK_MALLOC(sizeof(void*) * BlockCount);
self->_free_list_end = self->_free_list;
self->_free_list_length = BlockCount;
for(int i = 0; i < BlockCount; i++) {
self->_free_list[i] = self->data + i * BlockSize;
}
@ -23,9 +23,9 @@ void FixedMemoryPool__dtor(FixedMemoryPool* self) {
}
void* FixedMemoryPool__alloc(FixedMemoryPool* self) {
if(self->_free_list_end != self->_free_list) {
self->_free_list_end--;
return *self->_free_list_end;
if(self->_free_list_length > 0) {
self->_free_list_length--;
return self->_free_list[self->_free_list_length];
} else {
self->exceeded_bytes += self->BlockSize;
return PK_MALLOC(self->BlockSize);
@ -35,8 +35,8 @@ void* FixedMemoryPool__alloc(FixedMemoryPool* self) {
void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p) {
bool is_valid = (char*)p >= self->data && (char*)p < self->data_end;
if(is_valid) {
*self->_free_list_end = p;
self->_free_list_end++;
self->_free_list[self->_free_list_length] = p;
self->_free_list_length++;
} else {
self->exceeded_bytes -= self->BlockSize;
PK_FREE(p);

View File

@ -97,18 +97,16 @@ FrameResult VM__run_top_frame(VM* self) {
frame->ip++;
__NEXT_STEP:
if(self->callbacks.tracefunc) {
// TODO: implement tracing mechanism
}
byte = codes[frame->ip];
#ifndef NDEBUG
pk_print_stack(self, frame, byte);
#endif
if(self->is_signal_interrupted) {
self->is_signal_interrupted = false;
py_exception(tp_KeyboardInterrupt, "");
goto __ERROR;
}
switch((Opcode)byte.op) {
case OP_NO_OP: DISPATCH();
/*****************************************/
@ -199,13 +197,14 @@ FrameResult VM__run_top_frame(VM* self) {
/*****************************************/
case OP_LOAD_FAST: {
assert(!frame->is_locals_special);
PUSH(&frame->locals[byte.arg]);
if(py_isnil(TOP())) {
py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
UnboundLocalError(name);
goto __ERROR;
py_Ref val = &frame->locals[byte.arg];
if(!py_isnil(val)) {
PUSH(val);
DISPATCH();
}
DISPATCH();
py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
UnboundLocalError(name);
goto __ERROR;
}
case OP_LOAD_NAME: {
assert(frame->is_locals_special);

View File

@ -76,16 +76,8 @@ static bool generator__next__(int argc, py_Ref argv) {
}
}
static void generator__gc_mark(void* ud){
Generator* gen = ud;
if(gen->frame) Frame__gc_mark(gen->frame);
}
py_Type pk_generator__register() {
py_Type type = pk_newtype("generator", tp_object, NULL, (py_Dtor)Generator__dtor, false, true);
pk__tp_set_marker(type, generator__gc_mark);
py_bindmagic(type, __iter__, pk_wrapper__self);
py_bindmagic(type, __next__, generator__next__);
return type;

View File

@ -38,9 +38,12 @@ void ManagedHeap__collect_if_needed(ManagedHeap* self) {
self->freed_ma[1] = self->freed_ma[2];
self->freed_ma[2] = freed;
int avg_freed = (self->freed_ma[0] + self->freed_ma[1] + self->freed_ma[2]) / 3;
int upper = self->gc_threshold * 2;
int lower = c11__max(PK_GC_MIN_THRESHOLD, self->gc_threshold / 2 + 1);
self->gc_threshold = c11__min(c11__max(avg_freed, lower), upper);
const int upper = PK_GC_MIN_THRESHOLD * 2;
const int lower = PK_GC_MIN_THRESHOLD / 2;
float free_ratio = (float)avg_freed / PK_GC_MIN_THRESHOLD;
int new_threshold = self->gc_threshold * (1 / free_ratio);
// printf("gc_threshold=%d, avg_freed=%d, new_threshold=%d\n", self->gc_threshold, avg_freed, new_threshold);
self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper);
}
int ManagedHeap__collect(ManagedHeap* self) {

View File

@ -60,18 +60,14 @@ py_TValue* TypeList__magic(py_TypeInfo* self, unsigned index) {
return self->magic_1 + index;
}
py_TValue* TypeList__magic_readonly_nullable(py_TypeInfo* self, unsigned index) {
py_TValue* TypeList__magic_readonly(py_TypeInfo* self, unsigned index) {
if(index > __xor__) {
// common magic slots
py_TValue* slot = TypeList__magic_common(self, index);
if(py_isnil(slot)) return NULL;
return slot;
return TypeList__magic_common(self, index);
}
// uncommon magic slots
if(self->magic_1 == NULL) return NULL;
py_TValue* slot = self->magic_1 + index;
if(py_isnil(slot)) return NULL;
return slot;
if(self->magic_1 == NULL) return py_NIL();
return self->magic_1 + index;
}
#undef CHUNK_SIZE

View File

@ -68,10 +68,10 @@ void VM__ctor(VM* self) {
self->callbacks.importfile = pk_default_importfile;
self->callbacks.print = pk_default_print;
self->callbacks.getchar = getchar;
self->callbacks.tracefunc = NULL;
self->last_retval = *py_NIL();
self->curr_exception = *py_NIL();
self->is_signal_interrupted = false;
self->is_curr_exc_handled = false;
self->ctx = NULL;
@ -447,7 +447,9 @@ static bool
}
FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall) {
#ifndef NDEBUG
pk_print_stack(self, self->top_frame, (Bytecode){0});
#endif
py_Ref p1 = self->stack.sp - kwargc * 2;
py_Ref p0 = p1 - argc - 2;
@ -602,19 +604,6 @@ void PyObject__dtor(PyObject* self) {
if(self->slots == -1) NameDict__dtor(PyObject__dict(self));
}
void pk__mark_namedict(NameDict* dict) {
for(int i = 0; i < dict->length; i++) {
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
pk__mark_value(&kv->value);
}
}
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*)) {
py_TypeInfo* ti = pk__type_info(type);
assert(ti->gc_mark == NULL);
ti->gc_mark = gc_mark;
}
void PyObject__mark(PyObject* obj) {
assert(!obj->gc_marked);
@ -625,12 +614,51 @@ void PyObject__mark(PyObject* obj) {
for(int i = 0; i < obj->slots; i++)
pk__mark_value(p + i);
} else if(obj->slots == -1) {
NameDict* dict = PyObject__dict(obj);
pk__mark_namedict(dict);
NameDict* namedict = PyObject__dict(obj);
for(int i = 0; i < namedict->length; i++) {
NameDict_KV* kv = c11__at(NameDict_KV, namedict, i);
pk__mark_value(&kv->value);
}
}
py_TypeInfo* ti = pk__type_info(obj->type);
if(ti->gc_mark) ti->gc_mark(PyObject__userdata(obj));
void* ud = PyObject__userdata(obj);
switch(obj->type) {
case tp_list: {
List* self = ud;
for(int i = 0; i < self->length; i++) {
pk__mark_value(c11__at(py_TValue, self, i));
}
break;
}
case tp_dict: {
Dict* self = ud;
for(int i = 0; i < self->entries.length; i++) {
DictEntry* entry = c11__at(DictEntry, &self->entries, i);
if(py_isnil(&entry->key)) continue;
pk__mark_value(&entry->key);
pk__mark_value(&entry->val);
}
break;
}
case tp_generator: {
Generator* self = ud;
if(self->frame) Frame__gc_mark(self->frame);
break;
}
case tp_function: {
function__gc_mark(ud);
break;
}
case tp_code: {
CodeObject* self = ud;
CodeObject__gc_mark(self);
break;
}
case tp_chunked_array2d: {
c11_chunked_array2d__mark(ud);
}
default: return;
}
}
void FuncDecl__gc_mark(const FuncDecl* self) {

View File

@ -3,8 +3,8 @@
#include "pocketpy/pocketpy.h"
#include <limits.h>
static bool c11_array2d_like_is_valid(c11_array2d_like* self, unsigned int col, unsigned int row) {
return col < self->n_cols && row < self->n_rows;
static bool c11_array2d_like_is_valid(c11_array2d_like* self, int col, int row) {
return col >= 0 && col < self->n_cols && row >= 0 && row < self->n_rows;
}
static py_Ref c11_array2d__get(c11_array2d* self, int col, int row) {
@ -1211,7 +1211,7 @@ void c11_chunked_array2d__dtor(c11_chunked_array2d* self) {
c11_chunked_array2d_chunks__dtor(&self->chunks);
}
static void c11_chunked_array2d__mark(void* ud) {
void c11_chunked_array2d__mark(void* ud) {
c11_chunked_array2d* self = ud;
pk__mark_value(&self->default_T);
pk__mark_value(&self->context_builder);
@ -1291,7 +1291,6 @@ static bool chunked_array2d_view_chunks(int argc, py_Ref argv) {
static void register_chunked_array2d(py_Ref mod) {
py_Type type =
py_newtype("chunked_array2d", tp_object, mod, (py_Dtor)c11_chunked_array2d__dtor);
pk__tp_set_marker(type, c11_chunked_array2d__mark);
assert(type == tp_chunked_array2d);
py_bind(py_tpobject(type),

View File

@ -9,7 +9,6 @@
py_Type pk_code__register() {
py_Type type = pk_newtype("code", tp_object, NULL, (py_Dtor)CodeObject__dtor, false, true);
pk__tp_set_marker(type, (void (*)(void*))CodeObject__gc_mark);
return type;
}

View File

@ -90,8 +90,6 @@ void* py_getvmctx() { return pk_current_vm->ctx; }
void py_setvmctx(void* ctx) { pk_current_vm->ctx = ctx; }
void py_interrupt() { pk_current_vm->is_signal_interrupted = true; }
void py_sys_setargv(int argc, char** argv) {
py_GlobalRef sys = py_getmodule("sys");
py_Ref argv_list = py_getdict(sys, py_name("argv"));
@ -227,8 +225,9 @@ py_Ref py_tpfindmagic(py_Type t, py_Name name) {
assert(py_ismagicname(name));
py_TypeInfo* ti = pk__type_info(t);
do {
py_Ref f = TypeList__magic_readonly_nullable(ti, name);
if(f != NULL) return f;
py_Ref f = TypeList__magic_readonly(ti, name);
assert(f != NULL);
if(!py_isnil(f)) return f;
ti = ti->base_ti;
} while(ti);
return NULL;

View File

@ -773,10 +773,16 @@ py_TValue pk_builtins__register() {
return *builtins;
}
static void function__gc_mark(void* ud) {
void function__gc_mark(void* ud) {
Function* func = ud;
if(func->globals) pk__mark_value(func->globals);
if(func->closure) pk__mark_namedict(func->closure);
if(func->closure) {
NameDict* namedict = func->closure;
for(int i = 0; i < namedict->length; i++) {
NameDict_KV* kv = c11__at(NameDict_KV, namedict, i);
pk__mark_value(&kv->value);
}
}
FuncDecl__gc_mark(func->decl);
}
@ -794,9 +800,6 @@ static bool function__doc__(int argc, py_Ref argv) {
py_Type pk_function__register() {
py_Type type =
pk_newtype("function", tp_object, NULL, (void (*)(void*))Function__dtor, false, true);
pk__tp_set_marker(type, function__gc_mark);
py_bindproperty(type, "__doc__", function__doc__, NULL);
return type;
}

View File

@ -5,8 +5,6 @@
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
#define PK_DICT_MAX_COLLISION 4
static uint32_t Dict__next_cap(uint32_t cap) {
switch(cap) {
case 7: return 17;
@ -53,22 +51,7 @@ static uint32_t Dict__next_cap(uint32_t cap) {
}
}
typedef struct {
uint64_t hash;
py_TValue key;
py_TValue val;
} DictEntry;
typedef struct {
int _[PK_DICT_MAX_COLLISION];
} DictIndex;
typedef struct {
int length;
uint32_t capacity;
DictIndex* indices;
c11_vector /*T=DictEntry*/ entries;
} Dict;
typedef struct {
DictEntry* curr;
@ -525,21 +508,9 @@ static bool dict_values(int argc, py_Ref argv) {
return true;
}
static void dict__gc_mark(void* ud) {
Dict* self = ud;
for(int i = 0; i < self->entries.length; i++) {
DictEntry* entry = c11__at(DictEntry, &self->entries, i);
if(py_isnil(&entry->key)) continue;
pk__mark_value(&entry->key);
pk__mark_value(&entry->val);
}
}
py_Type pk_dict__register() {
py_Type type = pk_newtype("dict", tp_object, NULL, (void (*)(void*))Dict__dtor, false, false);
pk__tp_set_marker(type, dict__gc_mark);
py_bindmagic(type, __new__, dict__new__);
py_bindmagic(type, __init__, dict__init__);
py_bindmagic(type, __getitem__, dict__getitem__);

View File

@ -5,8 +5,6 @@
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/sstream.h"
typedef c11_vector List;
void py_newlist(py_Ref out) {
List* ud = py_newobject(out, tp_list, 0, sizeof(List));
c11_vector__ctor(ud, sizeof(py_TValue));
@ -404,19 +402,10 @@ static bool list__contains__(int argc, py_Ref argv) {
return pk_arraycontains(py_arg(0), py_arg(1));
}
static void list__gc_mark(void* ud) {
List* self = ud;
for(int i = 0; i < self->length; i++) {
pk__mark_value(c11__at(py_TValue, self, i));
}
}
py_Type pk_list__register() {
py_Type type =
pk_newtype("list", tp_object, NULL, (void (*)(void*))c11_vector__dtor, false, true);
pk__tp_set_marker(type, list__gc_mark);
py_bindmagic(type, __len__, list__len__);
py_bindmagic(type, __eq__, list__eq__);
py_bindmagic(type, __ne__, list__ne__);

View File

@ -5,6 +5,8 @@
#include "pocketpy.h"
#define py_interrupt()
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>