From bb2711257512dd22799f1bef608f51663a4bf9ca Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 3 May 2024 20:54:18 +0800 Subject: [PATCH] some refactor --- docs/quick-start/installation.md | 4 +- include/pocketpy/vm.h | 204 +++++++++++++++---------------- src/ceval.cpp | 2 +- src/pocketpy.cpp | 2 +- src/vm.cpp | 14 +-- 5 files changed, 110 insertions(+), 116 deletions(-) diff --git a/docs/quick-start/installation.md b/docs/quick-start/installation.md index f92e48a1..5ec74473 100644 --- a/docs/quick-start/installation.md +++ b/docs/quick-start/installation.md @@ -149,10 +149,10 @@ delete vm; By default, pkpy outputs all messages and errors to `stdout` and `stderr`. You can redirect them to your own buffer by setting `vm->_stdout` and `vm->_stderr`. -These two fields are C function pointers `PrintFunc` with the following signature: +These two fields are C function pointers with the following signature: ```cpp -typedef void(*PrintFunc)(const char*, int) +void(*)(const char*, int); ``` Or you can override these two virtual functions: diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index b6f9e38d..d43373a2 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -98,7 +98,32 @@ struct PyTypeInfo{ void (*on_end_subclass)(VM* vm, PyTypeInfo*) = nullptr; }; -typedef void(*PrintFunc)(const char*, int); +struct ImportContext{ + PK_ALWAYS_PASS_BY_POINTER(ImportContext) + + std::vector pending; + std::vector pending_is_init; // a.k.a __init__.py + + ImportContext() {} + + struct Temp{ + PK_ALWAYS_PASS_BY_POINTER(Temp) + + ImportContext* ctx; + Temp(ImportContext* ctx, Str name, bool is_init) : ctx(ctx){ + ctx->pending.push_back(name); + ctx->pending_is_init.push_back(is_init); + } + ~Temp(){ + ctx->pending.pop_back(); + ctx->pending_is_init.pop_back(); + } + }; + + Temp scope(Str name, bool is_init){ + return {this, name, is_init}; + } +}; class VM { PK_ALWAYS_PASS_BY_POINTER(VM) @@ -129,12 +154,13 @@ public: // typeid -> Type std::map _cxx_typeid_map; - // this is for repr() recursion detection (no need to mark) std::set _repr_recursion_set; - PyObject* __last_exception; // last exception - PyObject* __curr_class; // current class being defined + ImportContext __import_context; // for import + PyObject* __last_exception; // last exception + PyObject* __curr_class; // current class being defined + PyObject* __cached_object_new; std::map __cached_codes; void (*_ceval_on_step)(VM*, Frame*, Bytecode bc) = nullptr; @@ -144,8 +170,8 @@ public: NextBreakpoint _next_breakpoint; #endif - PrintFunc _stdout; - PrintFunc _stderr; + void(*_stdout)(const char*, int); + void(*_stderr)(const char*, int); unsigned char* (*_import_handler)(const char*, int, int*); // for quick access @@ -159,28 +185,50 @@ public: static constexpr Type tp_dict=18, tp_property=19, tp_star_wrapper=20; static constexpr Type tp_staticmethod=21, tp_classmethod=22; - PyObject* cached_object__new__; - const bool enable_os; - VM(bool enable_os=true); - void set_main_argv(int argc, char** argv); - + /********** py_xxx **********/ PyObject* py_str(PyObject* obj); PyObject* py_repr(PyObject* obj); PyObject* py_json(PyObject* obj); PyObject* py_iter(PyObject* obj); + PyObject* py_next(PyObject*); + PyObject* _py_next(const PyTypeInfo*, PyObject*); + PyObject* py_import(Str path, bool throw_err=true); + PyObject* py_negate(PyObject* obj); + PyObject* py_list(PyObject*); + bool py_callable(PyObject* obj); + bool py_bool(PyObject* obj); + i64 py_hash(PyObject* obj); + + bool py_eq(PyObject* lhs, PyObject* rhs); + // new in v1.2.9 + bool py_lt(PyObject* lhs, PyObject* rhs); + bool py_le(PyObject* lhs, PyObject* rhs); + bool py_gt(PyObject* lhs, PyObject* rhs); + bool py_ge(PyObject* lhs, PyObject* rhs); + bool py_ne(PyObject* lhs, PyObject* rhs) { return !py_eq(lhs, rhs); } + + /********** utils **********/ + PyObject* new_module(Str name, Str package=""); ArgsView _cast_array_view(PyObject* obj); + void set_main_argv(int argc, char** argv); + i64 normalized_index(i64 index, int size); + Str disassemble(CodeObject_ co); + void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step); + /********** name lookup **********/ PyObject* find_name_in_mro(Type cls, StrName name); - bool isinstance(PyObject* obj, Type base); - bool issubclass(Type cls, Type base); + PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true); + void delattr(PyObject* obj, StrName name); + PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err=true, bool fallback=false); + void setattr(PyObject* obj, StrName name, PyObject* value); + /********** execution **********/ CodeObject_ compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false); Str precompile(std::string_view source, const Str& filename, CompileMode mode); - PyObject* exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module=nullptr); PyObject* exec(std::string_view source); PyObject* eval(std::string_view source); @@ -191,19 +239,8 @@ public: return __run_top_frame(); } - void __push_varargs(){} - void __push_varargs(PyObject* _0){ PUSH(_0); } - void __push_varargs(PyObject* _0, PyObject* _1){ PUSH(_0); PUSH(_1); } - void __push_varargs(PyObject* _0, PyObject* _1, PyObject* _2){ PUSH(_0); PUSH(_1); PUSH(_2); } - void __push_varargs(PyObject* _0, PyObject* _1, PyObject* _2, PyObject* _3){ PUSH(_0); PUSH(_1); PUSH(_2); PUSH(_3); } - - virtual void stdout_write(const Str& s){ - _stdout(s.data, s.size); - } - - virtual void stderr_write(const Str& s){ - _stderr(s.data, s.size); - } + /********** invocation **********/ + PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false); template PyObject* call(PyObject* callable, Args&&... args){ @@ -227,9 +264,11 @@ public: return call_method(self, callable, args...); } - PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true); - const PyTypeInfo* _inst_type_info(PyObject* obj); + /********** io **********/ + virtual void stdout_write(const Str& s){ _stdout(s.data, s.size); } + virtual void stderr_write(const Str& s){ _stderr(s.data, s.size); } + /********** bindings **********/ void bind__repr__(Type type, PyObject* (*f)(VM*, PyObject*)); void bind__str__(Type type, PyObject* (*f)(VM*, PyObject*)); void bind__iter__(Type type, PyObject* (*f)(VM*, PyObject*)); @@ -266,13 +305,16 @@ public: void bind__setitem__(Type type, void (*f)(VM*, PyObject*, PyObject*, PyObject*)); void bind__delitem__(Type type, void (*f)(VM*, PyObject*, PyObject*)); - bool py_eq(PyObject* lhs, PyObject* rhs); - // new in v1.2.9 - bool py_lt(PyObject* lhs, PyObject* rhs); - bool py_le(PyObject* lhs, PyObject* rhs); - bool py_gt(PyObject* lhs, PyObject* rhs); - bool py_ge(PyObject* lhs, PyObject* rhs); - bool py_ne(PyObject* lhs, PyObject* rhs) { return !py_eq(lhs, rhs); } + template + PyObject* bind_method(Type, StrName, NativeFuncC); + template + PyObject* bind_method(PyObject*, StrName, NativeFuncC); + template + PyObject* bind_func(PyObject*, StrName, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); + // new style binding api + PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); + PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); + PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr); template PyObject* bind_constructor(__T&& type, NativeFuncC fn) { @@ -287,16 +329,8 @@ public: return vm->None; }); } - - i64 normalized_index(i64 index, int size); - PyObject* py_next(PyObject*); - PyObject* _py_next(const PyTypeInfo*, PyObject*); - PyObject* __pack_next_retval(unsigned); - bool py_callable(PyObject* obj); - - PyObject* __minmax_reduce(bool (VM::*op)(PyObject*, PyObject*), PyObject* args, PyObject* key); - - /***** Error Reporter *****/ + /********** error **********/ + void _error(PyObject*); void StackOverflowError() { __builtin_error("StackOverflowError"); } void IOError(const Str& msg) { __builtin_error("IOError", msg); } void NotImplementedError(){ __builtin_error("NotImplementedError"); } @@ -317,6 +351,13 @@ public: void AttributeError(PyObject* obj, StrName name); void AttributeError(const Str& msg){ __builtin_error("AttributeError", msg); } + /********** type **********/ + PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true); + + const PyTypeInfo* _inst_type_info(PyObject* obj); + bool isinstance(PyObject* obj, Type base); + bool issubclass(Type cls, Type base); + void check_type(PyObject* obj, Type type){ if(is_type(obj, type)) return; TypeError("expected " + _type_name(vm, type).escape() + ", got " + _type_name(vm, _tp(obj)).escape()); @@ -340,64 +381,7 @@ public: return _all_types[_tp(obj).index].obj; } - struct ImportContext{ - PK_ALWAYS_PASS_BY_POINTER(ImportContext) - - std::vector pending; - std::vector pending_is_init; // a.k.a __init__.py - - ImportContext() {} - - struct Temp{ - PK_ALWAYS_PASS_BY_POINTER(Temp) - - ImportContext* ctx; - Temp(ImportContext* ctx, Str name, bool is_init) : ctx(ctx){ - ctx->pending.push_back(name); - ctx->pending_is_init.push_back(is_init); - } - ~Temp(){ - ctx->pending.pop_back(); - ctx->pending_is_init.pop_back(); - } - }; - - Temp scope(Str name, bool is_init){ - return {this, name, is_init}; - } - }; - - ImportContext _import_context; - PyObject* py_import(Str path, bool throw_err=true); - -#if PK_DEBUG_CEVAL_STEP - void _log_s_data(const char* title = nullptr); -#endif - PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false); - PyObject* py_negate(PyObject* obj); - bool py_bool(PyObject* obj); - i64 py_hash(PyObject* obj); - PyObject* py_list(PyObject*); - PyObject* new_module(Str name, Str package=""); - Str disassemble(CodeObject_ co); - PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true); - void delattr(PyObject* obj, StrName name); - PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err=true, bool fallback=false); - void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step); - void setattr(PyObject* obj, StrName name, PyObject* value); - template - PyObject* bind_method(Type, StrName, NativeFuncC); - template - PyObject* bind_method(PyObject*, StrName, NativeFuncC); - template - PyObject* bind_func(PyObject*, StrName, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); - void _error(PyObject*); - - // new style binding api - PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); - PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); - PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr); - + /********** user type **********/ template PyObject* register_user_class(PyObject* mod, StrName name, bool subclass_enabled=false){ PyObject* type = new_type_object(mod, name, 0, subclass_enabled); @@ -439,7 +423,10 @@ public: virtual ~VM(); - /***** Private *****/ + /********** private **********/ +#if PK_DEBUG_CEVAL_STEP + void __log_s_data(const char* title = nullptr); +#endif void __breakpoint(); PyObject* __format_object(PyObject*, Str); PyObject* __run_top_frame(); @@ -455,6 +442,13 @@ public: void __builtin_error(StrName type); void __builtin_error(StrName type, PyObject* arg); void __builtin_error(StrName type, const Str& msg); + void __push_varargs(){} + void __push_varargs(PyObject* _0){ PUSH(_0); } + void __push_varargs(PyObject* _0, PyObject* _1){ PUSH(_0); PUSH(_1); } + void __push_varargs(PyObject* _0, PyObject* _1, PyObject* _2){ PUSH(_0); PUSH(_1); PUSH(_2); } + void __push_varargs(PyObject* _0, PyObject* _1, PyObject* _2, PyObject* _3){ PUSH(_0); PUSH(_1); PUSH(_2); PUSH(_3); } + PyObject* __pack_next_retval(unsigned); + PyObject* __minmax_reduce(bool (VM::*op)(PyObject*, PyObject*), PyObject* args, PyObject* key); }; diff --git a/src/ceval.cpp b/src/ceval.cpp index 239eda44..5361e024 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -118,7 +118,7 @@ __NEXT_FRAME: __NEXT_STEP:; #if PK_DEBUG_CEVAL_STEP - _log_s_data(); + __log_s_data(); #endif switch ((Opcode)byte.op) { diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index d03db3f1..c38a6ff5 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -356,7 +356,7 @@ void init_builtins(VM* _vm) { return VAR(_0 == _1); }); - _vm->cached_object__new__ = _vm->bind_constructor<1>(_vm->_t(VM::tp_object), [](VM* vm, ArgsView args) { + _vm->__cached_object_new = _vm->bind_constructor<1>(_vm->_t(VM::tp_object), [](VM* vm, ArgsView args) { vm->check_type(args[0], vm->tp_type); Type t = PK_OBJ_GET(Type, args[0]); return vm->heap.gcnew(t); diff --git a/src/vm.cpp b/src/vm.cpp index af180780..be47c34d 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -319,11 +319,11 @@ namespace pkpy{ }; if(path[0] == '.'){ - if(_import_context.pending.empty()){ + if(__import_context.pending.empty()){ ImportError("relative import outside of package"); } - Str curr_path = _import_context.pending.back(); - bool curr_is_init = _import_context.pending_is_init.back(); + Str curr_path = __import_context.pending.back(); + bool curr_is_init = __import_context.pending_is_init.back(); // convert relative path to absolute path pod_vector cpnts = curr_path.split('.'); int prefix = 0; // how many dots in the prefix @@ -347,7 +347,7 @@ namespace pkpy{ pod_vector path_cpnts = path.split('.'); // check circular import - if(_import_context.pending.size() > 128){ + if(__import_context.pending.size() > 128){ ImportError("maximum recursion depth exceeded while importing"); } @@ -375,7 +375,7 @@ namespace pkpy{ source = it->second; _lazy_modules.erase(it); } - auto _ = _import_context.scope(path, is_init); + auto _ = __import_context.scope(path, is_init); CodeObject_ code = compile(source, filename, EXEC_MODE); Str name_cpnt = path_cpnts.back(); @@ -684,7 +684,7 @@ Str VM::disassemble(CodeObject_ co){ } #if PK_DEBUG_CEVAL_STEP -void VM::_log_s_data(const char* title) { +void VM::__log_s_data(const char* title) { if(_main == nullptr) return; if(callstack.empty()) return; SStream ss; @@ -1002,7 +1002,7 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){ PyObject* new_f = find_name_in_mro(PK_OBJ_GET(Type, callable), __new__); PyObject* obj; PK_DEBUG_ASSERT(new_f != nullptr && !method_call); - if(new_f == cached_object__new__) { + if(new_f == __cached_object_new) { // fast path for object.__new__ obj = vm->heap.gcnew(PK_OBJ_GET(Type, callable)); }else{