diff --git a/README.md b/README.md index 493e93ab792..615fb260e3c 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ For C/C++ developers, you can download the `pocketpy.h` on our GitHub release pa https://github.com/blueloveTH/pocketpy/releases/latest -Check [C-API](https://pocketpy.dev/c-api/vm/) for references. +Check [C-API](https://pocketpy.dev/c-api/vm/) for references. C++ APIs will be available soon. ```cpp #include "pocketpy.h" @@ -139,6 +139,7 @@ You can download `artifact.zip` from [Github Release](https://github.com/bluelov - linux/ - x86_64/ - pocketpy + - pocketpy.so - macos/ - pocketpy.bundle/ - web/ diff --git a/README_zh.md b/README_zh.md index 3bc41985849..47a4e73c217 100644 --- a/README_zh.md +++ b/README_zh.md @@ -132,6 +132,7 @@ flutter pub add pocketpy - linux/ - x86_64/ - pocketpy + - pocketpy.so - macos/ - pocketpy.bundle/ - web/ diff --git a/src/common.h b/src/common.h index 5a40093195a..d70415f2553 100644 --- a/src/common.h +++ b/src/common.h @@ -35,10 +35,11 @@ #include #endif -#define PK_VERSION "0.8.1" +#define PK_VERSION "0.8.2" typedef int64_t i64; typedef double f64; #define DUMMY_VAL (i64)0 -#define CPP_LAMBDA(x) ([](VM* vm, const pkpy::Args& args) { return x; }) \ No newline at end of file +#define CPP_LAMBDA(x) ([](VM* vm, const pkpy::Args& args) { return x; }) +#define CPP_NOT_IMPLEMENTED() ([](VM* vm, const pkpy::Args& args) { vm->notImplementedError(); return vm->None; }) \ No newline at end of file diff --git a/src/iter.h b/src/iter.h index da08f10b4d1..86889c6d818 100644 --- a/src/iter.h +++ b/src/iter.h @@ -13,11 +13,7 @@ class RangeIterator : public BaseIterator { } bool hasNext() override { - if(r.step > 0){ - return current < r.stop; - }else{ - return current > r.stop; - } + return r.step > 0 ? current < r.stop : current > r.stop; } PyVar next() override; @@ -32,13 +28,8 @@ class VectorIterator : public BaseIterator { vec = &OBJ_GET(PyVarList, _ref); } - bool hasNext(){ - return index < vec->size(); - } - - PyVar next(){ - return vec->operator[](index++); - } + bool hasNext(){ return index < vec->size(); } + PyVar next(){ return vec->operator[](index++); } }; class StringIterator : public BaseIterator { @@ -50,9 +41,6 @@ class StringIterator : public BaseIterator { str = OBJ_GET(_Str, _ref); } - bool hasNext(){ - return index < str.u8_length(); - } - + bool hasNext(){ return index < str.u8_length(); } PyVar next(); }; diff --git a/src/obj.h b/src/obj.h index 26adf66d71f..175dd2b0a9d 100644 --- a/src/obj.h +++ b/src/obj.h @@ -93,7 +93,13 @@ struct Py_ : PyObject { virtual void* value() override { return &_value; } }; -//#define OBJ_GET(T, obj) (((Py_*)((obj).get()))->_value) +// Unsafe cast from PyObject to C++ type #define OBJ_GET(T, obj) (*static_cast((obj)->value())) #define OBJ_NAME(obj) OBJ_GET(_Str, (obj)->attribs[__name__]) -#define OBJ_TP_NAME(obj) OBJ_GET(_Str, (obj)->type->attribs[__name__]) \ No newline at end of file +#define OBJ_TP_NAME(obj) OBJ_GET(_Str, (obj)->type->attribs[__name__]) + +#define PY_CLASS(mod, name) \ + inline static PyVar _type(VM* vm) { return vm->_modules[#mod]->attribs[#name]; } \ + inline static const char* _name() { return #name; } + +#define PY_BUILTIN_CLASS(name) inline static PyVar _type(VM* vm) { return vm->_tp_##name; } \ No newline at end of file diff --git a/src/pocketpy.h b/src/pocketpy.h index 36fada6917b..cf757c41192 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -573,8 +573,6 @@ void __add_module_dis(VM* vm){ }); } -#define PY_CLASS(mod, name) inline static PyVar _tp(VM* vm) { return vm->_modules[#mod]->attribs[#name]; } - struct ReMatch { PY_CLASS(re, Match) @@ -583,27 +581,22 @@ struct ReMatch { std::smatch m; ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {} - static PyVar _register(VM* vm, PyVar mod){ - PyVar _tp_match = vm->new_user_type_object(mod, "Match", vm->_tp_object); - vm->bindMethod<-1>(_tp_match, "__init__", [](VM* vm, const pkpy::Args& args){ - vm->notImplementedError(); - return vm->None; - }); - vm->bindMethod<0>(_tp_match, "start", CPP_LAMBDA(vm->PyInt(OBJ_GET(ReMatch, args[0]).start))); - vm->bindMethod<0>(_tp_match, "end", CPP_LAMBDA(vm->PyInt(OBJ_GET(ReMatch, args[0]).end))); + static void _register(VM* vm, PyVar mod, PyVar type){ + vm->bindMethod<-1>(type, "__init__", CPP_NOT_IMPLEMENTED()); + vm->bindMethod<0>(type, "start", CPP_LAMBDA(vm->PyInt(vm->py_cast(args[0]).start))); + vm->bindMethod<0>(type, "end", CPP_LAMBDA(vm->PyInt(vm->py_cast(args[0]).end))); - vm->bindMethod<0>(_tp_match, "span", [](VM* vm, const pkpy::Args& args) { - auto& self = OBJ_GET(ReMatch, args[0]); + vm->bindMethod<0>(type, "span", [](VM* vm, const pkpy::Args& args) { + auto& self = vm->py_cast(args[0]); return vm->PyTuple({ vm->PyInt(self.start), vm->PyInt(self.end) }); }); - vm->bindMethod<1>(_tp_match, "group", [](VM* vm, const pkpy::Args& args) { - auto& self = OBJ_GET(ReMatch, args[0]); + vm->bindMethod<1>(type, "group", [](VM* vm, const pkpy::Args& args) { + auto& self = vm->py_cast(args[0]); int index = (int)vm->PyInt_AS_C(args[1]); index = vm->normalized_index(index, self.m.size()); return vm->PyStr(self.m[index].str()); }); - return _tp_match; } }; @@ -614,14 +607,14 @@ PyVar __regex_search(const _Str& pattern, const _Str& string, bool fromStart, VM if(fromStart && m.position() != 0) return vm->None; i64 start = string.__to_u8_index(m.position()); i64 end = string.__to_u8_index(m.position() + m.length()); - return vm->new_object_c(start, end, m); + return vm->new_object(start, end, m); } return vm->None; }; void __add_module_re(VM* vm){ PyVar mod = vm->new_module("re"); - ReMatch::_register(vm, mod); + vm->register_class(mod); vm->bindFunc<2>(mod, "match", [](VM* vm, const pkpy::Args& args) { const _Str& pattern = vm->PyStr_AS_C(args[0]); @@ -827,7 +820,7 @@ extern "C" { for(int i=0; mod[i]; i++) if(mod[i] == ' ') return nullptr; for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr; std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++); - PyVar obj = vm->new_module_if_not_existed(mod); + PyVar obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod); vm->bindFunc<-1>(obj, name, [ret_code, f_header](VM* vm, const pkpy::Args& args){ _StrStream ss; ss << f_header; diff --git a/src/vm.h b/src/vm.h index 93f8dc5144c..ad3014e6fb5 100644 --- a/src/vm.h +++ b/src/vm.h @@ -613,23 +613,17 @@ class VM { } template - inline PyVar new_object_c(Args&&... args) { - return new_object(T::_tp(this), T(std::forward(args)...)); + inline PyVar new_object(Args&&... args) { + return new_object(T::_type(this), T(std::forward(args)...)); } - PyVar new_module(_Str name) { + PyVar new_module(const _Str& name) { PyVar obj = new_object(_tp_module, DUMMY_VAL); setattr(obj, __name__, PyStr(name)); _modules[name] = obj; return obj; } - PyVar new_module_if_not_existed(_Str name) { - PyVar* it = _modules.try_get(name); - if(it != nullptr) return *it; - return new_module(name); - } - PyVarOrNull getattr(const PyVar& obj, const _Str& name, bool throw_err=true) { PyVarDict::iterator it; PyObject* cls; @@ -944,6 +938,19 @@ class VM { if(!obj->is_type(type)) typeError("expected '" + OBJ_NAME(type) + "', but got '" + OBJ_TP_NAME(obj) + "'"); } + template + PyVar register_class(PyVar mod){ + PyVar type = new_user_type_object(mod, T::_name(), _tp_object); + T::_register(this, mod, type); + return type; + } + + template + T& py_cast(const PyVar& obj){ + check_type(obj, T::_type(this)); + return OBJ_GET(T, obj); + } + ~VM() { if(!use_stdio){ delete _stdout; diff --git a/test_cpp.sh b/test_cpp.sh deleted file mode 100644 index a63e19cb896..00000000000 --- a/test_cpp.sh +++ /dev/null @@ -1,7 +0,0 @@ -g++ -o pocketpy src/main.cpp --std=c++17 -pg -O1 -fno-rtti - -./pocketpy tests/1.py - -gprof pocketpy gmon.out > gprof.txt - -rm gmon.out \ No newline at end of file