This commit is contained in:
blueloveTH 2024-07-14 23:41:56 +08:00
parent 20cd2064d4
commit 51e2433404
16 changed files with 150 additions and 67 deletions

View File

@ -38,7 +38,7 @@ typedef struct Frame {
struct Frame* f_back;
const Bytecode* ip;
const CodeObject* co;
PyObject* module;
py_TValue module; // weak ref
PyObject* function; // a function object or NULL (global scope)
py_TValue* p0; // unwinding base
py_TValue* locals; // locals base
@ -47,7 +47,7 @@ typedef struct Frame {
} Frame;
Frame* Frame__new(const CodeObject* co,
PyObject* module,
py_TValue* module,
const py_TValue* function,
py_TValue* p0,
py_TValue* locals,
@ -66,12 +66,6 @@ PK_INLINE int Frame__iblock(const Frame* self) {
return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).iblock;
}
PK_INLINE pk_NameDict* Frame__f_globals(Frame* self) { return PyObject__dict(self->module); }
PK_INLINE py_TValue* Frame__f_globals_try_get(Frame* self, py_Name name) {
return pk_NameDict__try_get(Frame__f_globals(self), name);
}
PK_INLINE py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name) {
return FastLocals__try_get_by_name(self->locals, self->locals_co, name);
}

View File

