diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f9bc8291..b91004f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,157 +1,157 @@ -name: build -on: - push: - paths-ignore: - - 'docs/**' - - 'web/**' - - '**.md' - pull_request: - paths-ignore: - - 'docs/**' - - 'web/**' - - '**.md' -jobs: - build_win32_amalgamated: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - uses: ilammy/msvc-dev-cmd@v1 - - name: Compile - shell: powershell - run: | - python amalgamate.py - cd amalgamated - cl.exe /std:c++17 /EHsc /utf-8 /Ox /I. /DPK_ENABLE_OS=1 main.cpp /link /out:pkpy.exe - - uses: actions/upload-artifact@v3 - with: - path: amalgamated/pkpy.exe - build_win32: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - uses: ilammy/msvc-dev-cmd@v1 - - name: Compile - shell: bash - run: | - mkdir -p output/windows/x86_64 - python cmake_build.py - cp main.exe output/windows/x86_64 - cp pocketpy.dll output/windows/x86_64 - - uses: actions/upload-artifact@v3 - with: - path: output - - name: Unit Test - run: python scripts/run_tests.py - - name: Benchmark - run: python scripts/run_tests.py benchmark - build_linux: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v4 - - name: Setup Clang - uses: egor-tensin/setup-clang@v1 - with: - version: 15 - platform: x64 - - name: Install libc++ - run: sudo apt-get install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev - - name: Unit Test with Coverage - run: bash run_tests.sh - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: .coverage - if: github.ref == 'refs/heads/main' - - name: Compile - run: | - mkdir -p output/linux/x86_64 - python cmake_build.py - cp main output/linux/x86_64 - cp libpocketpy.so output/linux/x86_64 - env: - CXX: clang++ - CC: clang - - uses: actions/upload-artifact@v3 - with: - path: output - - name: Benchmark - run: python scripts/run_tests.py benchmark - - name: C Binding Test - run: bash run_c_binding_test.sh - build_linux_x86: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Setup Alpine Linux for aarch64 - uses: jirutka/setup-alpine@v1 - with: - arch: x86 - packages: gcc g++ make cmake libc-dev linux-headers python3 - - name: Build and Test - run: | - uname -m - python cmake_build.py - python scripts/run_tests.py - python scripts/run_tests.py benchmark - shell: alpine.sh --root {0} - build_darwin: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Compile and Test - run: | - python cmake_build.py - python scripts/run_tests.py - - name: Benchmark - run: python scripts/run_tests.py benchmark - - run: | - python amalgamate.py - cd plugins/macos/pocketpy - mkdir -p output/macos - xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO - cp -r build/Release/pocketpy.bundle output/macos - - uses: actions/upload-artifact@v3 - with: - path: plugins/macos/pocketpy/output - build_android: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: nttld/setup-ndk@v1 - id: setup-ndk - with: - ndk-version: r23 - local-cache: false - add-to-path: false - - name: Compile Shared Library - run: | - bash build_android.sh arm64-v8a - bash build_android.sh armeabi-v7a - bash build_android.sh x86_64 +# name: build +# on: +# push: +# paths-ignore: +# - 'docs/**' +# - 'web/**' +# - '**.md' +# pull_request: +# paths-ignore: +# - 'docs/**' +# - 'web/**' +# - '**.md' +# jobs: +# build_win32_amalgamated: +# runs-on: windows-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: ilammy/msvc-dev-cmd@v1 +# - name: Compile +# shell: powershell +# run: | +# python amalgamate.py +# cd amalgamated +# cl.exe /std:c++17 /EHsc /utf-8 /Ox /I. /DPK_ENABLE_OS=1 main.cpp /link /out:pkpy.exe +# - uses: actions/upload-artifact@v3 +# with: +# path: amalgamated/pkpy.exe +# build_win32: +# runs-on: windows-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: ilammy/msvc-dev-cmd@v1 +# - name: Compile +# shell: bash +# run: | +# mkdir -p output/windows/x86_64 +# python cmake_build.py +# cp main.exe output/windows/x86_64 +# cp pocketpy.dll output/windows/x86_64 +# - uses: actions/upload-artifact@v3 +# with: +# path: output +# - name: Unit Test +# run: python scripts/run_tests.py +# - name: Benchmark +# run: python scripts/run_tests.py benchmark +# build_linux: +# runs-on: ubuntu-20.04 +# steps: +# - uses: actions/checkout@v4 +# - name: Setup Clang +# uses: egor-tensin/setup-clang@v1 +# with: +# version: 15 +# platform: x64 +# - name: Install libc++ +# run: sudo apt-get install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev +# - name: Unit Test with Coverage +# run: bash run_tests.sh +# - name: Upload coverage reports to Codecov +# uses: codecov/codecov-action@v4 +# with: +# token: ${{ secrets.CODECOV_TOKEN }} +# directory: .coverage +# if: github.ref == 'refs/heads/main' +# - name: Compile +# run: | +# mkdir -p output/linux/x86_64 +# python cmake_build.py +# cp main output/linux/x86_64 +# cp libpocketpy.so output/linux/x86_64 +# env: +# CXX: clang++ +# CC: clang +# - uses: actions/upload-artifact@v3 +# with: +# path: output +# - name: Benchmark +# run: python scripts/run_tests.py benchmark +# - name: C Binding Test +# run: bash run_c_binding_test.sh +# build_linux_x86: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# - name: Setup Alpine Linux for aarch64 +# uses: jirutka/setup-alpine@v1 +# with: +# arch: x86 +# packages: gcc g++ make cmake libc-dev linux-headers python3 +# - name: Build and Test +# run: | +# uname -m +# python cmake_build.py +# python scripts/run_tests.py +# python scripts/run_tests.py benchmark +# shell: alpine.sh --root {0} +# build_darwin: +# runs-on: macos-latest +# steps: +# - uses: actions/checkout@v4 +# - name: Compile and Test +# run: | +# python cmake_build.py +# python scripts/run_tests.py +# - name: Benchmark +# run: python scripts/run_tests.py benchmark +# - run: | +# python amalgamate.py +# cd plugins/macos/pocketpy +# mkdir -p output/macos +# xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO +# cp -r build/Release/pocketpy.bundle output/macos +# - uses: actions/upload-artifact@v3 +# with: +# path: plugins/macos/pocketpy/output +# build_android: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: nttld/setup-ndk@v1 +# id: setup-ndk +# with: +# ndk-version: r23 +# local-cache: false +# add-to-path: false +# - name: Compile Shared Library +# run: | +# bash build_android.sh arm64-v8a +# bash build_android.sh armeabi-v7a +# bash build_android.sh x86_64 - mkdir -p output/android/arm64-v8a - mkdir -p output/android/armeabi-v7a - mkdir -p output/android/x86_64 +# mkdir -p output/android/arm64-v8a +# mkdir -p output/android/armeabi-v7a +# mkdir -p output/android/x86_64 - cp build/android/arm64-v8a/libpocketpy.so output/android/arm64-v8a - cp build/android/armeabi-v7a/libpocketpy.so output/android/armeabi-v7a - cp build/android/x86_64/libpocketpy.so output/android/x86_64 - env: - ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} - - uses: actions/upload-artifact@v3 - with: - path: output - build_ios: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - name: Compile Frameworks - run: | - git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake - bash build_ios.sh - mkdir -p output/ios - cp -r build/pocketpy.xcframework output/ios/pocketpy.xcframework - - uses: actions/upload-artifact@v3 - with: - path: output +# cp build/android/arm64-v8a/libpocketpy.so output/android/arm64-v8a +# cp build/android/armeabi-v7a/libpocketpy.so output/android/armeabi-v7a +# cp build/android/x86_64/libpocketpy.so output/android/x86_64 +# env: +# ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} +# - uses: actions/upload-artifact@v3 +# with: +# path: output +# build_ios: +# runs-on: macos-latest +# steps: +# - uses: actions/checkout@v4 +# - name: Compile Frameworks +# run: | +# git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake +# bash build_ios.sh +# mkdir -p output/ios +# cp -r build/pocketpy.xcframework output/ios/pocketpy.xcframework +# - uses: actions/upload-artifact@v3 +# with: +# path: output diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 7d80a048..ac8c79b2 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -1,42 +1,42 @@ -name: website +# name: website -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] +# on: +# push: +# branches: [ main ] +# pull_request: +# branches: [ main ] -permissions: - contents: write +# permissions: +# contents: write -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - ################################################### - - uses: actions/setup-node@v3.1.1 - - name: Retype build - run: | - python scripts/build_references.py - cd docs - npm install retypeapp --global - retype build - ################################################### - - name: Setup emsdk - uses: mymindstorm/setup-emsdk@v12 - with: - version: 3.1.25 - actions-cache-folder: 'emsdk-cache' - - name: Compile - run: | - bash build_web.sh - mv web docs/.retype/static - ################################################### - - uses: crazy-max/ghaction-github-pages@v3 - with: - target_branch: gh-pages - build_dir: docs/.retype - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: github.ref == 'refs/heads/main' +# jobs: +# deploy: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# ################################################### +# - uses: actions/setup-node@v3.1.1 +# - name: Retype build +# run: | +# python scripts/build_references.py +# cd docs +# npm install retypeapp --global +# retype build +# ################################################### +# - name: Setup emsdk +# uses: mymindstorm/setup-emsdk@v12 +# with: +# version: 3.1.25 +# actions-cache-folder: 'emsdk-cache' +# - name: Compile +# run: | +# bash build_web.sh +# mv web docs/.retype/static +# ################################################### +# - uses: crazy-max/ghaction-github-pages@v3 +# with: +# target_branch: gh-pages +# build_dir: docs/.retype +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# if: github.ref == 'refs/heads/main' diff --git a/3rd/cjson/src/cJSONw.cpp b/3rd/cjson/src/cJSONw.cpp index 91ff1484..acb36e40 100644 --- a/3rd/cjson/src/cJSONw.cpp +++ b/3rd/cjson/src/cJSONw.cpp @@ -90,7 +90,7 @@ static PyVar convert_cjson_to_python_object(const cJSON * const item, VM* vm) } void add_module_cjson(VM* vm){ - PyVar mod = vm->new_module("cjson"); + PyObject* mod = vm->new_module("cjson"); vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args){ std::string_view sv; diff --git a/3rd/lua_bridge/src/lua_bridge.cpp b/3rd/lua_bridge/src/lua_bridge.cpp index 8a562228..16791862 100644 --- a/3rd/lua_bridge/src/lua_bridge.cpp +++ b/3rd/lua_bridge/src/lua_bridge.cpp @@ -38,8 +38,8 @@ struct PyLuaObject{ }; struct PyLuaTable: PyLuaObject{ - static void _register(VM* vm, PyVar mod, PyVar type){ - Type t = PK_OBJ_GET(Type, type); + static void _register(VM* vm, PyObject* mod, PyObject* type){ + Type t = type->as(); PyTypeInfo* ti = &vm->_all_types[t]; ti->subclass_enabled = false; ti->m__getattr__ = [](VM* vm, PyVar obj, StrName name){ @@ -195,7 +195,7 @@ static PyVar lua_popx_multi_to_python(VM* vm, int count){ } struct PyLuaFunction: PyLuaObject{ - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_func(type, __call__, -1, [](VM* vm, ArgsView args){ if(args.size() < 1) vm->TypeError("__call__ takes at least 1 argument"); const PyLuaFunction& self = _CAST(PyLuaFunction&, args[0]); @@ -320,7 +320,7 @@ PyVar lua_popx_to_python(VM* vm) { } void initialize_lua_bridge(VM* vm, lua_State* newL){ - PyVar mod = vm->new_module("lua"); + PyObject* mod = vm->new_module("lua"); if(_L != nullptr){ throw std::runtime_error("lua bridge already initialized"); diff --git a/docs/1_5_0.md b/docs/1_5_0.md index a516c615..e5f92a5b 100644 --- a/docs/1_5_0.md +++ b/docs/1_5_0.md @@ -46,14 +46,14 @@ struct Point{ int x, y; - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ // do bindings here } }; int main(){ VM* vm = new VM(); - PyVar mod = vm->new_module("test"); + PyObject* mod = vm->new_module("test"); Point::register_class(vm, mod); return 0; } @@ -68,7 +68,7 @@ struct Point{ int main(){ VM* vm = new VM(); - PyVar mod = vm->new_module("test"); + PyObject* mod = vm->new_module("test"); vm->register_user_class(mod, "Point", [](VM* vm, PyVar mod, PyVar type){ // do bindings here @@ -84,14 +84,14 @@ This is achieved by an overloaded version of `vm->register_user_class<>`. For ex struct Point{ int x, y; - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ // do bindings here (if you like the intrusive way) } }; int main(){ VM* vm = new VM(); - PyVar mod = vm->new_module("test"); + PyObject* mod = vm->new_module("test"); vm->register_user_class(mod, "Point"); return 0; } diff --git a/docs/bindings.md b/docs/bindings.md index 68edbff7..257e659e 100644 --- a/docs/bindings.md +++ b/docs/bindings.md @@ -115,7 +115,7 @@ You can create a `test` module and use `vm->register_user_class<>` to bind the c ```cpp int main(){ VM* vm = new VM(); - PyVar mod = vm->new_module("test"); + PyObject* mod = vm->new_module("test"); vm->register_user_class(mod, "Point", [](VM* vm, PyVar mod, PyVar type){ // wrap field x @@ -165,11 +165,11 @@ struct Container{ void _gc_mark(VM* vm) const{ // mark a - if(a) PK_OBJ_MARK(a); + vm->obj_gc_mark(a); // mark elements in b for(PyVar obj : b){ - if(obj) PK_OBJ_MARK(obj); + vm->obj_gc_mark(obj); } } } diff --git a/docs/cheatsheet.md b/docs/cheatsheet.md index e52a93eb..2847c864 100644 --- a/docs/cheatsheet.md +++ b/docs/cheatsheet.md @@ -328,6 +328,6 @@ vm->_lazy_modules["test"] = "pi = 3.14"; Create a native module ```cpp -PyVar mod = vm->new_module("test"); +PyObject* mod = vm->new_module("test"); vm->setattr(mod, "pi", py_var(vm, 3.14)); ``` diff --git a/docs/quick-start/modules.md b/docs/quick-start/modules.md index c622d6aa..241c0a47 100644 --- a/docs/quick-start/modules.md +++ b/docs/quick-start/modules.md @@ -30,7 +30,7 @@ Native modules are always compiled and executed when the VM is created. To creata a native module, use `vm->new_module(Str name)`. ```cpp -PyVar mod = vm->new_module("test"); +PyObject* mod = vm->new_module("test"); mod->attr().set("pi", py_var(vm, 3.14)); vm->bind(mod, "add(a: int, b: int)", diff --git a/include/pocketpy/bindings.h b/include/pocketpy/bindings.h index f765f7f6..f91acea4 100644 --- a/include/pocketpy/bindings.h +++ b/include/pocketpy/bindings.h @@ -63,31 +63,31 @@ inline PyVar __proxy_wrapper(VM* vm, ArgsView args){ } template -PyVar VM::bind(PyVar obj, const char* sig, Ret(*func)(Params...), BindType bt){ +PyObject* VM::bind(PyObject* obj, const char* sig, Ret(*func)(Params...), BindType bt){ NativeProxyFuncCBase* proxy = new NativeProxyFuncC(func); return vm->bind(obj, sig, __proxy_wrapper, proxy, bt); } template -PyVar VM::bind(PyVar obj, const char* sig, Ret(T::*func)(Params...), BindType bt){ +PyObject* VM::bind(PyObject* obj, const char* sig, Ret(T::*func)(Params...), BindType bt){ NativeProxyFuncCBase* proxy = new NativeProxyMethodC(func); return vm->bind(obj, sig, __proxy_wrapper, proxy, bt); } template -PyVar VM::bind(PyVar obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){ +PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){ NativeProxyFuncCBase* proxy = new NativeProxyFuncC(func); return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt); } template -PyVar VM::bind(PyVar obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){ +PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){ NativeProxyFuncCBase* proxy = new NativeProxyMethodC(func); return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt); } template -PyVar VM::bind_field(PyVar obj, const char* name, F T::*field){ +PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){ static_assert(!std::is_reference_v); PK_ASSERT(is_type(obj, tp_type)); std::string_view name_sv(name); int pos = name_sv.find(':'); @@ -108,7 +108,7 @@ PyVar VM::bind_field(PyVar obj, const char* name, F T::*field){ }; _1 = new_object(tp_native_func, fset, 2, field); } - PyVar prop = VAR(Property(_0, _1)); + PyObject* prop = heap.gcnew(tp_property, _0, _1); obj->attr().set(StrName(name_sv), prop); return prop; } @@ -180,7 +180,7 @@ PyVar VM::bind_field(PyVar obj, const char* name, F T::*field){ vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){ \ return VAR(sizeof(wT)); \ }); \ - vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \ + vm->bind__eq__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ \ wT& self = _CAST(wT&, _0); \ if(!vm->isinstance(_1, vm->_tp_user())) return vm->NotImplemented; \ wT& other = _CAST(wT&, _1); \ @@ -188,13 +188,13 @@ PyVar VM::bind_field(PyVar obj, const char* name, F T::*field){ }); \ #define PY_POINTER_SETGETITEM(T) \ - vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \ + vm->bind__getitem__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ \ obj_get_t self = PK_OBJ_GET(VoidP, _0); \ i64 i = CAST(i64, _1); \ T* tgt = reinterpret_cast(self.ptr); \ return VAR(tgt[i]); \ }); \ - vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ \ + vm->bind__setitem__(type->as(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ \ obj_get_t self = PK_OBJ_GET(VoidP, _0); \ i64 i = CAST(i64, _1); \ T* tgt = reinterpret_cast(self.ptr); \ diff --git a/include/pocketpy/cffi.h b/include/pocketpy/cffi.h index 35a8834c..5fec58d5 100644 --- a/include/pocketpy/cffi.h +++ b/include/pocketpy/cffi.h @@ -32,14 +32,14 @@ struct VoidP{ return ss.str(); } - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); }; #define POINTER_VAR(Tp, NAME) \ inline PyVar py_var(VM* vm, Tp val){ \ const static std::pair P("c", NAME); \ PyVar type = vm->_modules[P.first]->attr(P.second); \ - return vm->new_object(PK_OBJ_GET(Type, type), val); \ + return vm->new_object(type->as(), val); \ } POINTER_VAR(char*, "char_p") @@ -84,7 +84,7 @@ struct Struct{ Struct(const Struct& other): Struct(other.p, other.size){} ~Struct(){ if(p!=_inlined) free(p); } - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); }; static_assert(py_sizeof <= 64); diff --git a/include/pocketpy/codeobject.h b/include/pocketpy/codeobject.h index 3d8df164..b4759067 100644 --- a/include/pocketpy/codeobject.h +++ b/include/pocketpy/codeobject.h @@ -145,11 +145,11 @@ struct NativeFunc { struct Function{ FuncDecl_ decl; - PyVar _module; // weak ref - PyVar _class; // weak ref + PyObject* _module; // weak ref + PyObject* _class; // weak ref NameDict_ _closure; - explicit Function(FuncDecl_ decl, PyVar _module, PyVar _class, NameDict_ _closure): + explicit Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict_ _closure): decl(decl), _module(_module), _class(_class), _closure(_closure) {} void _gc_mark(VM*) const; diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index 72be5ca7..302f5456 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -89,7 +89,6 @@ using f64 = double; // always 64-bit static_assert(sizeof(i64) == 8); -struct Dummy { }; // for special objects: True, False, None, Ellipsis, etc. struct DummyInstance { }; struct DummyModule { }; struct NoReturn { }; @@ -104,9 +103,9 @@ struct Type { constexpr operator int() const { return index; } }; -#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) { return x; }) -#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) { return VAR(x); }) -#define PK_ACTION(x) ([](VM* vm, ArgsView args) { x; return vm->None; }) +#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return x; }) +#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); }) +#define PK_ACTION(x) ([](VM* vm, ArgsView args) -> PyVar { x; return vm->None; }) #define PK_REGION(name) 1 @@ -190,6 +189,9 @@ struct PyVar final{ // uninitialized PyVar() = default; + // implict conversion + PyVar(PyObject* p); + /* We must initialize all members to allow == operator to work correctly */ // constexpr initialized constexpr PyVar(const const_sso_var&, Type type, int value): type(type), is_ptr(false), flags(0), _0(value), _1(0) {} diff --git a/include/pocketpy/error.h b/include/pocketpy/error.h index c2be6a2e..4127b986 100644 --- a/include/pocketpy/error.h +++ b/include/pocketpy/error.h @@ -69,12 +69,12 @@ struct Exception { int _ip_on_error; void* _code_on_error; - PyVar _self; // weak reference + PyObject* _self; // weak reference stack stacktrace; Exception(StrName type): type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {} - PyVar self() const{ + PyObject* self() const{ PK_ASSERT(_self != nullptr); return _self; } diff --git a/include/pocketpy/expr.h b/include/pocketpy/expr.h index b8e064ea..d85d6a47 100644 --- a/include/pocketpy/expr.h +++ b/include/pocketpy/expr.h @@ -106,7 +106,7 @@ struct CodeEmitContext{ bool is_compiling_class = false; std::map _co_consts_nonstring_dedup_map; - std::map> _co_consts_string_dedup_map; + std::map _co_consts_string_dedup_map; int get_loop() const; CodeBlock* enter_block(CodeBlockType type); diff --git a/include/pocketpy/frame.h b/include/pocketpy/frame.h index 7dcdc6d2..4e3a2e5e 100644 --- a/include/pocketpy/frame.h +++ b/include/pocketpy/frame.h @@ -29,6 +29,8 @@ struct FastLocals{ }; struct ValueStack { + PK_ALWAYS_PASS_BY_POINTER(ValueStack) + // We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`. PyVar _begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE/128]; PyVar* _sp; @@ -65,14 +67,6 @@ struct ValueStack { new(_sp) PyVar(std::forward(args)...); ++_sp; } - - PyVar operator[](int i) const { return _begin[i]; } - PyVar& operator[](int i) { return _begin[i]; } - - ValueStack(const ValueStack&) = delete; - ValueStack(ValueStack&&) = delete; - ValueStack& operator=(const ValueStack&) = delete; - ValueStack& operator=(ValueStack&&) = delete; }; struct UnwindTarget{ @@ -91,27 +85,27 @@ struct Frame { PyVar* _sp_base; const CodeObject* co; - PyVar _module; - PyVar _callable; // a function object or nullptr (global scope) + PyObject* _module; + PyObject* _callable; // a function object or nullptr (global scope) FastLocals _locals; // This list will be freed in __pop_frame UnwindTarget* _uw_list; NameDict& f_globals() { return _module->attr(); } - PyVar f_closure_try_get(StrName name); + PyVar* f_closure_try_get(StrName name); int ip() const { return _ip - co->codes.data(); } // function scope - Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, PyVar* _locals_base) + Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) : _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base), _uw_list(nullptr) { } // exec/eval - Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, FastLocals _locals) + Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) : _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals), _uw_list(nullptr) { } // global scope - Frame(PyVar* p0, const CodeObject_& co, PyVar _module) + Frame(PyVar* p0, const CodeObject_& co, PyObject* _module) : _ip(co->codes.data()-1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0), _uw_list(nullptr) { } PyVar* actual_sp_base() const { return _locals.a; } diff --git a/include/pocketpy/gc.h b/include/pocketpy/gc.h index 42f3292b..c69b0563 100644 --- a/include/pocketpy/gc.h +++ b/include/pocketpy/gc.h @@ -39,7 +39,7 @@ struct ManagedHeap{ /********************/ template - PyVar gcnew(Type type, Args&&... args){ + PyObject* gcnew(Type type, Args&&... args){ using __T = std::decay_t; static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types"); // https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476 @@ -47,17 +47,17 @@ struct ManagedHeap{ p->placement_new<__T>(std::forward(args)...); gen.push_back(p); gc_counter++; - return PyVar(type, p); + return p; } template - PyVar _new(Type type, Args&&... args){ + PyObject* _new(Type type, Args&&... args){ using __T = std::decay_t; static_assert(!is_sso_v<__T>); PyObject* p = new(pool128_alloc(py_sizeof<__T>)) PyObject(type); p->placement_new<__T>(std::forward(args)...); _no_gc.push_back(p); - return PyVar(type, p); + return p; } void _delete(PyObject*); diff --git a/include/pocketpy/iter.h b/include/pocketpy/iter.h index 33bf0112..49510f77 100644 --- a/include/pocketpy/iter.h +++ b/include/pocketpy/iter.h @@ -11,7 +11,7 @@ struct RangeIter{ // step > 0 i64 current; RangeIter(Range r) : r(r), current(r.start) {} - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); }; struct RangeIterR{ // step < 0 @@ -19,7 +19,7 @@ struct RangeIterR{ // step < 0 i64 current; RangeIterR(Range r) : r(r), current(r.start) {} - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); }; struct ArrayIter{ @@ -31,15 +31,15 @@ struct ArrayIter{ : ref(ref), end(end), current(begin) {} void _gc_mark(VM* vm) const{ vm->__obj_gc_mark(ref); } - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); }; struct StringIter{ PyVar ref; int i; // byte index StringIter(PyVar ref) : ref(ref), i(0) {} - void _gc_mark(VM* vm) const{ PK_OBJ_MARK(ref); } - static void _register(VM* vm, PyVar mod, PyVar type); + void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); } + static void _register(VM* vm, PyObject* mod, PyObject* type); }; struct Generator{ @@ -58,7 +58,7 @@ struct Generator{ } PyVar next(VM* vm); - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); ~Generator(){ if(lf){ @@ -74,8 +74,8 @@ struct DictItemsIter{ DictItemsIter(PyVar ref) : ref(ref) { i = PK_OBJ_GET(Dict, ref)._head_idx; } - void _gc_mark(VM* vm) const{ PK_OBJ_MARK(ref); } - static void _register(VM* vm, PyVar mod, PyVar type); + void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); } + static void _register(VM* vm, PyObject* mod, PyObject* type); }; } // namespace pkpy \ No newline at end of file diff --git a/include/pocketpy/linalg.h b/include/pocketpy/linalg.h index 67204816..008035be 100644 --- a/include/pocketpy/linalg.h +++ b/include/pocketpy/linalg.h @@ -7,7 +7,7 @@ namespace pkpy{ inline bool isclose(float a, float b){ return std::fabs(a - b) < 1e-4; } struct Vec2{ - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); float x, y; Vec2() : x(0.0f), y(0.0f) {} @@ -31,7 +31,7 @@ struct Vec2{ }; struct Vec3{ - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); float x, y, z; Vec3() : x(0.0f), y(0.0f), z(0.0f) {} @@ -54,7 +54,7 @@ struct Vec3{ }; struct Vec4{ - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); float x, y, z, w; Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {} @@ -78,7 +78,7 @@ struct Vec4{ }; struct Mat3x3{ - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); union { struct { diff --git a/include/pocketpy/namedict.h b/include/pocketpy/namedict.h index 8515ec8a..941a4655 100644 --- a/include/pocketpy/namedict.h +++ b/include/pocketpy/namedict.h @@ -16,6 +16,11 @@ constexpr T default_invalid_value(){ #define PK_SMALL_NAME_DICT_CAPACITY 6 #define PK_SMALL_NAME_DICT_LOOP(B) for(int i=0; i struct SmallNameDict{ using K = StrName; diff --git a/include/pocketpy/obj.h b/include/pocketpy/obj.h index c9414acc..92aba4a1 100644 --- a/include/pocketpy/obj.h +++ b/include/pocketpy/obj.h @@ -180,8 +180,8 @@ template struct has_gc_marker : std::false_type {}; template struct has_gc_marker> : std::true_type {}; struct MappingProxy{ - PyVar obj; - MappingProxy(PyVar obj) : obj(obj) {} + PyObject* obj; + MappingProxy(PyObject* obj) : obj(obj) {} NameDict& attr() { return obj->attr(); } void _gc_mark(VM*) const; }; @@ -202,8 +202,10 @@ obj_get_t PyVar::obj_get(){ } } -#define PK_OBJ_GET(T, obj) (obj).obj_get() -#define PK_OBJ_MARK(obj) if((obj).is_ptr) vm->__obj_gc_mark((obj).get()); +#define PK_OBJ_GET(T, obj) ((obj).obj_get()) + +// deprecated +#define PK_OBJ_MARK(obj) vm->obj_gc_mark(obj) #define VAR(x) py_var(vm, x) #define CAST(T, x) py_cast(vm, x) @@ -213,13 +215,6 @@ obj_get_t PyVar::obj_get(){ #define CAST_DEFAULT(T, x, default_value) (x != vm->None) ? py_cast(vm, x) : (default_value) /*****************************************************************/ -inline bool try_cast_int(PyVar obj, i64* val) noexcept { - if(is_int(obj)){ - *val = obj.as(); - return true; - } - return false; -} #define PY_NULL nullptr extern PyVar const PY_OP_CALL; diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index 420dfdb3..7fa1188e 100644 --- a/include/pocketpy/str.h +++ b/include/pocketpy/str.h @@ -119,9 +119,8 @@ struct StrName { return sv() > other.sv(); } - static bool is_valid(int index); static StrName get(std::string_view s); - static std::map>& _interned(); + static std::map& _interned(); static std::map& _r_interned(); static uint32_t _pesudo_random_index; }; diff --git a/include/pocketpy/tuplelist.h b/include/pocketpy/tuplelist.h index 6df7f9b7..57df62b9 100644 --- a/include/pocketpy/tuplelist.h +++ b/include/pocketpy/tuplelist.h @@ -7,8 +7,8 @@ namespace pkpy { -struct List: pod_vector{ - using pod_vector::pod_vector; +struct List: pod_vector{ + using pod_vector::pod_vector; void _gc_mark(VM*) const; }; diff --git a/include/pocketpy/vector.h b/include/pocketpy/vector.h index dc9917c0..160a3233 100644 --- a/include/pocketpy/vector.h +++ b/include/pocketpy/vector.h @@ -5,10 +5,11 @@ namespace pkpy{ -template +template struct pod_vector{ static constexpr int SizeT = sizeof(T); static constexpr int N = 128 / SizeT; + static constexpr int Growth = 2; // static_assert(128 % SizeT == 0); static_assert(is_pod_v); diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 84ea145c..9633b8b9 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -27,7 +27,7 @@ namespace pkpy{ #define STACK_VIEW(n) (s_data.view(n)) typedef PyVar (*BinaryFuncC)(VM*, PyVar, PyVar); -typedef void (*RegisterFunc)(VM*, PyVar, PyVar); +typedef void (*RegisterFunc)(VM*, PyObject*, PyObject*); #if PK_ENABLE_PROFILER struct NextBreakpoint{ @@ -64,14 +64,14 @@ struct PyTypeInfo{ } }; - PyVar obj; // never be garbage collected + PyObject* obj; // never be garbage collected Type base; - PyVar mod; // never be garbage collected + PyObject* mod; // never be garbage collected StrName name; bool subclass_enabled; Vt vt; - PyTypeInfo(PyVar obj, Type base, PyVar mod, StrName name, bool subclass_enabled, Vt vt={}): + PyTypeInfo(PyObject* obj, Type base, PyObject* mod, StrName name, bool subclass_enabled, Vt vt={}): obj(obj), base(base), mod(mod), name(name), subclass_enabled(subclass_enabled), vt(vt) {} std::vector annotated_fields = {}; @@ -165,12 +165,13 @@ public: std::map _lazy_modules; // lazy loaded modules struct{ - PyVar error; + PyObject* error; stack_no_copy s_view; } __c; PyVar StopIteration; // a special Exception class - PyVar builtins, _main; + PyObject* builtins; + PyObject* _main; // typeid -> Type std::map _cxx_typeid_map; @@ -178,8 +179,8 @@ public: std::set _repr_recursion_set; ImportContext __import_context; - PyVar __last_exception; - PyVar __curr_class; + PyObject* __last_exception; + PyObject* __curr_class; PyVar __cached_object_new; std::map __cached_codes; std::map __cached_op_funcs; @@ -260,6 +261,8 @@ public: 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); + void obj_gc_mark(PyVar obj) { if(obj.is_ptr) __obj_gc_mark(obj.get()); } + void obj_gc_mark(PyObject* p) { if(p) __obj_gc_mark(p); } #endif #if PK_REGION("Name Lookup Methods") @@ -273,7 +276,7 @@ public: #if PK_REGION("Source Execution Methods") 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); - PyVar exec(std::string_view source, Str filename, CompileMode mode, PyVar _module=nullptr); + PyVar exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module=nullptr); PyVar exec(std::string_view source); PyVar eval(std::string_view source); @@ -353,25 +356,25 @@ public: #endif #if PK_REGION("General Bindings") - PyVar bind_func(PyVar obj, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT); - PyVar bind_func(Type type, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT){ + PyObject* bind_func(PyObject*obj, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT); + PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT){ return bind_func(_t(type), name, argc, fn, std::move(userdata), bt); } - PyVar bind_property(PyVar, const char*, NativeFuncC fget, NativeFuncC fset=nullptr); + PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr); template - PyVar bind_field(PyVar, const char*, F T::*); + PyObject* bind_field(PyObject*, const char*, F T::*); - PyVar bind(PyVar, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT); + PyObject* bind(PyObject*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT); template - PyVar bind(PyVar, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT); + PyObject* bind(PyObject*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT); template - PyVar bind(PyVar, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT); + PyObject* bind(PyObject*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT); - PyVar bind(PyVar, const char*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT); + PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT); template - PyVar bind(PyVar, const char*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT); + PyObject* bind(PyObject*, const char*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT); template - PyVar bind(PyVar, const char*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT); + PyObject* bind(PyObject*, const char*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT); #endif #if PK_REGION("Error Reporting Methods") @@ -406,19 +409,19 @@ public: Type _tp(PyVar obj){ return obj.type; } const PyTypeInfo* _tp_info(PyVar obj) { return &_all_types[_tp(obj)]; } const PyTypeInfo* _tp_info(Type type) { return &_all_types[type]; } - PyVar _t(PyVar obj){ return _all_types[_tp(obj)].obj; } - PyVar _t(Type type){ return _all_types[type].obj; } + PyObject* _t(PyVar obj){ return _all_types[_tp(obj)].obj; } + PyObject* _t(Type type){ return _all_types[type].obj; } // equivalent to `obj == NotImplemented` but faster static bool is_not_implemented(PyVar obj){ return obj.type == tp_not_implemented; } #endif #if PK_REGION("User Type Registration") - PyVar new_module(Str name, Str package=""); - PyVar new_type_object(PyVar mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt={}); + PyObject* new_module(Str name, Str package=""); + PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt={}); template - PyVar new_type_object(PyVar mod, StrName name, Type base, bool subclass_enabled){ + PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled){ return new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get()); } @@ -428,9 +431,9 @@ public: bool is_user_type(PyVar obj){ return _tp(obj) == _tp_user(); } template - PyVar register_user_class(PyVar, StrName, RegisterFunc, Type base=tp_object, bool subclass_enabled=false); + PyObject* register_user_class(PyObject*, StrName, RegisterFunc, Type base=tp_object, bool subclass_enabled=false); template - PyVar register_user_class(PyVar, StrName, Type base=tp_object, bool subclass_enabled=false); + PyObject* register_user_class(PyObject*, StrName, Type base=tp_object, bool subclass_enabled=false); template PyVar new_user_object(Args&&... args){ @@ -601,10 +604,8 @@ __T _py_cast__internal(VM* vm, PyVar obj) { return (T)obj.as(); }else if constexpr(is_floating_point_v){ static_assert(!std::is_reference_v<__T>); - // float if(is_float(obj)) return (T)obj.as(); - i64 bits; - if(try_cast_int(obj, &bits)) return (T)bits; + if(is_int(obj)) return (T)obj.as(); vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape()); return 0.0f; }else if constexpr(std::is_enum_v){ @@ -641,15 +642,15 @@ template __T _py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, false>(vm, obj); } template -PyVar VM::register_user_class(PyVar mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled){ - PyVar type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get()); +PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled){ + PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get()); mod->attr().set(name, type); - _cxx_typeid_map[typeid(T)] = PK_OBJ_GET(Type, type); + _cxx_typeid_map[typeid(T)] = type->as(); _register(this, mod, type); if(!type->attr().contains(__new__)){ if constexpr(std::is_default_constructible_v) { bind_func(type, __new__, -1, [](VM* vm, ArgsView args){ - Type cls_t = PK_OBJ_GET(Type, args[0]); + Type cls_t = args[0]->as(); return vm->new_object(cls_t); }); }else{ @@ -660,7 +661,7 @@ PyVar VM::register_user_class(PyVar mod, StrName name, RegisterFunc _register, T } template -PyVar VM::register_user_class(PyVar mod, StrName name, Type base, bool subclass_enabled){ +PyObject* VM::register_user_class(PyObject* mod, StrName name, Type base, bool subclass_enabled){ return register_user_class(mod, name, &T::_register, base, subclass_enabled); } diff --git a/src/array2d.cpp b/src/array2d.cpp index 41cd2c91..adb2f437 100644 --- a/src/array2d.cpp +++ b/src/array2d.cpp @@ -41,7 +41,7 @@ struct Array2d{ data[row * n_cols + col] = value; } - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args){ Type cls = PK_OBJ_GET(Type, args[0]); return vm->new_object(cls); @@ -113,11 +113,13 @@ struct Array2d{ int slice_height = stop_row - start_row; \ if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive"); - vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ + vm->bind__getitem__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ Array2d& self = PK_OBJ_GET(Array2d, _0); const Tuple& xy = CAST(Tuple&, _1); - i64 col, row; - if(try_cast_int(xy[0], &col) && try_cast_int(xy[1], &row)){ + + if(is_int(xy[0]) && is_int(xy[1])){ + i64 col = xy[0].as(); + i64 row = xy[1].as(); self.check_valid(vm, col, row); return self._get(col, row); } @@ -137,11 +139,12 @@ struct Array2d{ vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index"); }); - vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ + vm->bind__setitem__(type->as(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ Array2d& self = PK_OBJ_GET(Array2d, _0); const Tuple& xy = CAST(Tuple&, _1); - i64 col, row; - if(try_cast_int(xy[0], &col) && try_cast_int(xy[1], &row)){ + if(is_int(xy[0]) && is_int(xy[1])){ + i64 col = xy[0].as(); + i64 row = xy[1].as(); self.check_valid(vm, col, row); self._set(col, row, _2); return; @@ -195,12 +198,12 @@ struct Array2d{ return VAR(std::move(t)); }); - vm->bind__len__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ + vm->bind__len__(type->as(), [](VM* vm, PyVar _0){ Array2d& self = PK_OBJ_GET(Array2d, _0); return (i64)self.numel; }); - vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> Str{ + vm->bind__repr__(type->as(), [](VM* vm, PyVar _0) -> Str{ Array2d& self = PK_OBJ_GET(Array2d, _0); return _S("array2d(", self.n_cols, ", ", self.n_rows, ')'); }); @@ -269,7 +272,7 @@ struct Array2d{ return vm->None; }); - vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ + vm->bind__eq__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ Array2d& self = PK_OBJ_GET(Array2d, _0); if(!vm->is_user_type(_1)) return vm->NotImplemented; Array2d& other = PK_OBJ_GET(Array2d, _1); @@ -352,7 +355,7 @@ struct Array2d{ } void _gc_mark(VM* vm) const{ - for(int i = 0; i < numel; i++) PK_OBJ_MARK(data[i]); + for(int i = 0; i < numel; i++) vm->obj_gc_mark(data[i]); } ~Array2d(){ @@ -370,11 +373,11 @@ struct Array2dIter{ Array2dIter(PyVar ref, Array2d* a): ref(ref), a(a), i(0){} - void _gc_mark(VM* vm) const{ PK_OBJ_MARK(ref); } + void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); } - static void _register(VM* vm, PyVar mod, PyVar type){ - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) { return _0; }); - vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{ + static void _register(VM* vm, PyObject* mod, PyObject* type){ + vm->bind__iter__(type->as(), [](VM* vm, PyVar _0) { return _0; }); + vm->bind__next__(type->as(), [](VM* vm, PyVar _0) -> unsigned{ Array2dIter& self = PK_OBJ_GET(Array2dIter, _0); if(self.i == self.a->numel) return 0; std::div_t res = std::div(self.i, self.a->n_cols); @@ -387,7 +390,7 @@ struct Array2dIter{ }; void add_module_array2d(VM* vm){ - PyVar mod = vm->new_module("array2d"); + PyObject* mod = vm->new_module("array2d"); vm->register_user_class(mod, "array2d", VM::tp_object, true); vm->register_user_class(mod, "_array2d_iter"); diff --git a/src/base64.cpp b/src/base64.cpp index 8da0976e..3016f54c 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -166,7 +166,7 @@ base64_decode(const char *in, unsigned int inlen, unsigned char *out) } void add_module_base64(VM* vm){ - PyVar mod = vm->new_module("base64"); + PyObject* mod = vm->new_module("base64"); // b64encode vm->bind_func(mod, "b64encode", 1, [](VM* vm, ArgsView args){ diff --git a/src/ceval.cpp b/src/ceval.cpp index a0d99cde..81732100 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -1,4 +1,5 @@ #include "pocketpy/ceval.h" +#include "pocketpy/codeobject.h" namespace pkpy{ @@ -194,22 +195,22 @@ __NEXT_STEP: PUSH(*slot); DISPATCH() } - PyVar _0 = frame->f_closure_try_get(_name); - if(_0 != nullptr) { PUSH(_0); DISPATCH() } - _0 = frame->f_globals().try_get_likely_found(_name); - if(_0 != nullptr) { PUSH(_0); DISPATCH() } - _0 = vm->builtins->attr().try_get_likely_found(_name); - if(_0 != nullptr) { PUSH(_0); DISPATCH() } + PyVar* _0 = frame->f_closure_try_get(_name); + if(_0 != nullptr) { PUSH(*_0); DISPATCH() } + _0 = frame->f_globals().try_get_2_likely_found(_name); + if(_0 != nullptr) { PUSH(*_0); DISPATCH() } + _0 = vm->builtins->attr().try_get_2_likely_found(_name); + if(_0 != nullptr) { PUSH(*_0); DISPATCH() } vm->NameError(_name); } DISPATCH() case OP_LOAD_NONLOCAL: { StrName _name(byte.arg); - PyVar _0 = frame->f_closure_try_get(_name); - if(_0 != nullptr) { PUSH(_0); DISPATCH() } - _0 = frame->f_globals().try_get_likely_found(_name); - if(_0 != nullptr) { PUSH(_0); DISPATCH() } - _0 = vm->builtins->attr().try_get_likely_found(_name); - if(_0 != nullptr) { PUSH(_0); DISPATCH() } + PyVar* _0 = frame->f_closure_try_get(_name); + if(_0 != nullptr) { PUSH(*_0); DISPATCH() } + _0 = frame->f_globals().try_get_2_likely_found(_name); + if(_0 != nullptr) { PUSH(*_0); DISPATCH() } + _0 = vm->builtins->attr().try_get_2_likely_found(_name); + if(_0 != nullptr) { PUSH(*_0); DISPATCH() } vm->NameError(_name); } DISPATCH() case OP_LOAD_GLOBAL:{ @@ -282,7 +283,7 @@ __NEXT_STEP: if(slot != nullptr){ *slot = _0; // store in locals if possible }else{ - Function& func = PK_OBJ_GET(Function, frame->_callable); + Function& func = frame->_callable->as(); if(func.decl == __dynamic_func_decl){ PK_DEBUG_ASSERT(func._closure != nullptr); func._closure->set(_name, _0); @@ -338,7 +339,7 @@ __NEXT_STEP: if(slot != nullptr){ slot->set_null(); }else{ - Function& func = PK_OBJ_GET(Function, frame->_callable); + Function& func = frame->_callable->as(); if(func.decl == __dynamic_func_decl){ PK_DEBUG_ASSERT(func._closure != nullptr); bool ok = func._closure->del(_name); @@ -949,7 +950,7 @@ __NEXT_STEP: StrName _name(byte.arg); frame->_module->attr().set(_name, __curr_class); // call on_end_subclass - PyTypeInfo* ti = &_all_types[PK_OBJ_GET(Type, __curr_class)]; + PyTypeInfo* ti = &_all_types[__curr_class->as()]; if(ti->base != tp_object){ PyTypeInfo* base_ti = &_all_types[ti->base]; if(base_ti->on_end_subclass) base_ti->on_end_subclass(this, ti); @@ -969,12 +970,12 @@ __NEXT_STEP: PUSH(__curr_class); } DISPATCH() case OP_END_CLASS_DECORATION:{ - __curr_class = POPX(); + __curr_class = POPX().get(); } DISPATCH() case OP_ADD_CLASS_ANNOTATION: { PK_ASSERT(__curr_class != nullptr); StrName _name(byte.arg); - Type type = PK_OBJ_GET(Type, __curr_class); + Type type = __curr_class->as(); _all_types[type].annotated_fields.push_back(_name); } DISPATCH() /*****************************************/ @@ -1016,7 +1017,7 @@ __NEXT_STEP: } DISPATCH() case OP_RE_RAISE: __raise_exc(true); DISPATCH() - case OP_POP_EXCEPTION: __last_exception = POPX(); DISPATCH() + case OP_POP_EXCEPTION: __last_exception = POPX().get(); DISPATCH() /*****************************************/ case OP_FORMAT_STRING: { PyVar _0 = POPX(); diff --git a/src/cffi.cpp b/src/cffi.cpp index cf6ac12b..fa9cbadd 100644 --- a/src/cffi.cpp +++ b/src/cffi.cpp @@ -2,25 +2,25 @@ namespace pkpy{ - void VoidP::_register(VM* vm, PyVar mod, PyVar type){ + void VoidP::_register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){ Type cls = PK_OBJ_GET(Type, args[0]); i64 addr = CAST(i64, args[1]); return vm->new_object(cls, reinterpret_cast(addr)); }); - vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj){ + vm->bind__hash__(type->as(), [](VM* vm, PyVar obj){ obj_get_t self = PK_OBJ_GET(VoidP, obj); return reinterpret_cast(self.ptr); }); - vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{ + vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str{ obj_get_t self = PK_OBJ_GET(VoidP, obj); return _S(""); }); #define BIND_CMP(name, op) \ - vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyVar lhs, PyVar rhs){ \ + vm->bind##name(type->as(), [](VM* vm, PyVar lhs, PyVar rhs){ \ if(!vm->isinstance(rhs, vm->_tp_user())) return vm->NotImplemented; \ void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \ void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \ @@ -37,7 +37,7 @@ namespace pkpy{ } - void Struct::_register(VM* vm, PyVar mod, PyVar type){ + void Struct::_register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){ Type cls = PK_OBJ_GET(Type, args[0]); int size = CAST(int, args[1]); @@ -72,7 +72,7 @@ namespace pkpy{ return vm->new_user_object(std::move(buffer)); }, {}, BindType::STATICMETHOD); - vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj){ + vm->bind__repr__(type->as(), [](VM* vm, PyVar obj){ Struct& self = _CAST(Struct&, obj); SStream ss; ss << ""; @@ -94,7 +94,7 @@ namespace pkpy{ return vm->new_object(vm->_tp(args[0]), self); }); - vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar lhs, PyVar rhs){ + vm->bind__eq__(type->as(), [](VM* vm, PyVar lhs, PyVar rhs){ Struct& self = _CAST(Struct&, lhs); if(!vm->is_user_type(rhs)) return vm->NotImplemented; Struct& other = _CAST(Struct&, rhs); @@ -134,7 +134,7 @@ namespace pkpy{ } void add_module_c(VM* vm){ - PyVar mod = vm->new_module("c"); + PyObject* mod = vm->new_module("c"); vm->bind_func(mod, "malloc", 1, [](VM* vm, ArgsView args){ i64 size = CAST(i64, args[0]); @@ -187,7 +187,7 @@ void add_module_c(VM* vm){ return vm->new_object(args[0].type, value); }); - PyVar type; + PyObject* type; Type type_t; #define BIND_PRIMITIVE(T, CNAME) \ @@ -197,7 +197,7 @@ void add_module_c(VM* vm){ }); \ type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user(), true); \ mod->attr().set(CNAME "_p", type); \ - type_t = PK_OBJ_GET(Type, type); \ + type_t = type->as(); \ vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args){ \ obj_get_t voidp = PK_OBJ_GET(VoidP, args[0]); \ T* target = (T*)voidp.ptr; \ @@ -255,7 +255,7 @@ void add_module_c(VM* vm){ #undef BIND_PRIMITIVE - PyVar char_p_t = mod->attr("char_p"); + PyObject* char_p_t = mod->attr("char_p").get(); vm->bind(char_p_t, "read_string(self) -> str", [](VM* vm, ArgsView args){ obj_get_t voidp = PK_OBJ_GET(VoidP, args[0]); const char* target = (const char*)voidp.ptr; diff --git a/src/collections.cpp b/src/collections.cpp index aa93b4f5..7fc6232f 100644 --- a/src/collections.cpp +++ b/src/collections.cpp @@ -18,14 +18,14 @@ namespace pkpy { this->is_reversed = true; } - void _gc_mark(VM* vm) const { PK_OBJ_MARK(ref); } - static void _register(VM *vm, PyVar mod, PyVar type); + void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); } + static void _register(VM *vm, PyObject* mod, PyObject* type); }; - void PyDequeIter::_register(VM *vm, PyVar mod, PyVar type) + void PyDequeIter::_register(VM *vm, PyObject* mod, PyObject* type) { - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar obj) + vm->bind__iter__(type->as(), [](VM *vm, PyVar obj) { return obj; }); - vm->bind__next__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar obj) -> unsigned + vm->bind__next__(type->as(), [](VM *vm, PyVar obj) -> unsigned { PyDequeIter& self = _CAST(PyDequeIter&, obj); if(self.is_reversed){ @@ -52,10 +52,10 @@ namespace pkpy PyVar popObj(bool front, bool back, PyVar item, VM *vm); // pop at index, used purely for internal purposes: pop, popleft, remove methods int findIndex(VM *vm, PyVar obj, int start, int stop); // find the index of the given object in the deque // Special methods - static void _register(VM *vm, PyVar mod, PyVar type); // register the type + static void _register(VM *vm, PyObject* mod, PyObject* type); // register the type void _gc_mark(VM*) const; // needed for container types, mark all objects in the deque for gc }; - void PyDeque::_register(VM *vm, PyVar mod, PyVar type) + void PyDeque::_register(VM *vm, PyObject* mod, PyObject* type) { vm->bind(type, "__new__(cls, iterable=None, maxlen=None)", [](VM *vm, ArgsView args) @@ -67,7 +67,7 @@ namespace pkpy }); // gets the item at the given index, if index is negative, it will be treated as index + len(deque) // if the index is out of range, IndexError will be thrown --> required for [] operator - vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar _0, PyVar _1) + vm->bind__getitem__(type->as(), [](VM *vm, PyVar _0, PyVar _1) { PyDeque &self = _CAST(PyDeque &, _0); i64 index = CAST(i64, _1); @@ -76,7 +76,7 @@ namespace pkpy }); // sets the item at the given index, if index is negative, it will be treated as index + len(deque) // if the index is out of range, IndexError will be thrown --> required for [] operator - vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar _0, PyVar _1, PyVar _2) + vm->bind__setitem__(type->as(), [](VM *vm, PyVar _0, PyVar _1, PyVar _2) { PyDeque &self = _CAST(PyDeque&, _0); i64 index = CAST(i64, _1); @@ -85,7 +85,7 @@ namespace pkpy }); // erases the item at the given index, if index is negative, it will be treated as index + len(deque) // if the index is out of range, IndexError will be thrown --> required for [] operator - vm->bind__delitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar _0, PyVar _1) + vm->bind__delitem__(type->as(), [](VM *vm, PyVar _0, PyVar _1) { PyDeque &self = _CAST(PyDeque&, _0); i64 index = CAST(i64, _1); @@ -93,19 +93,19 @@ namespace pkpy self.dequeItems.erase(self.dequeItems.begin() + index); }); - vm->bind__len__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar _0) + vm->bind__len__(type->as(), [](VM *vm, PyVar _0) { PyDeque &self = _CAST(PyDeque&, _0); return (i64)self.dequeItems.size(); }); - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar _0) + vm->bind__iter__(type->as(), [](VM *vm, PyVar _0) { PyDeque &self = _CAST(PyDeque &, _0); return vm->new_user_object(_0, self.dequeItems.begin(), self.dequeItems.end()); }); - vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar _0) -> Str + vm->bind__repr__(type->as(), [](VM *vm, PyVar _0) -> Str { if(vm->_repr_recursion_set.count(_0)) return "[...]"; const PyDeque &self = _CAST(PyDeque&, _0); @@ -123,7 +123,7 @@ namespace pkpy }); // enables comparison between two deques, == and != are supported - vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM *vm, PyVar _0, PyVar _1) + vm->bind__eq__(type->as(), [](VM *vm, PyVar _0, PyVar _1) { const PyDeque &self = _CAST(PyDeque&, _0); if(!vm->is_user_type(_0)) return vm->NotImplemented; @@ -534,13 +534,12 @@ namespace pkpy /// @brief marks the deque items for garbage collection void PyDeque::_gc_mark(VM* vm) const { - for (PyVar obj : this->dequeItems) - PK_OBJ_MARK(obj); + for (PyVar obj : this->dequeItems) vm->obj_gc_mark(obj); } /// @brief registers the PyDeque class void add_module_collections(VM *vm) { - PyVar mod = vm->new_module("collections"); + PyObject* mod = vm->new_module("collections"); vm->register_user_class(mod, "deque", VM::tp_object, true); vm->register_user_class(mod, "_deque_iter"); CodeObject_ code = vm->compile(kPythonLibs_collections, "collections.py", EXEC_MODE); diff --git a/src/csv.cpp b/src/csv.cpp index e7f4c755..e6c054bb 100644 --- a/src/csv.cpp +++ b/src/csv.cpp @@ -3,7 +3,7 @@ namespace pkpy{ void add_module_csv(VM *vm){ - PyVar mod = vm->new_module("csv"); + PyObject* mod = vm->new_module("csv"); vm->bind(mod, "reader(csvfile: list[str]) -> list[list]", [](VM* vm, ArgsView args){ const List& csvfile = CAST(List&, args[0]); diff --git a/src/dataclasses.cpp b/src/dataclasses.cpp index 5c96af87..10a2e7f3 100644 --- a/src/dataclasses.cpp +++ b/src/dataclasses.cpp @@ -77,7 +77,7 @@ static void patch__eq__(VM* vm, Type cls){ } void add_module_dataclasses(VM* vm){ - PyVar mod = vm->new_module("dataclasses"); + PyObject* mod = vm->new_module("dataclasses"); vm->bind_func(mod, "dataclass", 1, [](VM* vm, ArgsView args){ vm->check_type(args[0], VM::tp_type); diff --git a/src/easing.cpp b/src/easing.cpp index cfd67885..615d434d 100644 --- a/src/easing.cpp +++ b/src/easing.cpp @@ -206,7 +206,7 @@ static double easeInOutBounce( double x ) { } void add_module_easing(VM* vm){ - PyVar mod = vm->new_module("easing"); + PyObject* mod = vm->new_module("easing"); #define EASE(name) \ vm->bind_func(mod, #name, 1, [](VM* vm, ArgsView args){ \ diff --git a/src/expr.cpp b/src/expr.cpp index 88f61be0..b61fc2da 100644 --- a/src/expr.cpp +++ b/src/expr.cpp @@ -120,26 +120,23 @@ namespace pkpy{ }else{ co->consts.push_back(VAR(key)); int index = co->consts.size() - 1; - _co_consts_string_dedup_map[std::string(key)] = index; + key = co->consts.back().obj_get().sv(); + _co_consts_string_dedup_map[key] = index; return index; } } int CodeEmitContext::add_const(PyVar v){ - if(is_type(v, vm->tp_str)){ - // warning: should use add_const_string() instead - return add_const_string(PK_OBJ_GET(Str, v).sv()); + PK_ASSERT(!is_type(v, VM::tp_str)) + // non-string deduplication + auto it = _co_consts_nonstring_dedup_map.find(v); + if(it != _co_consts_nonstring_dedup_map.end()){ + return it->second; }else{ - // non-string deduplication - auto it = _co_consts_nonstring_dedup_map.find(v); - if(it != _co_consts_nonstring_dedup_map.end()){ - return it->second; - }else{ - co->consts.push_back(v); - int index = co->consts.size() - 1; - _co_consts_nonstring_dedup_map[v] = index; - return index; - } + co->consts.push_back(v); + int index = co->consts.size() - 1; + _co_consts_nonstring_dedup_map[v] = index; + return index; } } diff --git a/src/frame.cpp b/src/frame.cpp index 934ee816..752624fd 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -16,11 +16,11 @@ namespace pkpy{ return dict; } - PyVar Frame::f_closure_try_get(StrName name){ + PyVar* Frame::f_closure_try_get(StrName name){ if(_callable == nullptr) return nullptr; - Function& fn = PK_OBJ_GET(Function, _callable); + Function& fn = _callable->as(); if(fn._closure == nullptr) return nullptr; - return fn._closure->try_get(name); + return fn._closure->try_get_2(name); } int Frame::prepare_jump_exception_handler(ValueStack* _s){ diff --git a/src/io.cpp b/src/io.cpp index 5d90a5e2..4baaaa3c 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -15,7 +15,7 @@ struct FileIO { FileIO(VM* vm, const Str& file, const Str& mode); void close(); - static void _register(VM* vm, PyVar mod, PyVar type); + static void _register(VM* vm, PyObject* mod, PyObject* type); }; static FILE* io_fopen(const char* name, const char* mode){ @@ -53,7 +53,7 @@ unsigned char* _default_import_handler(const char* name, int* out_size){ return buffer; }; -void FileIO::_register(VM* vm, PyVar mod, PyVar type){ +void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args){ Type cls = PK_OBJ_GET(Type, args[0]); return vm->new_object(cls, vm, @@ -138,7 +138,7 @@ void FileIO::close(){ } void add_module_io(VM* vm){ - PyVar mod = vm->new_module("io"); + PyObject* mod = vm->new_module("io"); vm->register_user_class(mod, "FileIO"); mod->attr().set("SEEK_SET", VAR(SEEK_SET)); @@ -153,7 +153,7 @@ void add_module_io(VM* vm){ } void add_module_os(VM* vm){ - PyVar mod = vm->new_module("os"); + PyObject* mod = vm->new_module("os"); PyVar path_obj = vm->new_object(vm->tp_object); mod->attr().set("path", path_obj); diff --git a/src/iter.cpp b/src/iter.cpp index 6eb138b6..9994be55 100644 --- a/src/iter.cpp +++ b/src/iter.cpp @@ -2,9 +2,9 @@ namespace pkpy{ - void RangeIter::_register(VM* vm, PyVar mod, PyVar type){ - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ return _0; }); - vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{ + void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type){ + vm->bind__iter__(type->as(), [](VM* vm, PyVar _0){ return _0; }); + vm->bind__next__(type->as(), [](VM* vm, PyVar _0) -> unsigned{ RangeIter& self = PK_OBJ_GET(RangeIter, _0); if(self.current >= self.r.stop) return 0; vm->s_data.emplace(VM::tp_int, self.current); @@ -13,9 +13,9 @@ namespace pkpy{ }); } - void RangeIterR::_register(VM* vm, PyVar mod, PyVar type){ - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ return _0; }); - vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{ + void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type){ + vm->bind__iter__(type->as(), [](VM* vm, PyVar _0){ return _0; }); + vm->bind__next__(type->as(), [](VM* vm, PyVar _0) -> unsigned{ RangeIterR& self = PK_OBJ_GET(RangeIterR, _0); if(self.current <= self.r.stop) return 0; vm->s_data.emplace(VM::tp_int, self.current); @@ -24,9 +24,9 @@ namespace pkpy{ }); } - void ArrayIter::_register(VM* vm, PyVar mod, PyVar type){ - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ return _0; }); - vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{ + void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type){ + vm->bind__iter__(type->as(), [](VM* vm, PyVar _0){ return _0; }); + vm->bind__next__(type->as(), [](VM* vm, PyVar _0) -> unsigned{ ArrayIter& self = _CAST(ArrayIter&, _0); if(self.current == self.end) return 0; vm->s_data.push(*self.current++); @@ -34,9 +34,9 @@ namespace pkpy{ }); } - void StringIter::_register(VM* vm, PyVar mod, PyVar type){ - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ return _0; }); - vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{ + void StringIter::_register(VM* vm, PyObject* mod, PyObject* type){ + vm->bind__iter__(type->as(), [](VM* vm, PyVar _0){ return _0; }); + vm->bind__next__(type->as(), [](VM* vm, PyVar _0) -> unsigned{ StringIter& self = _CAST(StringIter&, _0); Str& s = PK_OBJ_GET(Str, self.ref); if(self.i == s.size) return 0; @@ -99,9 +99,9 @@ namespace pkpy{ } } - void Generator::_register(VM* vm, PyVar mod, PyVar type){ - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ return _0; }); - vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{ + void Generator::_register(VM* vm, PyObject* mod, PyObject* type){ + vm->bind__iter__(type->as(), [](VM* vm, PyVar _0){ return _0; }); + vm->bind__next__(type->as(), [](VM* vm, PyVar _0) -> unsigned{ Generator& self = _CAST(Generator&, _0); PyVar retval = self.next(vm); if(retval == vm->StopIteration) return 0; @@ -110,9 +110,9 @@ namespace pkpy{ }); } - void DictItemsIter::_register(VM *vm, PyVar mod, PyVar type){ - vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0){ return _0; }); - vm->bind__next__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0) -> unsigned{ + void DictItemsIter::_register(VM *vm, PyObject* mod, PyObject* type){ + vm->bind__iter__(type->as(), [](VM* vm, PyVar _0){ return _0; }); + vm->bind__next__(type->as(), [](VM* vm, PyVar _0) -> unsigned{ DictItemsIter& self = _CAST(DictItemsIter&, _0); Dict& d = PK_OBJ_GET(Dict, self.ref); if(self.i == -1) return 0; diff --git a/src/linalg.cpp b/src/linalg.cpp index 4a3b6835..c856f980 100644 --- a/src/linalg.cpp +++ b/src/linalg.cpp @@ -3,14 +3,14 @@ namespace pkpy{ #define BIND_VEC_VEC_OP(D, name, op) \ - vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \ + vm->bind##name(type->as(), [](VM* vm, PyVar _0, PyVar _1){ \ Vec##D self = _CAST(Vec##D, _0); \ Vec##D other = CAST(Vec##D, _1); \ return VAR(self op other); \ }); #define BIND_VEC_FLOAT_OP(D, name, op) \ - vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \ + vm->bind##name(type->as(), [](VM* vm, PyVar _0, PyVar _1){ \ Vec##D self = _CAST(Vec##D, _0); \ f64 other = CAST(f64, _1); \ return VAR(self op other); \ @@ -30,7 +30,7 @@ namespace pkpy{ }); #define BIND_VEC_MUL_OP(D) \ - vm->bind__mul__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \ + vm->bind__mul__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ \ Vec##D self = _CAST(Vec##D, _0); \ if(vm->is_user_type(_1)){ \ Vec##D other = _CAST(Vec##D, _1); \ @@ -44,14 +44,14 @@ namespace pkpy{ f64 other = CAST(f64, args[1]); \ return VAR(self * other); \ }); \ - vm->bind__truediv__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \ + vm->bind__truediv__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ \ Vec##D self = _CAST(Vec##D, _0); \ f64 other = CAST(f64, _1); \ return VAR(self / other); \ }); #define BIND_VEC_GETITEM(D) \ - vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj, PyVar index){ \ + vm->bind__getitem__(type->as(), [](VM* vm, PyVar obj, PyVar index){ \ Vec##D self = _CAST(Vec##D, obj); \ i64 i = CAST(i64, index); \ if(i < 0 || i >= D) vm->IndexError("index out of range"); \ @@ -59,7 +59,7 @@ namespace pkpy{ }); #define BIND_SSO_VEC_COMMON(D) \ - vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ \ + vm->bind__eq__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ \ Vec##D self = _CAST(Vec##D, _0); \ if(!vm->is_user_type(_1)) return vm->NotImplemented; \ Vec##D other = _CAST(Vec##D, _1); \ @@ -127,7 +127,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return Vec2(output_x, output_y); } - void Vec2::_register(VM* vm, PyVar mod, PyVar type){ + void Vec2::_register(VM* vm, PyObject* mod, PyObject* type){ type->attr().set("ZERO", vm->new_user_object(0, 0)); type->attr().set("ONE", vm->new_user_object(1, 1)); @@ -160,7 +160,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return VAR(val); }, {}, BindType::STATICMETHOD); - vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{ + vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str{ Vec2 self = _CAST(Vec2, obj); SStream ss; ss.setprecision(3); @@ -190,7 +190,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s BIND_SSO_VEC_COMMON(2) } - void Vec3::_register(VM* vm, PyVar mod, PyVar type){ + void Vec3::_register(VM* vm, PyObject* mod, PyObject* type){ type->attr().set("ZERO", vm->new_user_object(0, 0, 0)); type->attr().set("ONE", vm->new_user_object(1, 1, 1)); @@ -201,7 +201,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return vm->new_object(PK_OBJ_GET(Type, args[0]), x, y, z); }); - vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{ + vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str{ Vec3 self = _CAST(Vec3, obj); SStream ss; ss.setprecision(3); @@ -225,7 +225,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s BIND_SSO_VEC_COMMON(3) } - void Vec4::_register(VM* vm, PyVar mod, PyVar type){ + void Vec4::_register(VM* vm, PyObject* mod, PyObject* type){ PY_STRUCT_LIKE(Vec4) type->attr().set("ZERO", vm->new_user_object(0, 0, 0, 0)); @@ -239,7 +239,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return vm->new_object(PK_OBJ_GET(Type, args[0]), x, y, z, w); }); - vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{ + vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str{ Vec4 self = _CAST(Vec4&, obj); SStream ss; ss.setprecision(3); @@ -270,7 +270,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s #undef BIND_VEC_FUNCTION_1 #undef BIND_VEC_GETITEM - void Mat3x3::_register(VM* vm, PyVar mod, PyVar type){ + void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type){ PY_STRUCT_LIKE(Mat3x3) vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args){ @@ -298,7 +298,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return vm->None; }); - vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj) -> Str{ + vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str{ const Mat3x3& self = _CAST(Mat3x3&, obj); SStream ss; ss.setprecision(3); @@ -308,7 +308,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return ss.str(); }); - vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj, PyVar index){ + vm->bind__getitem__(type->as(), [](VM* vm, PyVar obj, PyVar index){ Mat3x3& self = _CAST(Mat3x3&, obj); Tuple& t = CAST(Tuple&, index); if(t.size() != 2){ @@ -322,7 +322,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return VAR(self.m[i][j]); }); - vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj, PyVar index, PyVar value){ + vm->bind__setitem__(type->as(), [](VM* vm, PyVar obj, PyVar index, PyVar value){ Mat3x3& self = _CAST(Mat3x3&, obj); const Tuple& t = CAST(Tuple&, index); if(t.size() != 2){ @@ -346,19 +346,19 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s vm->bind_field(type, "_32", &Mat3x3::_32); vm->bind_field(type, "_33", &Mat3x3::_33); - vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ + vm->bind__add__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ Mat3x3& self = _CAST(Mat3x3&, _0); Mat3x3& other = CAST(Mat3x3&, _1); return vm->new_user_object(self + other); }); - vm->bind__sub__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ + vm->bind__sub__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ Mat3x3& self = _CAST(Mat3x3&, _0); Mat3x3& other = CAST(Mat3x3&, _1); return vm->new_user_object(self - other); }); - vm->bind__mul__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ + vm->bind__mul__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ Mat3x3& self = _CAST(Mat3x3&, _0); f64 other = CAST_F(_1); return vm->new_user_object(self * other); @@ -370,13 +370,13 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return vm->new_user_object(self * other); }); - vm->bind__truediv__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ + vm->bind__truediv__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ Mat3x3& self = _CAST(Mat3x3&, _0); f64 other = CAST_F(_1); return vm->new_user_object(self / other); }); - vm->bind__matmul__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar _0, PyVar _1){ + vm->bind__matmul__(type->as(), [](VM* vm, PyVar _0, PyVar _1){ Mat3x3& self = _CAST(Mat3x3&, _0); if(vm->is_user_type(_1)){ const Mat3x3& other = _CAST(Mat3x3&, _1); @@ -411,7 +411,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s return vm->new_user_object(self.transpose()); }); - vm->bind__invert__(PK_OBJ_GET(Type, type), [](VM* vm, PyVar obj){ + vm->bind__invert__(type->as(), [](VM* vm, PyVar obj){ Mat3x3& self = _CAST(Mat3x3&, obj); Mat3x3 ret; if(!self.inverse(ret)) vm->ValueError("matrix is not invertible"); @@ -548,7 +548,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s void add_module_linalg(VM* vm){ - PyVar linalg = vm->new_module("linalg"); + PyObject* linalg = vm->new_module("linalg"); vm->register_user_class(linalg, "vec2", VM::tp_object); vm->register_user_class(linalg, "vec3", VM::tp_object); diff --git a/src/modules.cpp b/src/modules.cpp index 8f023c66..55822fc3 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -26,7 +26,7 @@ struct PyStructTime{ tm_isdst = tm->tm_isdst; } - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ PY_READONLY_FIELD(PyStructTime, "tm_year", tm_year); PY_READONLY_FIELD(PyStructTime, "tm_mon", tm_mon); PY_READONLY_FIELD(PyStructTime, "tm_mday", tm_mday); @@ -40,7 +40,7 @@ struct PyStructTime{ }; void add_module_time(VM* vm){ - PyVar mod = vm->new_module("time"); + PyObject* mod = vm->new_module("time"); vm->register_user_class(mod, "struct_time"); vm->bind_func(mod, "time", 0, [](VM* vm, ArgsView args) { @@ -67,12 +67,12 @@ void add_module_time(VM* vm){ } void add_module_sys(VM* vm){ - PyVar mod = vm->new_module("sys"); + PyObject* mod = vm->new_module("sys"); vm->setattr(mod, "version", VAR(PK_VERSION)); vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM])); - PyVar stdout_ = vm->new_object(vm->tp_object); - PyVar stderr_ = vm->new_object(vm->tp_object); + PyObject* stdout_ = vm->heap.gcnew(vm->tp_object); + PyObject* stderr_ = vm->heap.gcnew(vm->tp_object); vm->setattr(mod, "stdout", stdout_); vm->setattr(mod, "stderr", stderr_); @@ -90,7 +90,7 @@ void add_module_sys(VM* vm){ } void add_module_json(VM* vm){ - PyVar mod = vm->new_module("json"); + PyObject* mod = vm->new_module("json"); vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args) { std::string_view sv; if(is_type(args[0], vm->tp_bytes)){ @@ -109,7 +109,7 @@ void add_module_json(VM* vm){ // https://docs.python.org/3.5/library/math.html void add_module_math(VM* vm){ - PyVar mod = vm->new_module("math"); + PyObject* mod = vm->new_module("math"); mod->attr().set("pi", VAR(3.1415926535897932384)); mod->attr().set("e" , VAR(2.7182818284590452354)); mod->attr().set("inf", VAR(std::numeric_limits::infinity())); @@ -196,7 +196,7 @@ void add_module_math(VM* vm){ } void add_module_traceback(VM* vm){ - PyVar mod = vm->new_module("traceback"); + PyObject* mod = vm->new_module("traceback"); vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) { if(vm->__last_exception==nullptr) vm->ValueError("no exception"); Exception& e = _CAST(Exception&, vm->__last_exception); @@ -212,7 +212,7 @@ void add_module_traceback(VM* vm){ } void add_module_dis(VM* vm){ - PyVar mod = vm->new_module("dis"); + PyObject* mod = vm->new_module("dis"); vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) { CodeObject_ code; @@ -230,12 +230,12 @@ void add_module_dis(VM* vm){ } void add_module_gc(VM* vm){ - PyVar mod = vm->new_module("gc"); + PyObject* mod = vm->new_module("gc"); vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(vm->heap.collect()))); } void add_module_enum(VM* vm){ - PyVar mod = vm->new_module("enum"); + PyObject* mod = vm->new_module("enum"); CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE); vm->_exec(code, mod); PyVar Enum = mod->attr("Enum"); @@ -253,7 +253,7 @@ void add_module_enum(VM* vm){ } void add_module___builtins(VM* vm){ - PyVar mod = vm->new_module("__builtins"); + PyObject* mod = vm->new_module("__builtins"); vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args){ return vm->py_next(args[0]); @@ -284,7 +284,7 @@ struct _LpGuard{ struct LineProfilerW{ LineProfiler profiler; - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){ Type cls = PK_OBJ_GET(Type, args[0]); return vm->new_object(cls); @@ -333,7 +333,7 @@ _LpGuard::~_LpGuard(){ } void add_module_line_profiler(VM *vm){ - PyVar mod = vm->new_module("line_profiler"); + PyObject* mod = vm->new_module("line_profiler"); vm->register_user_class(mod, "LineProfiler"); } #else diff --git a/src/obj.cpp b/src/obj.cpp index c2707d3c..0145784a 100644 --- a/src/obj.cpp +++ b/src/obj.cpp @@ -1,6 +1,8 @@ #include "pocketpy/obj.h" namespace pkpy{ + PyVar::PyVar(PyObject* p): PyVar(p->type, p) {} + bool Bytes::operator==(const Bytes& rhs) const{ if(_size != rhs._size) return false; for(int i=0; i<_size; i++) if(_data[i] != rhs._data[i]) return false; diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 1b696cfb..ec6b95be 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -10,8 +10,8 @@ template PyVar PyArrayGetItem(VM* vm, PyVar _0, PyVar _1){ static_assert(std::is_same_v || std::is_same_v); const T& self = _CAST(T&, _0); - i64 index; - if(try_cast_int(_1, &index)){ + if(is_int(_1)){ + i64 index = _1.as(); index = vm->normalized_index(index, self.size()); return self[index]; } @@ -28,16 +28,14 @@ PyVar PyArrayGetItem(VM* vm, PyVar _0, PyVar _1){ void __init_builtins(VM* _vm) { #define BIND_NUM_ARITH_OPT(name, op) \ - _vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \ - i64 val; \ - if(try_cast_int(rhs, &val)) return VAR(_CAST(i64, lhs) op val); \ - if(is_float(rhs)) return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \ + _vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \ + if(is_int(rhs)) return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \ + if(is_float(rhs)) return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \ return vm->NotImplemented; \ }); \ - _vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \ - i64 val; \ - if(try_cast_int(rhs, &val)) return VAR(_CAST(f64, lhs) op val); \ - if(is_float(rhs)) return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \ + _vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \ + if(is_int(rhs)) return VAR(_CAST(f64, lhs) op _CAST(i64, rhs)); \ + if(is_float(rhs)) return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \ return vm->NotImplemented; \ }); @@ -48,15 +46,13 @@ void __init_builtins(VM* _vm) { #undef BIND_NUM_ARITH_OPT #define BIND_NUM_LOGICAL_OPT(name, op) \ - _vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \ - i64 val; \ - if(try_cast_int(rhs, &val)) return VAR(_CAST(i64, lhs) op val); \ + _vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \ + if(is_int(rhs)) return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \ if(is_float(rhs)) return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \ return vm->NotImplemented; \ }); \ - _vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \ - i64 val; \ - if(try_cast_int(rhs, &val)) return VAR(_CAST(f64, lhs) op val); \ + _vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \ + if(is_int(rhs)) return VAR(_CAST(f64, lhs) op _CAST(i64, rhs)); \ if(is_float(rhs)) return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \ return vm->NotImplemented; \ }); @@ -79,15 +75,15 @@ void __init_builtins(VM* _vm) { }); _vm->bind_func(_vm->builtins, "super", -1, [](VM* vm, ArgsView args) { - PyVar class_arg = nullptr; + PyObject* class_arg = nullptr; PyVar self_arg = nullptr; if(args.size() == 2){ - class_arg = args[0]; + class_arg = args[0].get(); self_arg = args[1]; }else if(args.size() == 0){ Frame* frame = &vm->callstack.top(); if(frame->_callable != nullptr){ - class_arg = PK_OBJ_GET(Function, frame->_callable)._class; + class_arg = frame->_callable->as()._class; if(frame->_locals.size() > 0) self_arg = frame->_locals[0]; } if(class_arg == nullptr || self_arg == nullptr){ @@ -97,7 +93,7 @@ void __init_builtins(VM* _vm) { vm->TypeError("super() takes 0 or 2 arguments"); } vm->check_type(class_arg, vm->tp_type); - Type type = PK_OBJ_GET(Type, class_arg); + Type type = class_arg->as(); if(!vm->isinstance(self_arg, type)){ StrName _0 = _type_name(vm, vm->_tp(self_arg)); StrName _1 = _type_name(vm, type); @@ -123,7 +119,7 @@ void __init_builtins(VM* _vm) { Tuple& types = _CAST(Tuple&, args[1]); for(PyVar type : types){ vm->check_type(type, vm->tp_type); - if(vm->isinstance(args[0], PK_OBJ_GET(Type, type))) return vm->True; + if(vm->isinstance(args[0], type->as())) return vm->True; } return vm->False; } @@ -139,7 +135,7 @@ void __init_builtins(VM* _vm) { }); _vm->bind_func(_vm->builtins, "globals", 0, [](VM* vm, ArgsView args) { - PyVar mod = vm->callstack.top()._module; + PyObject* mod = vm->callstack.top()._module; return VAR(MappingProxy(mod)); }); @@ -395,8 +391,9 @@ void __init_builtins(VM* _vm) { }); auto py_number_pow = [](VM* vm, PyVar _0, PyVar _1) { - i64 lhs, rhs; - if(try_cast_int(_0, &lhs) && try_cast_int(_1, &rhs)){ + if(is_int(_0) && is_int(_1)){ + i64 lhs = _CAST(i64, _0); + i64 rhs = _CAST(i64, _1); if(rhs < 0) { if(lhs == 0) vm->ZeroDivisionError("0.0 cannot be raised to a negative power"); return VAR((f64)std::pow(lhs, rhs)); @@ -1484,12 +1481,12 @@ void __init_builtins(VM* _vm) { }); // tp_exception - _vm->bind_func(VM::tp_exception, __new__, -1, [](VM* vm, ArgsView args){ + _vm->bind_func(VM::tp_exception, __new__, -1, [](VM* vm, ArgsView args) -> PyVar{ Type cls = PK_OBJ_GET(Type, args[0]); StrName cls_name = _type_name(vm, cls); - PyVar e_obj = vm->new_object(cls, cls_name); + PyObject* e_obj = vm->heap.gcnew(cls, cls_name); e_obj->_enable_instance_dict(); - PK_OBJ_GET(Exception, e_obj)._self = e_obj; + e_obj->as()._self = e_obj; return e_obj; }); @@ -1560,7 +1557,7 @@ void VM::__post_init_builtin_types(){ const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; return VAR(info.name.sv()); }); - bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args){ + bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args) -> PyVar{ const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; if(info.mod == nullptr) return vm->None; return info.mod; @@ -1591,7 +1588,7 @@ void VM::__post_init_builtin_types(){ bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args){ if(is_tagged(args[0]) || !args[0]->is_attr_valid()) return vm->None; - return VAR(MappingProxy(args[0])); + return VAR(MappingProxy(args[0].get())); }); bind(builtins, "print(*args, sep=' ', end='\\n')", [](VM* vm, ArgsView args) { diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp index 998dded2..f44c5adb 100644 --- a/src/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -48,8 +48,8 @@ static PyVar stack_item(VM* vm, int index){ vm->__c.error = e.self(); \ return false; \ } catch(const std::exception& re){ \ - PyVar e_t = vm->_t(vm->tp_exception); \ - vm->__c.error = vm->call(e_t, VAR(re.what())); \ + PyObject* e_t = vm->_t(vm->tp_exception); \ + vm->__c.error = vm->call(e_t, VAR(re.what())).get(); \ return false; \ } @@ -76,12 +76,12 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i VM* vm = (VM*) vm_handle; PK_ASSERT_NO_ERROR() PyVar res; - PyVar mod; + PyObject* mod; PK_PROTECTED( if(module == nullptr){ mod = vm->_main; }else{ - mod = vm->_modules[module]; // may raise + mod = vm->_modules[module].get(); // may raise } CodeObject_ code = vm->compile(source, filename, (CompileMode)mode); res = vm->_exec(code, mod); @@ -342,7 +342,7 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) { // propagate_if_errored if (vm->__c.error != nullptr){ - PyVar e_obj = PK_OBJ_GET(Exception, vm->__c.error).self(); + PyObject* e_obj = vm->__c.error; vm->__c.error = nullptr; vm->_error(e_obj); return nullptr; @@ -370,8 +370,8 @@ bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) { VM* vm = (VM*) vm_handle; PK_ASSERT_NO_ERROR() PK_PROTECTED( - PyVar module = vm->new_module(name); - vm->s_data.push(module); + PyObject* module = vm->new_module(name); + vm->s_data.emplace(module); ) return true; } @@ -511,7 +511,7 @@ bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) { std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'" << std::endl; } } - vm->__c.error = vm->call(e_t, VAR(message)); + vm->__c.error = vm->call(e_t, VAR(message)).get(); return false; } @@ -524,7 +524,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) { VM* vm = (VM*) vm_handle; // no error if (vm->__c.error == nullptr) return false; - Exception& e = PK_OBJ_GET(Exception, vm->__c.error); + Exception& e = vm->__c.error->as(); if (message != nullptr) *message = strdup(e.summary().c_str()); else diff --git a/src/random.cpp b/src/random.cpp index 6ce0ab80..21350b62 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -133,7 +133,7 @@ struct Random{ gen.seed((uint32_t)count); } - static void _register(VM* vm, PyVar mod, PyVar type){ + static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){ Type cls = PK_OBJ_GET(Type, args[0]); return vm->new_object(cls); @@ -215,7 +215,7 @@ struct Random{ }; void add_module_random(VM* vm){ - PyVar mod = vm->new_module("random"); + PyObject* mod = vm->new_module("random"); vm->register_user_class(mod, "Random"); PyVar instance = vm->new_user_object(); mod->attr().set("seed", vm->getattr(instance, "seed")); diff --git a/src/str.cpp b/src/str.cpp index a6abf25d..8b31ded6 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -376,8 +376,8 @@ int utf8len(unsigned char c, bool suppress){ return cnt; } - std::map>& StrName::_interned(){ - static std::map> interned; + std::map& StrName::_interned(){ + static std::map interned; return interned; } @@ -395,17 +395,14 @@ int utf8len(unsigned char c, bool suppress){ // https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175 uint16_t index = ((_pesudo_random_index*5) + 1) & 65535; if(index == 0) throw std::runtime_error("StrName index overflow"); - _interned()[std::string(s)] = index; - if(is_valid(index)) throw std::runtime_error("StrName index conflict"); - _r_interned()[index] = std::string(s); + auto res = _r_interned().emplace(index, s); + PK_ASSERT(res.second); + s = std::string_view(res.first->second); + _interned()[s] = index; _pesudo_random_index = index; return StrName(index); } - bool StrName::is_valid(int index) { - return _r_interned().find(index) != _r_interned().end(); - } - Str SStream::str(){ // after this call, the buffer is no longer valid buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0' diff --git a/src/vm.cpp b/src/vm.cpp index 146d5572..957647f7 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -1,4 +1,5 @@ #include "pocketpy/vm.h" +#include "pocketpy/obj.h" static const char* OP_NAMES[] = { #define OPCODE(name) #name, @@ -78,6 +79,7 @@ namespace pkpy{ _ceval_on_step = nullptr; _stdout = [](const char* buf, int size) { std::cout.write(buf, size); }; _stderr = [](const char* buf, int size) { std::cerr.write(buf, size); }; + builtins = nullptr; _main = nullptr; __last_exception = nullptr; _import_handler = [](const char* name, int* out_size) -> unsigned char*{ return nullptr; }; @@ -167,7 +169,7 @@ namespace pkpy{ return false; } - PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyVar _module){ + PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module){ if(_module == nullptr) _module = _main; try { #if PK_DEBUG_PRECOMPILED_EXEC == 1 @@ -204,8 +206,8 @@ namespace pkpy{ return exec(source, "", EVAL_MODE); } - PyVar VM::new_type_object(PyVar mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt){ - PyVar obj = heap._new(tp_type, Type(_all_types.size())); + PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt){ + PyObject* obj = heap._new(tp_type, Type(_all_types.size())); const PyTypeInfo& base_info = _all_types[base]; if(!base_info.subclass_enabled){ Str error = _S("type ", base_info.name.escape(), " is not `subclass_enabled`"); @@ -399,7 +401,7 @@ namespace pkpy{ Str name_cpnt = path_cpnts.back(); path_cpnts.pop_back(); - PyVar new_mod = new_module(name_cpnt, f_join(path_cpnts)); + PyObject* new_mod = new_module(name_cpnt, f_join(path_cpnts)); _exec(code, new_mod); return new_mod; } @@ -442,7 +444,7 @@ void VM::__obj_gc_mark(PyObject* obj){ if(ti->vt._gc_mark) ti->vt._gc_mark(obj->_value_ptr(), this); if(obj->is_attr_valid()){ obj->attr().apply([this](StrName _, PyVar obj){ - PK_OBJ_MARK(obj); + if (obj.is_ptr) vm->__obj_gc_mark((obj).get()); }); } } @@ -564,7 +566,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local auto _lock = heap.gc_scope_lock(); // for safety - PyVar globals_obj = nullptr; + PyObject* globals_obj = nullptr; Dict* globals_dict = nullptr; NameDict_ locals_closure = nullptr; @@ -578,7 +580,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local }else{ check_compatible_type(globals, VM::tp_dict); // make a temporary object and copy globals into it - globals_obj = new_object(VM::tp_object); + globals_obj = new_object(VM::tp_object).get(); globals_obj->_enable_instance_dict(); globals_dict = &PK_OBJ_GET(Dict, globals); globals_dict->apply([&](PyVar k, PyVar v){ @@ -598,7 +600,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local locals_dict->apply([&](PyVar k, PyVar v){ locals_closure->set(CAST(Str&, k), v); }); - PyVar _callable = VAR(Function(__dynamic_func_decl, globals_obj, nullptr, locals_closure)); + PyObject* _callable = heap.gcnew(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure); retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp); } @@ -713,8 +715,8 @@ PyVar VM::__format_object(PyVar obj, Str spec){ return VAR(ret); } -PyVar VM::new_module(Str name, Str package) { - PyVar obj = heap._new(tp_module); +PyObject* VM::new_module(Str name, Str package) { + PyObject* obj = heap._new(tp_module); obj->attr().set(__name__, VAR(name)); obj->attr().set(__package__, VAR(package)); // convert to fullname @@ -1091,7 +1093,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){ case FuncType::GENERATOR: __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl); s_data.reset(p0); - callstack.emplace(nullptr, co, fn._module, callable, nullptr); + callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr); return __py_generator( callstack.popx(), ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals) @@ -1104,7 +1106,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){ }; // simple or normal - callstack.emplace(p0, co, fn._module, callable, args.begin()); + callstack.emplace(p0, co, fn._module, callable.get(), args.begin()); if(op_call) return PY_OP_CALL; return __run_top_frame(); /*****************_py_call*****************/ @@ -1357,22 +1359,26 @@ void VM::setattr(PyVar obj, StrName name, PyVar value){ obj->attr().set(name, value); } -PyVar VM::bind_func(PyVar obj, StrName name, int argc, NativeFuncC fn, any userdata, BindType bt) { - PyVar nf = VAR(NativeFunc(fn, argc, std::move(userdata))); +PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata, BindType bt) { + PyObject* nf = heap.gcnew(tp_native_func, fn, argc, std::move(userdata)); switch(bt){ case BindType::DEFAULT: break; - case BindType::STATICMETHOD: nf = VAR(StaticMethod(nf)); break; - case BindType::CLASSMETHOD: nf = VAR(ClassMethod(nf)); break; + case BindType::STATICMETHOD: + nf = heap.gcnew(tp_staticmethod, nf); + break; + case BindType::CLASSMETHOD: + nf = heap.gcnew(tp_classmethod, nf); + break; } if(obj != nullptr) obj->attr().set(name, nf); return nf; } -PyVar VM::bind(PyVar obj, const char* sig, NativeFuncC fn, any userdata, BindType bt){ +PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, any userdata, BindType bt){ return bind(obj, sig, nullptr, fn, std::move(userdata), bt); } -PyVar VM::bind(PyVar obj, const char* sig, const char* docstring, NativeFuncC fn, any userdata, BindType bt){ +PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, any userdata, BindType bt){ CodeObject_ co; try{ // fn(a, b, *c, d=1) -> None @@ -1385,14 +1391,14 @@ PyVar VM::bind(PyVar obj, const char* sig, const char* docstring, NativeFuncC fn } FuncDecl_ decl = co->func_decls[0]; decl->docstring = docstring; - PyVar f_obj = VAR(NativeFunc(fn, decl, std::move(userdata))); + PyObject* f_obj = heap.gcnew(tp_native_func, fn, decl, std::move(userdata)); switch(bt){ case BindType::STATICMETHOD: - f_obj = VAR(StaticMethod(f_obj)); + f_obj = heap.gcnew(tp_staticmethod, f_obj); break; case BindType::CLASSMETHOD: - f_obj = VAR(ClassMethod(f_obj)); + f_obj = heap.gcnew(tp_classmethod, f_obj); break; case BindType::DEFAULT: break; @@ -1401,14 +1407,14 @@ PyVar VM::bind(PyVar obj, const char* sig, const char* docstring, NativeFuncC fn return f_obj; } -PyVar VM::bind_property(PyVar obj, const char* name, NativeFuncC fget, NativeFuncC fset){ +PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, NativeFuncC fset){ PK_ASSERT(is_type(obj, tp_type)); std::string_view name_sv(name); int pos = name_sv.find(':'); if(pos > 0) name_sv = name_sv.substr(0, pos); PyVar _0 = new_object(tp_native_func, fget, 1); PyVar _1 = vm->None; if(fset != nullptr) _1 = new_object(tp_native_func, fset, 2); - PyVar prop = VAR(Property(_0, _1)); + PyObject* prop = heap.gcnew(tp_property, _0, _1); obj->attr().set(StrName(name_sv), prop); return prop; } @@ -1474,14 +1480,14 @@ StrName _type_name(VM *vm, Type type){ void VM::bind__getitem__(Type type, PyVar (*f)(VM*, PyVar, PyVar)){ _all_types[type].m__getitem__ = f; bind_func(type, __getitem__, 2, [](VM* vm, ArgsView args){ - return lambda_get_userdata(args.begin())(vm, args[0], args[1]); + return lambda_get_userdata(args.begin())(vm, args[0], args[1]); }, f); } void VM::bind__setitem__(Type type, void (*f)(VM*, PyVar, PyVar, PyVar)){ _all_types[type].m__setitem__ = f; bind_func(type, __setitem__, 3, [](VM* vm, ArgsView args){ - lambda_get_userdata(args.begin())(vm, args[0], args[1], args[2]); + lambda_get_userdata(args.begin())(vm, args[0], args[1], args[2]); return vm->None; }, f); } @@ -1489,7 +1495,7 @@ void VM::bind__setitem__(Type type, void (*f)(VM*, PyVar, PyVar, PyVar)){ void VM::bind__delitem__(Type type, void (*f)(VM*, PyVar, PyVar)){ _all_types[type].m__delitem__ = f; bind_func(type, __delitem__, 2, [](VM* vm, ArgsView args){ - lambda_get_userdata(args.begin())(vm, args[0], args[1]); + lambda_get_userdata(args.begin())(vm, args[0], args[1]); return vm->None; }, f); } @@ -1505,7 +1511,7 @@ PyVar VM::__pack_next_retval(unsigned n){ void VM::bind__next__(Type type, unsigned (*f)(VM*, PyVar)){ _all_types[type].op__next__ = f; bind_func(type, __next__, 1, [](VM* vm, ArgsView args){ - int n = lambda_get_userdata(args.begin())(vm, args[0]); + int n = lambda_get_userdata(args.begin())(vm, args[0]); return vm->__pack_next_retval(n); }, f); } @@ -1792,7 +1798,7 @@ void Function::_gc_mark(VM* vm) const{ decl->_gc_mark(vm); if(_closure){ _closure->apply([=](StrName _, PyVar obj){ - PK_OBJ_MARK(obj); + vm->obj_gc_mark(obj); }); } } @@ -1803,67 +1809,67 @@ void NativeFunc::_gc_mark(VM* vm) const{ void FuncDecl::_gc_mark(VM* vm) const{ code->_gc_mark(vm); - for(int i=0; iobj_gc_mark(kwargs[i].value); } void List::_gc_mark(VM* vm) const{ - for(PyVar obj: *this) PK_OBJ_MARK(obj); + for(PyVar obj: *this) vm->obj_gc_mark(obj); } void Tuple::_gc_mark(VM* vm) const{ - for(PyVar obj: *this) PK_OBJ_MARK(obj); + for(PyVar obj: *this) vm->obj_gc_mark(obj); } void MappingProxy::_gc_mark(VM* vm) const{ - PK_OBJ_MARK(obj); + vm->__obj_gc_mark(obj); } void BoundMethod::_gc_mark(VM* vm) const{ - PK_OBJ_MARK(func); - PK_OBJ_MARK(self); + vm->obj_gc_mark(func); + vm->obj_gc_mark(self); } void StarWrapper::_gc_mark(VM* vm) const{ - PK_OBJ_MARK(obj); + vm->obj_gc_mark(obj); } void StaticMethod::_gc_mark(VM* vm) const{ - PK_OBJ_MARK(func); + vm->obj_gc_mark(func); } void ClassMethod::_gc_mark(VM* vm) const{ - PK_OBJ_MARK(func); + vm->obj_gc_mark(func); } void Property::_gc_mark(VM* vm) const{ - PK_OBJ_MARK(getter); - PK_OBJ_MARK(setter); + vm->obj_gc_mark(getter); + vm->obj_gc_mark(setter); } void Slice::_gc_mark(VM* vm) const{ - PK_OBJ_MARK(start); - PK_OBJ_MARK(stop); - PK_OBJ_MARK(step); + vm->obj_gc_mark(start); + vm->obj_gc_mark(stop); + vm->obj_gc_mark(step); } void Super::_gc_mark(VM* vm) const{ - PK_OBJ_MARK(first); + vm->obj_gc_mark(first); } void Frame::_gc_mark(VM* vm) const { - PK_OBJ_MARK(_module); + vm->obj_gc_mark(_module); co->_gc_mark(vm); // Frame could be stored in a generator, so mark _callable for safety - if(_callable != nullptr) PK_OBJ_MARK(_callable); + vm->obj_gc_mark(_callable); } void ManagedHeap::mark() { for(PyObject* obj: _no_gc) vm->__obj_gc_mark(obj); vm->callstack.apply([this](Frame& frame){ frame._gc_mark(vm); }); for(auto [_, co]: vm->__cached_codes) co->_gc_mark(vm); - if(vm->__last_exception) PK_OBJ_MARK(vm->__last_exception); - if(vm->__curr_class) PK_OBJ_MARK(vm->__curr_class); - if(vm->__c.error != nullptr) PK_OBJ_MARK(vm->__c.error); + vm->obj_gc_mark(vm->__last_exception); + vm->obj_gc_mark(vm->__curr_class); + vm->obj_gc_mark(vm->__c.error); vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end()); if(_gc_marker_ex) _gc_marker_ex(vm); } @@ -1880,13 +1886,13 @@ void ManagedHeap::_delete(PyObject* obj){ void Dict::_gc_mark(VM* vm) const{ apply([vm](PyVar k, PyVar v){ - PK_OBJ_MARK(k); - PK_OBJ_MARK(v); + vm->obj_gc_mark(k); + vm->obj_gc_mark(v); }); } void CodeObject::_gc_mark(VM* vm) const { - for(PyVar v : consts) PK_OBJ_MARK(v); + for(PyVar v : consts) vm->obj_gc_mark(v); for(auto& decl: func_decls) decl->_gc_mark(vm); }