diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 8ad1679e..6b00cbb4 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -64,7 +64,6 @@ typedef struct pk_VM { PyVar last_retval; // registers PyVar reg[8]; - PyVar sysreg[8]; PyObject* __curr_class; PyObject* __cached_object_new; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index cf23be68..9808a9ea 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -1,12 +1,9 @@ #pragma once -#include "stdint.h" -#include "stdbool.h" - -#ifdef __cplusplus -extern "C" { -#endif +#include +#include +/************* Public Types *************/ typedef struct PyObject PyObject; typedef struct PyVar PyVar; typedef struct pk_VM pk_VM; @@ -27,38 +24,28 @@ typedef enum BindType { BindType_CLASSMETHOD, } BindType; - - extern pk_VM* pk_current_vm; - +/************* Global VMs *************/ void py_initialize(); -// void py_switch_vm(const char* name); void py_finalize(); -int py_exec_simple(const char*); -int py_eval_simple(const char*, py_Ref); +int py_exec(const char*); +int py_eval(const char*); -/* py_error */ -py_Error* py_getlasterror(); -void py_Error__print(py_Error*); - -int py_eq(const py_Ref, const py_Ref); -int py_le(const py_Ref, const py_Ref); -int py_hash(const py_Ref, int64_t* out); - -/* py_var */ +/************* Values Creation *************/ void py_newint(py_Ref, int64_t); void py_newfloat(py_Ref, double); void py_newbool(py_Ref, bool); void py_newstr(py_Ref, const char*); void py_newstrn(py_Ref, const char*, int); // void py_newfstr(py_Ref, const char*, ...); -void py_newbytes(py_Ref, const uint8_t*, int); +// void py_newbytes(py_Ref, const uint8_t*, int); void py_newnone(py_Ref); void py_newnull(py_Ref); void py_newtuple(py_Ref, int); +// void py_newlist(py_Ref); // new style decl-based function void py_newfunction(py_Ref, py_CFunction, const char* sig, BindType bt); @@ -67,48 +54,55 @@ void py_newfunction2(py_Ref, py_CFunction, const char* sig, BindType bt, const c void py_newnativefunc(py_Ref, py_CFunction, int argc, BindType bt); void py_newnativefunc2(py_Ref, py_CFunction, int argc, BindType bt, const char* docstring, const py_Ref userdata); - -py_Ref py_newmodule(const char* name, const char* package); -py_Ref py_getmodule(const char* name); -const py_Ref py_import(const char* name); - -#define py_isnull(self) ((self)->type == 0) - - -/// Sets the name of the object to the given value. -void py_setdict(py_Ref self, py_Name name, const py_Ref val); -/// Returns a reference to the name of the object. +/************* References *************/ py_Ref py_getdict(const py_Ref self, py_Name name); +void py_setdict(py_Ref self, py_Name name, const py_Ref val); -/// Sets the i-th slot of the object to the given value. -void py_setslot(py_Ref self, int i, const py_Ref val); -/// Returns a reference to the i-th slot of the object. py_Ref py_getslot(const py_Ref self, int i); +void py_setslot(py_Ref self, int i, const py_Ref val); -/// Equivalent to `self.name = val`. -/// Returns 0 | err -int py_setattr(py_Ref self, py_Name name, const py_Ref val); +// int py_getattr(const py_Ref self, py_Name name, py_Ref out); +// int py_setattr(py_Ref self, py_Name name, const py_Ref val); -/// Equivalent to `self.name`. -/// Returns 0 | err -int py_getattr(const py_Ref self, py_Name name, py_Ref out); +/// Copies src to dst. +void py_copyref(const py_Ref src, py_Ref dst); +/************* Stack Operations *************/ +py_Ref py_gettop(); +void py_settop(const py_Ref); +py_Ref py_getsecond(); +void py_setsecond(const py_Ref); /// Returns a reference to the i-th object from the top of the stack. /// i should be negative, e.g. (-1) means TOS. -py_Ref py_stack(int i); -/// Returns a reference to the i-th register. -py_Ref py_reg(int i); -/// Returns a reference to the i-th system register. -py_Ref py_sysreg(int i); +py_Ref py_peek(int i); /// Prepares a push and returns an uninitialized reference. py_Ref py_push(); - +/// Pops an object from the stack. +void py_pop(); +void py_shrink(int n); /// Pushes the object to the stack. void py_pushref(const py_Ref src); -/// Pops the object from the stack. -void py_copyref(const py_Ref src, py_Ref dst); +/// Get a temporary variable from the stack and returns the reference to it. +py_Ref py_pushtmp(); +/// Free n temporary variable. +void py_poptmp(int n); + +/************* Modules *************/ +py_Ref py_newmodule(const char* name, const char* package); +py_Ref py_getmodule(const char* name); +void py_import(const char* name, py_Ref out); + +/************* Errors *************/ +py_Error* py_getlasterror(); +void py_Error__print(py_Error*); + +int py_eq(const py_Ref, const py_Ref); +int py_le(const py_Ref, const py_Ref); +int py_hash(const py_Ref, int64_t* out); + +#define py_isnull(self) ((self)->type == 0) /* tuple */ diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 0bfedb2d..44dbb587 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -106,19 +106,19 @@ void pk_VM__ctor(pk_VM* self){ ValueStack__ctor(&self->stack); self->True = (PyVar){.type=tp_bool, .is_ptr=true, .extra=1, - ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 1), + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0), }; self->False = (PyVar){.type=tp_bool, .is_ptr=true, .extra=0, - ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 1), + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0), }; self->None = (PyVar){.type=tp_none_type, .is_ptr=true, - ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_none_type, 0, 1), + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_none_type, 0, 0), }; self->NotImplemented = (PyVar){.type=tp_not_implemented_type, .is_ptr=true, - ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_not_implemented_type, 0, 1), + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_not_implemented_type, 0, 0), }; self->Ellipsis = (PyVar){.type=tp_ellipsis, .is_ptr=true, - ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_ellipsis, 0, 1), + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_ellipsis, 0, 0), }; /* Init Builtin Types */ diff --git a/src/pocketpy.c b/src/pocketpy.c index 6a801ac1..dc1347c1 100644 --- a/src/pocketpy.c +++ b/src/pocketpy.c @@ -5,135 +5,13 @@ #include #include -pk_VM* pk_current_vm; -static pk_VM pk_default_vm; -void py_initialize(){ - Pools_initialize(); - pk_StrName__initialize(); - pk_current_vm = &pk_default_vm; - pk_VM__ctor(&pk_default_vm); -} -int py_exec_simple(const char* source){ - CodeObject* co = NULL; - pk_VM* vm = pk_current_vm; - 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); - if(res == RES_ERROR) return vm->last_error->type; - if(res == RES_RETURN) return 0; // vm->last_retval; - assert(0); // unreachable -} -py_Ref py_getmodule(const char *name){ - pk_VM* vm = pk_current_vm; - return pk_NameDict__try_get(&vm->modules, py_name(name)); -} -py_Ref py_newmodule(const char *name, const char *package){ - pk_ManagedHeap* heap = &pk_current_vm->heap; - PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_module, -1, 0); - py_Ref r0 = py_sysreg(0); - py_Ref r1 = py_sysreg(1); - *r0 = PyVar__fromobj(obj); - py_newstr(r1, name); - py_setdict(r0, __name__, r1); - package = package ? package : ""; - py_newstr(r1, package); - py_setdict(r0, __package__, r1); - // convert to fullname - if(package[0] != '\0'){ - // package.name - char buf[256]; - snprintf(buf, sizeof(buf), "%s.%s", package, name); - name = buf; - } - - py_newstr(r1, name); - py_setdict(r0, __path__, r1); - - // we do not allow override in order to avoid memory leak - // it is because Module objects are not garbage collected - bool exists = pk_NameDict__contains(&pk_current_vm->modules, py_name(name)); - if(exists) abort(); - pk_NameDict__set(&pk_current_vm->modules, py_name(name), *r0); - return py_getmodule(name); -} - -py_Error* py_getlasterror(){ - return pk_current_vm->last_error; -} - -void py_Error__print(py_Error* self){ - abort(); -} - -py_Ref py_reg(int i){ - assert(i >= 0 && i < 8); - return &pk_current_vm->reg[i]; -} - -py_Ref py_sysreg(int i){ - assert(i >= 0 && i < 8); - return &pk_current_vm->sysreg[i]; -} - -py_Ref py_stack(int i){ - assert(i < 0); - return &pk_current_vm->stack.sp[i]; -} - -void py_finalize(){ - pk_VM__dtor(&pk_default_vm); - pk_current_vm = NULL; - pk_StrName__finalize(); - Pools_finalize(); -} - -void py_setdict(py_Ref self, py_Name name, const py_Ref val){ - pk_NameDict__set( - PyObject__dict(self->_obj), - name, - *val - ); -} - -void py_newint(py_Ref self, int64_t val){ - self->type = tp_int; - self->is_ptr = false; - self->_i64 = val; -} - -void py_newfloat(py_Ref self, double val){ - self->type = tp_float; - self->is_ptr = false; - self->_f64 = val; -} - -void py_newbool(py_Ref self, bool val){ - pk_VM* vm = pk_current_vm; - *self = val ? vm->True : vm->False; -} - -void py_newstr(py_Ref self, const char* val){ - pk_VM* vm = pk_current_vm; - PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_str, 0, sizeof(py_Str)); - py_Str__ctor((py_Str*)PyObject__value(obj), val); - self->type = tp_str; - self->is_ptr = true; - self->_obj = obj; -} diff --git a/src/public/error.c b/src/public/error.c new file mode 100644 index 00000000..70933374 --- /dev/null +++ b/src/public/error.c @@ -0,0 +1,15 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + + +py_Error* py_getlasterror(){ + return pk_current_vm->last_error; +} + +void py_Error__print(py_Error* self){ + abort(); +} + diff --git a/src/public/modules.c b/src/public/modules.c new file mode 100644 index 00000000..fba0b1b2 --- /dev/null +++ b/src/public/modules.c @@ -0,0 +1,48 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +py_Ref py_getmodule(const char *name){ + pk_VM* vm = pk_current_vm; + return pk_NameDict__try_get(&vm->modules, py_name(name)); +} + +py_Ref py_newmodule(const char *name, const char *package){ + pk_ManagedHeap* heap = &pk_current_vm->heap; + PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_module, -1, 0); + + py_Ref r0 = py_pushtmp(); + py_Ref r1 = py_pushtmp(); + + *r0 = PyVar__fromobj(obj); + + py_newstr(r1, name); + py_setdict(r0, __name__, r1); + + package = package ? package : ""; + + py_newstr(r1, package); + py_setdict(r0, __package__, r1); + + // convert to fullname + if(package[0] != '\0'){ + // package.name + char buf[256]; + snprintf(buf, sizeof(buf), "%s.%s", package, name); + name = buf; + } + + py_newstr(r1, name); + py_setdict(r0, __path__, r1); + + // we do not allow override in order to avoid memory leak + // it is because Module objects are not garbage collected + bool exists = pk_NameDict__contains(&pk_current_vm->modules, py_name(name)); + if(exists) abort(); + pk_NameDict__set(&pk_current_vm->modules, py_name(name), *r0); + + py_poptmp(2); + return py_getmodule(name); +} diff --git a/src/public/stackops.c b/src/public/stackops.c new file mode 100644 index 00000000..b832d67c --- /dev/null +++ b/src/public/stackops.c @@ -0,0 +1,84 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +py_Ref py_getdict(const py_Ref self, py_Name name){ + assert(self && self->is_ptr); + return pk_NameDict__try_get(PyObject__dict(self->_obj), name); +} + +void py_setdict(py_Ref self, py_Name name, const py_Ref val){ + assert(self && self->is_ptr); + pk_NameDict__set(PyObject__dict(self->_obj), name, *val); +} + +py_Ref py_getslot(const py_Ref self, int i){ + assert(self && self->is_ptr); + assert(i >= 0 && i < self->_obj->slots); + return PyObject__slots(self->_obj) + i; +} + +void py_setslot(py_Ref self, int i, const py_Ref val){ + assert(self && self->is_ptr); + assert(i >= 0 && i < self->_obj->slots); + PyObject__slots(self->_obj)[i] = *val; +} + +void py_copyref(const py_Ref src, py_Ref dst){ + *dst = *src; +} + +/* Stack References */ +py_Ref py_gettop(){ + return pk_current_vm->stack.sp - 1; +} + +void py_settop(const py_Ref val){ + pk_current_vm->stack.sp[-1] = *val; +} + +py_Ref py_getsecond(){ + return pk_current_vm->stack.sp - 2; +} + +void py_setsecond(const py_Ref val){ + pk_current_vm->stack.sp[-2] = *val; +} + +py_Ref py_peek(int i){ + assert(i < 0); + return pk_current_vm->stack.sp + i; +} + +py_Ref py_push(){ + pk_VM* vm = pk_current_vm; + py_Ref top = vm->stack.sp; + vm->stack.sp++; + return top; +} + +void py_pop(){ + pk_VM* vm = pk_current_vm; + vm->stack.sp--; +} + +void py_shrink(int n){ + pk_VM* vm = pk_current_vm; + vm->stack.sp -= n; +} + +void py_pushref(const py_Ref src){ + *py_push() = *src; +} + +py_Ref py_pushtmp(){ + py_Ref r = py_push(); + py_newnull(r); + return r; +} + +void py_poptmp(int n){ + py_shrink(n); +} \ No newline at end of file diff --git a/src/public/values.c b/src/public/values.c new file mode 100644 index 00000000..8eaecfed --- /dev/null +++ b/src/public/values.c @@ -0,0 +1,73 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +void py_newint(py_Ref self, int64_t val){ + self->type = tp_int; + self->is_ptr = false; + self->_i64 = val; +} + +void py_newfloat(py_Ref self, double val){ + self->type = tp_float; + self->is_ptr = false; + self->_f64 = val; +} + +void py_newbool(py_Ref self, bool val){ + pk_VM* vm = pk_current_vm; + *self = val ? vm->True : vm->False; +} + +void py_newstr(py_Ref self, const char* data){ + pk_ManagedHeap* heap = &pk_current_vm->heap; + PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, sizeof(py_Str)); + py_Str__ctor((py_Str*)PyObject__value(obj), data); + self->type = tp_str; + self->is_ptr = true; + self->_obj = obj; +} + +void py_newstrn(py_Ref self, const char* data, int size){ + pk_ManagedHeap* heap = &pk_current_vm->heap; + PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, sizeof(py_Str)); + py_Str__ctor2((py_Str*)PyObject__value(obj), data, size); + self->type = tp_str; + self->is_ptr = true; + self->_obj = obj; +} + +void py_newnone(py_Ref self){ + pk_VM* vm = pk_current_vm; + *self = vm->None; +} + +void py_newnull(py_Ref self){ + self->type = 0; +} + +void py_newtuple(py_Ref self, int n){ + pk_VM* vm = pk_current_vm; + PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_tuple, n, 0); + self->type = tp_tuple; + self->is_ptr = true; + self->_obj = obj; +} + +void py_newfunction(py_Ref self, py_CFunction f, const char* sig, BindType bt){ + py_newfunction2(self, f, sig, bt, NULL, NULL); +} + +void py_newfunction2(py_Ref self, py_CFunction f, const char *sig, BindType bt, const char *docstring, const py_Ref userdata){ + +} + +void py_newnativefunc(py_Ref self, py_CFunction f, int argc, BindType bt){ + py_newnativefunc2(self, f, argc, bt, NULL, NULL); +} + +void py_newnativefunc2(py_Ref self, py_CFunction f, int argc, BindType bt, const char *docstring, const py_Ref userdata){ + +} \ No newline at end of file diff --git a/src/public/vm.c b/src/public/vm.c new file mode 100644 index 00000000..c2548360 --- /dev/null +++ b/src/public/vm.c @@ -0,0 +1,40 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + +pk_VM* pk_current_vm; +static pk_VM pk_default_vm; + +void py_initialize(){ + Pools_initialize(); + pk_StrName__initialize(); + pk_current_vm = &pk_default_vm; + pk_VM__ctor(&pk_default_vm); +} + +void py_finalize(){ + pk_VM__dtor(&pk_default_vm); + pk_current_vm = NULL; + pk_StrName__finalize(); + Pools_finalize(); +} + +int py_exec(const char* source){ + CodeObject* co = NULL; + pk_VM* vm = pk_current_vm; + 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); + if(res == RES_ERROR) return vm->last_error->type; + if(res == RES_RETURN) return 0; // vm->last_retval; + assert(0); // unreachable +} diff --git a/src2/main.c b/src2/main.c index 005fca28..3cd9d531 100644 --- a/src2/main.c +++ b/src2/main.c @@ -1,7 +1,7 @@ #include #include + #include "pocketpy.h" -#include "pocketpy/pocketpy.h" char* read_file(const char* path) { FILE* file = fopen(path, "r"); @@ -28,7 +28,7 @@ int main(int argc, char** argv) { char* source = read_file(argv[1]); py_initialize(); - if(py_exec_simple(source)){ + if(py_exec(source)){ py_Error* err = py_getlasterror(); py_Error__print(err); }