@ -23,7 +23,7 @@ typedef struct pk_TypeInfo {
c11_vector /*T=py_Name*/ annotated_fields;
py_CFunction on_end_subclass; // backdoor for enum module
void (*on_end_subclass)(struct pk_TypeInfo*); // backdoor for enum module
/* Magic Slots */
py_TValue magic[64];
@ -49,7 +49,7 @@ typedef struct pk_VM {
py_TValue reg[8]; // users' registers
py_TValue __curr_class;
py_TValue* __curr_class;
FuncDecl_ __dynamic_func_decl;
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];

View File

@ -36,8 +36,6 @@ typedef struct py_TValue {
static_assert(sizeof(py_CFunction) <= 8, "sizeof(py_CFunction) > 8");
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
extern py_TValue PY_NIL;
#ifdef __cplusplus
}
#endif

View File

@ -137,13 +137,13 @@ FuncDecl_ FuncDecl__build(c11_sv name,
// runtime function
typedef struct Function {
FuncDecl_ decl;
PyObject* module; // weak ref
py_TValue module; // weak ref
PyObject* clazz; // weak ref
pk_NameDict* closure; // strong ref
py_CFunction cfunc; // wrapped C function
} Function;
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module);
void Function__ctor(Function* self, FuncDecl_ decl, py_TValue* module);
void Function__dtor(Function* self);
#ifdef __cplusplus

View File

@ -132,6 +132,7 @@ bool py_issubclass(py_Type derived, py_Type base);
extern py_GlobalRef py_True;
extern py_GlobalRef py_False;
extern py_GlobalRef py_None;
extern py_GlobalRef py_NIL;
/************* References *************/
#define PY_CHECK_ARGC(n) \
@ -183,6 +184,7 @@ py_GlobalRef py_reg(int i);
/// Returns a reference to the value or NULL if not found.
py_ObjectRef py_getdict(const py_Ref self, py_Name name);
void py_setdict(py_Ref self, py_Name name, const py_Ref val);
bool py_deldict(py_Ref self, py_Name name);
/// Get the reference of the i-th slot of the object.
/// The object must have slots and `i` must be in range.

View File

@ -96,8 +96,6 @@ OPCODE(UNPACK_EX)
OPCODE(BEGIN_CLASS)
OPCODE(END_CLASS)
OPCODE(STORE_CLASS_ATTR)
OPCODE(BEGIN_CLASS_DECORATION)
OPCODE(END_CLASS_DECORATION)
OPCODE(ADD_CLASS_ANNOTATION)
/**************************/
OPCODE(WITH_ENTER)

View File

@ -1291,6 +1291,7 @@ static void Ctx__exit_block(Ctx* self) {
}
static void Ctx__s_emit_decorators(Ctx* self, int count) {
if(count == 0) return;
assert(Ctx__s_size(self) >= count);
// [obj]
for(int i = 0; i < count; i++) {
@ -2252,7 +2253,7 @@ static Error* read_literal(Compiler* self, py_Ref out) {
}
return NULL;
}
default: *out = PY_NIL; return NULL;
default: py_newnil(out); return NULL;
}
}
@ -2346,6 +2347,37 @@ static Error* compile_function(Compiler* self, int decorators) {
return NULL;
}
static Error* compile_class(Compiler* self, int decorators) {
Error* err;
consume(TK_ID);
py_Name name = py_namev(Token__sv(prev()));
bool has_base = false;
if(match(TK_LPAREN)) {
if(is_expression(self, false)) {
check(EXPR(self));
has_base = true; // [base]
}
consume(TK_RPAREN);
}
if(!has_base) {
Ctx__emit_(ctx(), OP_LOAD_NONE, BC_NOARG, prev()->line);
} else {
Ctx__s_emit_top(ctx()); // []
}
Ctx__emit_(ctx(), OP_BEGIN_CLASS, name, BC_KEEPLINE);
c11__foreach(Ctx, &self->contexts, it) {
if(it->is_compiling_class) return SyntaxError("nested class is not allowed");
}
ctx()->is_compiling_class = true;
check(compile_block_body(self, compile_stmt));
ctx()->is_compiling_class = false;
Ctx__s_emit_decorators(ctx(), decorators);
Ctx__emit_(ctx(), OP_END_CLASS, name, BC_KEEPLINE);
return NULL;
}
static Error* compile_decorated(Compiler* self) {
Error* err;
int count = 0;
@ -2356,7 +2388,7 @@ static Error* compile_decorated(Compiler* self) {
} while(match(TK_DECORATOR));
if(match(TK_CLASS)) {
// check(compile_class(count));
check(compile_class(self, count));
} else {
consume(TK_DEF);
check(compile_function(self, count));
@ -2467,8 +2499,7 @@ static Error* compile_try_except(Compiler* self) {
static Error* compile_stmt(Compiler* self) {
Error* err;
if(match(TK_CLASS)) {
// check(compile_class());
assert(false);
check(compile_class(self, 0));
return NULL;
}
advance();

View File

@ -143,7 +143,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
case OP_LOAD_FUNCTION: {
FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
Function__ctor(ud, decl, frame->module);
Function__ctor(ud, decl, &frame->module);
if(decl->nested) {
ud->closure = FastLocals__to_namedict(frame->locals, frame->locals_co);
py_Name name = py_namev(c11_string__sv(decl->code.name));
@ -182,7 +182,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
PUSH(tmp);
DISPATCH();
}
tmp = Frame__f_globals_try_get(frame, name);
tmp = py_getdict(&frame->module, name);
if(tmp != NULL) {
PUSH(tmp);
DISPATCH();
@ -202,7 +202,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
PUSH(tmp);
DISPATCH();
}
tmp = Frame__f_globals_try_get(frame, name);
tmp = py_getdict(&frame->module, name);
if(tmp != NULL) {
PUSH(tmp);
DISPATCH();
@ -217,7 +217,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
case OP_LOAD_GLOBAL: {
py_Name name = byte.arg;
py_Ref tmp = Frame__f_globals_try_get(frame, name);
py_Ref tmp = py_getdict(&frame->module, name);
if(tmp != NULL) {
PUSH(tmp);
DISPATCH();
@ -238,14 +238,13 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
DISPATCH();
}
case OP_LOAD_CLASS_GLOBAL: {
assert(self->__curr_class.type);
py_Name name = byte.arg;
if(py_getattr(&self->__curr_class, name, SP())) {
if(py_getattr(self->__curr_class, name, SP())) {
SP()++;
DISPATCH();
}
// load global if attribute not found
py_Ref tmp = Frame__f_globals_try_get(frame, name);
py_Ref tmp = py_getdict(&frame->module, name);
if(tmp) {
PUSH(tmp);
DISPATCH();
@ -294,12 +293,11 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
case OP_STORE_NAME: {
py_Name _name = byte.arg;
py_TValue _0 = POPX();
py_Name name = byte.arg;
if(frame->function) {
py_Ref slot = Frame__f_locals_try_get(frame, _name);
py_Ref slot = Frame__f_locals_try_get(frame, name);
if(slot != NULL) {
*slot = _0; // store in locals if possible
*slot = *TOP(); // store in locals if possible
} else {
// Function& func = frame->_callable->as<Function>();
// if(func.decl == __dynamic_func_decl) {
@ -311,14 +309,16 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
// }
}
} else {
pk_NameDict__set(Frame__f_globals(frame), _name, _0);
py_setdict(&frame->module, name, TOP());
}
POP();
DISPATCH();
}
case OP_STORE_GLOBAL:
pk_NameDict__set(Frame__f_globals(frame), byte.arg, POPX());
case OP_STORE_GLOBAL: {
py_setdict(&frame->module, byte.arg, TOP());
POP();
DISPATCH();
}
case OP_STORE_ATTR: {
int err = py_setattr(TOP(), byte.arg, SECOND());
if(err) goto __ERROR;
@ -370,8 +370,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
// }
}
} else {
// if(!frame->f_globals().del(_name)) vm->NameError(_name);
bool ok = pk_NameDict__del(Frame__f_globals(frame), name);
bool ok = py_deldict(&frame->module, name);
if(!ok) {
NameError(name);
goto __ERROR;
@ -381,7 +380,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
case OP_DELETE_GLOBAL: {
py_Name name = byte.arg;
bool ok = pk_NameDict__del(Frame__f_globals(frame), name);
bool ok = py_deldict(&frame->module, name);
if(!ok) {
NameError(name);
goto __ERROR;
@ -794,7 +793,58 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
DISPATCH();
}
///////////
case OP_BEGIN_CLASS: {
// [base]
py_Name name = byte.arg;
py_Type base;
if(py_isnone(TOP())) {
base = tp_object;
} else {
if(!py_checktype(TOP(), tp_type)) goto __ERROR;
base = py_totype(TOP());
}
POP();
py_Type type = py_newtype(py_name2str(name), base, &frame->module, NULL);
PUSH(py_tpobject(type));
self->__curr_class = TOP();
DISPATCH();
}
case OP_END_CLASS: {
// [cls or decorated]
py_Name name = byte.arg;
// set into f_globals
py_setdict(&frame->module, name, TOP());
if(py_istype(TOP(), tp_type)) {
// call on_end_subclass
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, py_totype(TOP()));
if(ti->base != tp_object) {
// PyTypeInfo* base_ti = &_all_types[ti->base];
pk_TypeInfo* base_ti = c11__at(pk_TypeInfo, &self->types, ti->base);
if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
}
}
POP();
self->__curr_class = NULL;
DISPATCH();
}
case OP_STORE_CLASS_ATTR: {
py_Name name = byte.arg;
if(py_istype(TOP(), tp_function)) {
Function* ud = py_touserdata(TOP());
ud->clazz = self->__curr_class->_obj;
}
py_setdict(self->__curr_class, name, TOP());
POP();
DISPATCH();
}
case OP_ADD_CLASS_ANNOTATION: {
py_Type type = py_totype(self->__curr_class);
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, type);
c11_vector__push(py_Name, &ti->annotated_fields, byte.arg);
DISPATCH();
}
///////////
case OP_RAISE_ASSERT: {
if(byte.arg) {

View File

@ -34,7 +34,7 @@ UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset) {
void UnwindTarget__delete(UnwindTarget* self) { free(self); }
Frame* Frame__new(const CodeObject* co,
PyObject* module,
py_TValue* module,
const py_TValue* function,
py_TValue* p0,
py_TValue* locals,
@ -44,7 +44,7 @@ Frame* Frame__new(const CodeObject* co,
self->f_back = NULL;
self->ip = (Bytecode*)co->codes.data - 1;
self->co = co;
self->module = module;
self->module = *module;
self->function = function ? function->_obj : NULL;
self->p0 = p0;
self->locals = locals;

View File

@ -47,7 +47,7 @@ static void pk_TypeInfo__ctor(pk_TypeInfo* self,
._obj = typeobj,
};
self->module = module ? *module : PY_NIL;
self->module = module ? *module : *py_NIL;
c11_vector__ctor(&self->annotated_fields, sizeof(py_Name));
}
@ -59,19 +59,19 @@ void pk_VM__ctor(pk_VM* self) {
pk_NameDict__ctor(&self->modules);
c11_vector__ctor(&self->types, sizeof(pk_TypeInfo));
self->builtins = PY_NIL;
self->main = PY_NIL;
self->builtins = *py_NIL;
self->main = *py_NIL;
self->_ceval_on_step = NULL;
self->_import_file = pk_default_import_file;
self->_stdout = pk_default_stdout;
self->_stderr = pk_default_stderr;
self->last_retval = PY_NIL;
self->last_exception = PY_NIL;
self->last_retval = *py_NIL;
self->last_exception = *py_NIL;
self->is_stopiteration = false;
self->__curr_class = PY_NIL;
self->__curr_class = NULL;
self->__dynamic_func_decl = NULL;
pk_ManagedHeap__ctor(&self->heap, self);
@ -388,7 +388,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
// submit the call
if(!fn->cfunc) {
pk_VM__push_frame(self, Frame__new(co, fn->module, p0, p0, argv, co));
pk_VM__push_frame(self, Frame__new(co, &fn->module, p0, p0, argv, co));
return opcall ? RES_CALL : pk_VM__run_top_frame(self);
} else {
bool ok = py_callcfunc(p0, fn->cfunc, co->nlocals, argv);
@ -408,10 +408,10 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
// [callable, <self>, args..., local_vars...]
// ^p0 ^p1 ^_sp
self->stack.sp = argv + co->nlocals;
// initialize local variables to PY_NIL
// initialize local variables to py_NIL
memset(p1, 0, (char*)self->stack.sp - (char*)p1);
// submit the call
pk_VM__push_frame(self, Frame__new(co, fn->module, p0, p0, argv, co));
pk_VM__push_frame(self, Frame__new(co, &fn->module, p0, p0, argv, co));
return opcall ? RES_CALL : pk_VM__run_top_frame(self);
case FuncType_GENERATOR:
assert(false);
@ -537,15 +537,17 @@ void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) {
mark_value(p);
}
// mark frame
for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) {
mark_value(&frame->module);
if(frame->function) mark_object(frame->function);
}
// mark vm's registers
mark_value(&vm->last_retval);
mark_value(&vm->last_exception);
for(int i = 0; i < c11__count_array(vm->reg); i++) {
mark_value(&vm->reg[i]);
}
mark_value(&vm->__curr_class);
}
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {

View File

@ -1,4 +0,0 @@
#include "pocketpy/objects/base.h"
py_TValue PY_NIL = {.type=0, .is_ptr=false, .extra=0, ._i64=0};

View File

@ -158,10 +158,10 @@ void CodeObject__dtor(CodeObject* self) {
c11_vector__dtor(&self->func_decls);
}
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module) {
void Function__ctor(Function* self, FuncDecl_ decl, py_TValue* module) {
PK_INCREF(decl);
self->decl = decl;
self->module = module;
self->module = module ? *module : *py_NIL;
self->clazz = NULL;
self->closure = NULL;
self->cfunc = NULL;

View File

@ -25,6 +25,15 @@ void py_setdict(py_Ref self, py_Name name, const py_Ref val) {
pk_NameDict__set(PyObject__dict(self->_obj), name, *val);
}
bool py_deldict(py_Ref self, py_Name name) {
assert(self && self->is_ptr);
if(self->type == tp_type && py_ismagicname(name)) {
py_Type* ud = py_touserdata(self);
py_newnil(py_tpmagic(*ud, name));
}
return pk_NameDict__del(PyObject__dict(self->_obj), name);
}
py_Ref py_getslot(const py_Ref self, int i) {
assert(self && self->is_ptr);
assert(i >= 0 && i < self->_obj->slots);

View File

@ -14,6 +14,7 @@ pk_VM* pk_current_vm;
py_GlobalRef py_True;
py_GlobalRef py_False;
py_GlobalRef py_None;
py_GlobalRef py_NIL;
static pk_VM pk_default_vm;
@ -23,14 +24,15 @@ void py_initialize() {
pk_current_vm = &pk_default_vm;
// initialize some convenient references
static py_TValue _True, _False, _None;
static py_TValue _True, _False, _None, _NIL;
py_newbool(&_True, true);
py_newbool(&_False, false);
py_newnone(&_None);
py_newnil(&_NIL);
py_True = &_True;
py_False = &_False;
py_None = &_None;
py_NIL = &_NIL;
pk_VM__ctor(&pk_default_vm);
}
@ -183,7 +185,7 @@ static bool
// disassemble(&co);
Frame* frame = Frame__new(&co, vm->main._obj, NULL, vm->stack.sp, vm->stack.sp, &co);
Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co);
pk_VM__push_frame(vm, frame);
pk_FrameResult res = pk_VM__run_top_frame(vm);
CodeObject__dtor(&co);
@ -289,6 +291,7 @@ py_Ref py_tpmagic(py_Type type, py_Name name) {
}
py_Ref py_tpobject(py_Type type) {
assert(type);
pk_VM* vm = pk_current_vm;
return &c11__at(pk_TypeInfo, &vm->types, type)->self;
}

View File

@ -1,8 +1,3 @@
class A: pass
class B: pass
a = A()
assert type(a) is A
x = 0
if x==0: x=1
assert x==1
@ -17,4 +12,9 @@ else: x=3
assert x==2
def f1(x): return x+1
assert f1(1)==2
assert f1(1)==2
# class A: pass
# class B: pass
# a = A()
# assert type(a) is A