From a648313fb7ced3d27011db2967ba08aa6ebff593 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 30 Jul 2024 23:44:22 +0800 Subject: [PATCH] ... --- include/pocketpy/interpreter/vm.h | 1 + include/pocketpy/pocketpy.h | 230 ++++++++++++++---------------- src/interpreter/ceval.c | 6 +- src/public/{vm.c => internal.c} | 21 +-- src/public/modules.c | 8 +- src/public/py_dict.c | 6 + src/public/py_ops.c | 6 +- src/public/py_str.c | 8 ++ src/public/stack_ops.c | 4 +- src/public/values.c | 51 ++++--- src2/main.c | 4 +- 11 files changed, 170 insertions(+), 175 deletions(-) rename src/public/{vm.c => internal.c} (93%) diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 193acfc7..32fc5b61 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -94,6 +94,7 @@ bool pk_arrayiter(py_Ref val); bool pk_arraycontains(py_Ref self, py_Ref val); bool pk_pushmethod(py_StackRef self, py_Name name); +bool pk_callmagic(py_Name name, int argc, py_Ref argv); /// Assumes [a, b] are on the stack, performs a binary op. /// The result is stored in `self->last_retval`. diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index be7c0f72..65aafb08 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -15,7 +15,8 @@ typedef int16_t py_Type; typedef int64_t py_i64; typedef double py_f64; -/* string_view */ +#define PY_RAISE // mark a function that can raise an exception + typedef struct c11_sv { const char* data; int size; @@ -36,26 +37,33 @@ typedef py_TValue* py_TmpRef; /// @param argc number of arguments. /// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument. /// @return true if the function is successful. -typedef bool (*py_CFunction)(int argc, py_StackRef argv); +typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE; -enum py_BindType { - bt_function, - bt_staticmethod, - bt_classmethod, -}; +enum py_BindType { bt_function, bt_staticmethod, bt_classmethod }; enum py_CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, CELL_MODE }; -/************* Global VMs *************/ +extern py_GlobalRef py_True; +extern py_GlobalRef py_False; +extern py_GlobalRef py_None; +extern py_GlobalRef py_NIL; + +/************* Global Setup *************/ +/// Initialize the VM. void py_initialize(); +/// Finalize the VM. void py_finalize(); -/// Run a simple source string. Do not change the stack. -bool py_exec(const char* source); -/// Eval a simple expression. -/// The result will be set to `py_retval()`. -bool py_eval(const char* source); -bool py_exec2(const char* source, const char* filename, enum py_CompileMode mode); +/// Run a source string. +/// @param source source string. +/// @param filename filename (for error messages). +/// @param mode compile mode. Use `EXEC_MODE` for statements `EVAL_MODE` for expressions. +/// @param module target module. Use NULL for the main module. +/// @return true if the execution is successful. +bool py_exec(const char* source, + const char* filename, + enum py_CompileMode mode, + py_Ref module) PY_RAISE; /************* Values Creation *************/ void py_newint(py_Ref, py_i64); @@ -78,6 +86,17 @@ void py_newlist(py_Ref); /// You should initialize all elements before using it. void py_newlistn(py_Ref, int n); +void py_newdict(py_Ref); +void py_newslice(py_Ref); +void py_newnativefunc(py_Ref out, py_CFunction); +py_Name py_newfunction(py_Ref out, + const char* sig, + py_CFunction f, + enum py_BindType bt, + const char* docstring, + int slots); + +/************* Name Convertions *************/ py_Name py_name(const char*); const char* py_name2str(py_Name); py_Name py_namev(c11_sv name); @@ -85,12 +104,7 @@ c11_sv py_name2sv(py_Name); #define py_ismagicname(name) (name <= __missing__) -// opaque types -void py_newdict(py_Ref); -void py_newslice(py_Ref); -// old style argc-based function -void py_newnativefunc(py_Ref out, py_CFunction); - +/************* Meta Operations *************/ /// Create a new type. /// @param name name of the type. /// @param base base type. @@ -104,6 +118,7 @@ py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, vo /// @param slots number of slots. Use -1 to create a `__dict__`. /// @param udsize size of your userdata. You can use `py_touserdata()` to get the pointer to it. void* py_newobject(py_Ref out, py_Type type, int slots, int udsize); + /************* Type Cast *************/ py_i64 py_toint(py_Ref); py_f64 py_tofloat(py_Ref); @@ -125,15 +140,34 @@ void* py_touserdata(py_Ref); #define py_istuple(self) py_istype(self, tp_tuple) #define py_isdict(self) py_istype(self, tp_dict) +#define py_isnil(self) py_istype(self, 0) +#define py_isnone(self) py_istype(self, tp_NoneType) + +py_Type py_typeof(py_Ref self); bool py_istype(py_Ref, py_Type); bool py_isinstance(py_Ref obj, py_Type type); 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; +/// Search the magic method from the given type to the base type. +py_GlobalRef py_tpfindmagic(py_Type, py_Name name); +/// Search the name from the given type to the base type. +py_GlobalRef py_tpfindname(py_Type, py_Name name); +/// Get the type object of the given type. +py_GlobalRef py_tpobject(py_Type type); +/// Get the type name. +const char* py_tpname(py_Type type); +/// Call a type to create a new instance. +bool py_tpcall(py_Type type, int argc, py_Ref argv); +/// Find the magic method from the given type to the base type. +py_GlobalRef py_tpmagic(py_Type type, py_Name name); +/// Check if the object is an instance of the given type. +bool py_checktype(py_Ref self, py_Type type) PY_RAISE; + +#define py_checkint(self) py_checktype(self, tp_int) +#define py_checkfloat(self) py_checktype(self, tp_float) +#define py_checkbool(self) py_checktype(self, tp_bool) +#define py_checkstr(self) py_checktype(self, tp_str) /************* References *************/ #define PY_CHECK_ARGC(n) \ if(argc != n) return TypeError("expected %d arguments, got %d", n, argc) @@ -144,27 +178,16 @@ extern py_GlobalRef py_NIL; #define py_offset(p, i) ((py_Ref)((char*)p + ((i) << 4))) #define py_arg(i) py_offset(argv, i) -py_GlobalRef py_tpmagic(py_Type type, py_Name name); -#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f)) - -// new style decl-based bindings -void py_bind(py_Ref obj, const char* sig, py_CFunction f); - -py_ObjectRef py_bind2(py_Ref obj, - const char* sig, - py_CFunction f, - enum py_BindType bt, - const char* docstring, - int slots); - -// old style argc-based bindings -void py_bindmethod(py_Type type, const char* name, py_CFunction f); -void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum py_BindType bt); -void py_bindfunc(py_Ref obj, const char* name, py_CFunction f); - /// Get the reference to the i-th register. /// All registers are located in a contiguous memory. -py_GlobalRef py_reg(int i); +py_GlobalRef py_getreg(int i); +/// Set the reference to the i-th register. +void py_setreg(int i, py_Ref val); + +/// Equivalent to `*dst = *src`. +void py_assign(py_Ref dst, py_Ref src); +/// The return value of the most recent call. +py_GlobalRef py_retval(); /// Get the reference of the object's `__dict__`. /// The object must have a `__dict__`. @@ -178,21 +201,28 @@ bool py_deldict(py_Ref self, py_Name name); py_ObjectRef py_getslot(py_Ref self, int i); void py_setslot(py_Ref self, int i, py_Ref val); -/// Gets the attribute of the object. -bool py_getattr(py_Ref self, py_Name name); -/// Sets the attribute of the object. -bool py_setattr(py_Ref self, py_Name name, py_Ref val); -/// Deletes the attribute of the object. -bool py_delattr(py_Ref self, py_Name name); +/************* Bindings *************/ +// new style decl-based bindings +void py_bind(py_Ref obj, const char* sig, py_CFunction f); +// old style argc-based bindings +void py_bindmethod(py_Type type, const char* name, py_CFunction f); +void py_bindfunc(py_Ref obj, const char* name, py_CFunction f); -bool py_getitem(py_Ref self, py_Ref key); -bool py_setitem(py_Ref self, py_Ref key, py_Ref val); -bool py_delitem(py_Ref self, py_Ref key); +#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f)) + +/************* Python Equivalents *************/ +bool py_getattr(py_Ref self, py_Name name) PY_RAISE; +bool py_setattr(py_Ref self, py_Name name, py_Ref val) PY_RAISE; +bool py_delattr(py_Ref self, py_Name name) PY_RAISE; + +bool py_getitem(py_Ref self, py_Ref key) PY_RAISE; +bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE; +bool py_delitem(py_Ref self, py_Ref key) PY_RAISE; /// Perform a binary operation on the stack. /// It assumes `lhs` and `rhs` are already pushed to the stack. /// The result will be set to `py_retval()`. -bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop); +bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE; #define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__) #define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__) @@ -209,9 +239,6 @@ bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop); #define py_binaryxor(lhs, rhs) py_binaryop(lhs, rhs, __xor__, 0) #define py_binarymatmul(lhs, rhs) py_binaryop(lhs, rhs, __matmul__, 0) -/// Equivalent to `*dst = *src`. -void py_assign(py_Ref dst, py_Ref src); - /************* Stack Operations *************/ /// Return a reference to the i-th object from the top of the stack. /// i should be negative, e.g. (-1) means TOS. @@ -238,13 +265,13 @@ py_TmpRef py_getmodule(const char* name); /// Import a module. /// The result will be set to `py_retval()`. -bool py_import(const char* name); +bool py_import(const char* name) PY_RAISE; /************* Errors *************/ /// Raise an exception by name and message. Always returns false. -bool py_exception(const char* name, const char* fmt, ...); +bool py_exception(const char* name, const char* fmt, ...) PY_RAISE; /// Raise an expection object. Always returns false. -bool py_raise(py_Ref); +bool py_raise(py_Ref) PY_RAISE; /// Print the last error to the console. void py_printexc(); /// Format the last error to a string. @@ -264,13 +291,16 @@ bool py_checkexc(); py_exception("UnboundLocalError", "local variable '%n' referenced before assignment", (n)) bool StopIteration(); -bool KeyError(py_Ref key); +bool KeyError(py_Ref key) PY_RAISE; /************* Operators *************/ +int py_equal(py_Ref lhs, py_Ref rhs) PY_RAISE; +int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE; + /// Equivalent to `bool(val)`. /// Returns 1 if `val` is truthy, otherwise 0. /// Returns -1 if an error occurred. -int py_bool(py_Ref val); +int py_bool(py_Ref val) PY_RAISE; #define py_eq(lhs, rhs) py_binaryop(lhs, rhs, __eq__, __eq__) #define py_ne(lhs, rhs) py_binaryop(lhs, rhs, __ne__, __ne__) @@ -279,61 +309,42 @@ int py_bool(py_Ref val); #define py_gt(lhs, rhs) py_binaryop(lhs, rhs, __gt__, __lt__) #define py_ge(lhs, rhs) py_binaryop(lhs, rhs, __ge__, __le__) -int py_equal(py_Ref lhs, py_Ref rhs); -int py_less(py_Ref lhs, py_Ref rhs); - -bool py_hash(py_Ref, py_i64* out); - +bool py_hash(py_Ref, py_i64* out) PY_RAISE; /// Get the iterator of the object. -bool py_iter(py_Ref); +bool py_iter(py_Ref) PY_RAISE; /// Get the next element from the iterator. /// 1: success, 0: StopIteration, -1: error -int py_next(py_Ref); - +int py_next(py_Ref) PY_RAISE; /// Python equivalent to `lhs is rhs`. bool py_isidentical(py_Ref, py_Ref); - /// A stack operation that calls a function. /// It assumes `argc + kwargc` arguments are already pushed to the stack. /// The result will be set to `py_retval()`. /// The stack size will be reduced by `argc + kwargc`. -bool py_vectorcall(uint16_t argc, uint16_t kwargc); +bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE; /// Call a function. /// It prepares the stack and then performs a `vectorcall(argc, 0, false)`. /// The result will be set to `py_retval()`. /// The stack remains unchanged after the operation. -bool py_call(py_Ref f, int argc, py_Ref argv); +bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE; /// Call a non-magic method. /// It prepares the stack and then performs a `vectorcall(argc+1, 0, false)`. /// The result will be set to `py_retval()`. /// The stack remains unchanged after the operation. -bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv); -/// Call a magic method using a continuous buffer. -/// The result will be set to `py_retval()`. -/// The stack remains unchanged after the operation. -bool py_callmagic(py_Name name, int argc, py_Ref argv); +bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) PY_RAISE; /// Call a `py_CFunction` in a safe way. -bool py_callcfunc(py_StackRef p0, py_CFunction cfunc, int argc, py_Ref argv); +bool py_callcfunc(py_StackRef p0, py_CFunction cfunc, int argc, py_Ref argv) PY_RAISE; -bool py_str(py_Ref val); -#define py_repr(val) py_callmagic(__repr__, 1, val) -#define py_len(val) py_callmagic(__len__, 1, val) +bool py_str(py_Ref val) PY_RAISE; +bool py_repr(py_Ref val) PY_RAISE; +bool py_len(py_Ref val) PY_RAISE; -/// The return value of the most recent call. -py_GlobalRef py_retval(); - -#define py_isnil(self) py_istype(self, 0) -#define py_isnone(self) py_istype(self, tp_NoneType) - -/* tuple */ - -// unchecked functions, if self is not a tuple, the behavior is undefined +/************* Unchecked Functions *************/ py_ObjectRef py_tuple__data(py_Ref self); py_ObjectRef py_tuple__getitem(py_Ref self, int i); void py_tuple__setitem(py_Ref self, int i, py_Ref val); int py_tuple__len(py_Ref self); -// unchecked functions, if self is not a list, the behavior is undefined py_TmpRef py_list__data(py_Ref self); py_TmpRef py_list__getitem(py_Ref self, int i); void py_list__setitem(py_Ref self, int i, py_Ref val); @@ -344,44 +355,17 @@ void py_list__clear(py_Ref self); void py_list__insert(py_Ref self, int i, py_Ref val); void py_list__reverse(py_Ref self); -// unchecked functions, if self is not a dict, the behavior is undefined -py_TmpRef py_dict__getitem(py_Ref self, py_Ref key); -void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val); +py_TmpRef py_dict__getitem(py_Ref self, py_Ref key) PY_RAISE; +void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE; +void py_dict__delitem(py_Ref self, py_Ref key) PY_RAISE; bool py_dict__contains(py_Ref self, py_Ref key); int py_dict__len(py_Ref self); bool py_dict__apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx); -/// Search the magic method from the given type to the base type. -/// Return the reference or NULL if not found. -py_GlobalRef py_tpfindmagic(py_Type, py_Name name); - -/// Search the name from the given type to the base type. -/// Return the reference or NULL if not found. -py_GlobalRef py_tpfindname(py_Type, py_Name name); - -/// Get the type object of the given type. -py_GlobalRef py_tpobject(py_Type type); - -/// Get the type name. -const char* py_tpname(py_Type type); - -/// Call a type to create a new instance. -bool py_tpcall(py_Type type, int argc, py_Ref argv); - -/// Check if the object is an instance of the given type. -bool py_checktype(py_Ref self, py_Type type); - -/// Get the type of the object. -py_Type py_typeof(py_Ref self); - -#define py_checkint(self) py_checktype(self, tp_int) -#define py_checkfloat(self) py_checktype(self, tp_float) -#define py_checkbool(self) py_checktype(self, tp_bool) -#define py_checkstr(self) py_checktype(self, tp_str) - +/************* Others *************/ int py_replinput(char* buf); -/// Python favored string formatting. +/// Python favored string formatting. (just put here, not for users) /// %d: int /// %i: py_i64 (int64_t) /// %f: py_f64 (double) diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index ea3a441f..175f37bf 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -717,7 +717,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { } ///////// case OP_UNARY_NEGATIVE: { - if(!py_callmagic(__neg__, 1, TOP())) goto __ERROR; + if(!pk_callmagic(__neg__, 1, TOP())) goto __ERROR; *TOP() = self->last_retval; DISPATCH(); } @@ -735,7 +735,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { DISPATCH(); } case OP_UNARY_INVERT: { - if(!py_callmagic(__invert__, 1, TOP())) goto __ERROR; + if(!pk_callmagic(__invert__, 1, TOP())) goto __ERROR; *TOP() = self->last_retval; DISPATCH(); } @@ -889,7 +889,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg); const char* string = py_tostr(tmp); // TODO: optimize this - if(!py_exec2(string, "", EVAL_MODE)) goto __ERROR; + if(!py_exec(string, "", EVAL_MODE, &frame->module)) goto __ERROR; PUSH(py_retval()); DISPATCH(); } diff --git a/src/public/vm.c b/src/public/internal.c similarity index 93% rename from src/public/vm.c rename to src/public/internal.c index 8f67ca91..f855f0b8 100644 --- a/src/public/vm.c +++ b/src/public/internal.c @@ -174,8 +174,8 @@ static void disassemble(CodeObject* co) { c11_vector__dtor(&jumpTargets); } -static bool - pk_VM__exec(pk_VM* vm, const char* source, const char* filename, enum py_CompileMode mode) { +bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) { + pk_VM* vm = pk_current_vm; CodeObject co; pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false); Error* err = pk_compile(src, &co); @@ -189,8 +189,9 @@ static bool } // disassemble(&co); + if(!module) module = &vm->main; - Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co); + Frame* frame = Frame__new(&co, module, 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); @@ -200,14 +201,6 @@ static bool c11__unreachedable(); } -bool py_exec(const char* source) { return pk_VM__exec(pk_current_vm, source, "", EXEC_MODE); } - -bool py_eval(const char* source) { return pk_VM__exec(pk_current_vm, source, "", EVAL_MODE); } - -bool py_exec2(const char* source, const char* filename, enum py_CompileMode mode) { - return pk_VM__exec(pk_current_vm, source, filename, mode); -} - bool py_call(py_Ref f, int argc, py_Ref argv) { if(f->type == tp_nativefunc) { py_TValue* p0 = pk_current_vm->stack.sp; @@ -230,9 +223,7 @@ bool py_vectorcall(uint16_t argc, uint16_t kwargc) { py_Ref py_retval() { return &pk_current_vm->last_retval; } -bool py_pushmethod(py_Name name){ - return pk_pushmethod(py_peek(-1), name); -} +bool py_pushmethod(py_Name name) { return pk_pushmethod(py_peek(-1), name); } bool pk_pushmethod(py_StackRef self, py_Name name) { // NOTE: `out` and `out_self` may overlap with `self` @@ -317,7 +308,7 @@ bool py_tpcall(py_Type type, int argc, py_Ref argv) { return py_call(py_tpobject(type), argc, argv); } -bool py_callmagic(py_Name name, int argc, py_Ref argv) { +bool pk_callmagic(py_Name name, int argc, py_Ref argv) { assert(argc >= 1); assert(py_ismagicname(name)); py_Ref tmp = py_tpfindmagic(argv->type, name); diff --git a/src/public/modules.c b/src/public/modules.c index f2d54f64..762d29ae 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -156,7 +156,7 @@ static bool _py_builtins__hash(int argc, py_Ref argv) { static bool _py_builtins__abs(int argc, py_Ref argv) { PY_CHECK_ARGC(1); - return py_callmagic(__abs__, 1, argv); + return pk_callmagic(__abs__, 1, argv); } static bool _py_builtins__sum(int argc, py_Ref argv) { @@ -205,15 +205,13 @@ static bool _py_NoneType__repr__(int argc, py_Ref argv) { static bool _py_builtins__exec(int argc, py_Ref argv) { PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_str); - bool ok = py_exec(py_tostr(argv)); - py_newnone(py_retval()); - return ok; + return py_exec(py_tostr(argv), "", EXEC_MODE, NULL); } static bool _py_builtins__eval(int argc, py_Ref argv) { PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_str); - return py_eval(py_tostr(argv)); + return py_exec(py_tostr(argv), "", EVAL_MODE, NULL); } py_TValue pk_builtins__register() { diff --git a/src/public/py_dict.c b/src/public/py_dict.c index 43c1cfe8..ab37a956 100644 --- a/src/public/py_dict.c +++ b/src/public/py_dict.c @@ -500,6 +500,12 @@ py_Ref py_dict__getitem(py_Ref self, py_Ref key) { return NULL; } +void py_dict__delitem(py_Ref self, py_Ref key) { + assert(py_isdict(self)); + Dict* ud = py_touserdata(self); + Dict__pop(ud, key); +} + void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val) { assert(py_isdict(self)); Dict* ud = py_touserdata(self); diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 755b1be2..8d26d398 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -178,7 +178,7 @@ bool py_delattr(py_Ref self, py_Name name) { bool py_getitem(py_Ref self, py_Ref key) { py_push(self); py_push(key); - bool ok = py_callmagic(__getitem__, 2, py_peek(-2)); + bool ok = pk_callmagic(__getitem__, 2, py_peek(-2)); py_shrink(2); return ok; } @@ -187,7 +187,7 @@ bool py_setitem(py_Ref self, py_Ref key, py_Ref val) { py_push(self); py_push(key); py_push(val); - bool ok = py_callmagic(__setitem__, 3, py_peek(-3)); + bool ok = pk_callmagic(__setitem__, 3, py_peek(-3)); py_shrink(3); return ok; } @@ -195,7 +195,7 @@ bool py_setitem(py_Ref self, py_Ref key, py_Ref val) { bool py_delitem(py_Ref self, py_Ref key) { py_push(self); py_push(key); - bool ok = py_callmagic(__delitem__, 2, py_peek(-2)); + bool ok = pk_callmagic(__delitem__, 2, py_peek(-2)); py_shrink(2); return ok; } diff --git a/src/public/py_str.c b/src/public/py_str.c index e4031b12..83b1acac 100644 --- a/src/public/py_str.c +++ b/src/public/py_str.c @@ -545,3 +545,11 @@ bool py_str(py_Ref val) { if(!tmp) return py_repr(val); return py_call(tmp, 1, val); } + +bool py_repr(py_Ref val) { + return pk_callmagic(__repr__, 1, val); +} + +bool py_len(py_Ref val){ + return pk_callmagic(__len__, 1, val); +} \ No newline at end of file diff --git a/src/public/stack_ops.c b/src/public/stack_ops.c index 935b97f1..b16d7bc0 100644 --- a/src/public/stack_ops.c +++ b/src/public/stack_ops.c @@ -4,7 +4,9 @@ #include "pocketpy/objects/object.h" #include "pocketpy/interpreter/vm.h" -py_Ref py_reg(int i) { return pk_current_vm->reg + i; } +py_Ref py_getreg(int i) { return pk_current_vm->reg + i; } + +void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; } py_Ref py_getdict(py_Ref self, py_Name name) { assert(self && self->is_ptr); diff --git a/src/public/values.c b/src/public/values.c index 53a2a6e3..46985e69 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -49,10 +49,6 @@ void py_newnativefunc(py_Ref out, py_CFunction f) { } void py_bindmethod(py_Type type, const char* name, py_CFunction f) { - py_bindmethod2(type, name, f, bt_function); -} - -void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum py_BindType bt) { py_TValue tmp; py_newnativefunc(&tmp, f); py_setdict(py_tpobject(type), py_name(name), &tmp); @@ -66,28 +62,37 @@ void py_bindfunc(py_Ref obj, const char* name, py_CFunction f) { void py_bind(py_Ref obj, const char* sig, py_CFunction f) { py_TValue tmp; - do { - char buffer[256]; - snprintf(buffer, sizeof(buffer), "def %s: pass", sig); - // fn(a, b, *c, d=1) -> None - CodeObject code; - pk_SourceData_ source = pk_SourceData__rcnew(buffer, "", EXEC_MODE, false); - Error* err = pk_compile(source, &code); - if(err) c11__abort("py_bind(): failed to compile signature '%s'", sig); - if(code.func_decls.count != 1) c11__abort("py_bind(): invalid signature '%s'", sig); - FuncDecl_ decl = c11__getitem(FuncDecl_, &code.func_decls, 0); - // construct the function - Function* ud = py_newobject(&tmp, tp_function, 0, sizeof(Function)); - Function__ctor(ud, decl, NULL); - ud->cfunc = f; - CodeObject__dtor(&code); - PK_DECREF(source); - } while(0); - Function* ud = py_touserdata(&tmp); - py_Name name = py_name(ud->decl->code.name->data); + py_Name name = py_newfunction(&tmp, sig, f, bt_function, NULL, 0); py_setdict(obj, name, &tmp); } +py_Name py_newfunction(py_Ref out, + const char* sig, + py_CFunction f, + enum py_BindType bt, + const char* docstring, + int slots) { + char buffer[256]; + snprintf(buffer, sizeof(buffer), "def %s: pass", sig); + // fn(a, b, *c, d=1) -> None + CodeObject code; + pk_SourceData_ source = pk_SourceData__rcnew(buffer, "", EXEC_MODE, false); + Error* err = pk_compile(source, &code); + if(err || code.func_decls.count != 1) { + c11__abort("py_newfunction(): invalid signature '%s'", sig); + } + FuncDecl_ decl = c11__getitem(FuncDecl_, &code.func_decls, 0); + decl->docstring = docstring; + // construct the function + Function* ud = py_newobject(out, tp_function, slots, sizeof(Function)); + Function__ctor(ud, decl, NULL); + ud->cfunc = f; + CodeObject__dtor(&code); + PK_DECREF(source); + assert(decl->rc.count == 1); + return py_name(ud->decl->code.name->data); +} + void* py_newobject(py_Ref out, py_Type type, int slots, int udsize) { pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = pk_ManagedHeap__gcnew(heap, type, slots, udsize); diff --git a/src2/main.c b/src2/main.c index fe96049a..ef8b91a5 100644 --- a/src2/main.c +++ b/src2/main.c @@ -49,13 +49,13 @@ int main(int argc, char** argv) { int size = py_replinput(buf); assert(size < sizeof(buf)); if(size >= 0) { - if(!py_exec2(buf, "", REPL_MODE)) py_printexc(); + if(!py_exec(buf, "", REPL_MODE, NULL)) py_printexc(); } } } else { char* source = read_file(argv[1]); if(source) { - if(!py_exec(source)) py_printexc(); + if(!py_exec(source, argv[1], EXEC_MODE, NULL)) py_printexc(); free(source); } }