blueloveTH 1 gadu atpakaļ
vecāks
revīzija
51e2433404

+ 2 - 8
include/pocketpy/interpreter/frame.h

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

+ 2 - 2
include/pocketpy/interpreter/vm.h

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

+ 0 - 2
include/pocketpy/objects/base.h

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

+ 2 - 2
include/pocketpy/objects/codeobject.h

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

+ 2 - 0
include/pocketpy/pocketpy.h

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

+ 0 - 2
include/pocketpy/xmacros/opcodes.h

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

+ 35 - 4
src/compiler/compiler.c

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

+ 68 - 18
src/interpreter/ceval.c

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

+ 2 - 2
src/interpreter/frame.c

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

+ 14 - 12
src/interpreter/vm.c

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

+ 0 - 4
src/objects/base.c

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

+ 2 - 2
src/objects/codeobject.c

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

+ 9 - 0
src/public/stack_ops.c

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

+ 6 - 3
src/public/vm.c

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

+ 6 - 6
tests/24_inline_blocks.py

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

+ 0 - 0
tests/22_bytes.py → tests/68_bytes.py