From 19ed0fdaf5ec39aeb58c9cf0e8c59cc9cbf1b67f Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Mon, 24 Jun 2024 00:06:31 +0800 Subject: [PATCH] remove `*.cpp` --- .github/workflows.zip | Bin 0 -> 2482 bytes .github/workflows/main.yml | 204 -- .github/workflows/website.yml | 42 - compile_flags.txt | 6 +- include/pocketpy.h | 2 +- include/pocketpy.hpp | 2 +- include/pocketpy/common/str.h | 1 + include/pocketpy/common/str.hpp | 404 ---- include/pocketpy/common/strname.h | 12 +- include/pocketpy/common/traits.hpp | 46 - include/pocketpy/common/types.hpp | 37 - include/pocketpy/common/utils.h | 2 + include/pocketpy/common/vector.hpp | 459 ----- include/pocketpy/interpreter/bindings.hpp | 229 --- .../interpreter/{ceval.hpp => ceval.h} | 0 include/pocketpy/interpreter/cffi.hpp | 105 - include/pocketpy/interpreter/frame.h | 102 + include/pocketpy/interpreter/frame.hpp | 214 -- include/pocketpy/interpreter/gc.h | 11 +- include/pocketpy/interpreter/iter.hpp | 86 - include/pocketpy/interpreter/profiler.hpp | 44 - include/pocketpy/interpreter/vm.h | 90 +- include/pocketpy/interpreter/vm.hpp | 138 +- include/pocketpy/modules/array2d.hpp | 9 - include/pocketpy/modules/base64.hpp | 9 - include/pocketpy/modules/csv.hpp | 9 - include/pocketpy/modules/dataclasses.hpp | 9 - include/pocketpy/modules/easing.hpp | 9 - include/pocketpy/modules/io.hpp | 9 - include/pocketpy/modules/linalg.hpp | 215 -- include/pocketpy/modules/modules.hpp | 18 - include/pocketpy/modules/random.hpp | 9 - include/pocketpy/objects/base.h | 33 +- include/pocketpy/objects/base.hpp | 85 - include/pocketpy/objects/builtins.hpp | 141 -- include/pocketpy/objects/codeobject.hpp | 66 - include/pocketpy/objects/dict.hpp | 98 - include/pocketpy/objects/error.h | 4 +- include/pocketpy/objects/error.hpp | 64 - include/pocketpy/objects/namedict.h | 2 +- include/pocketpy/objects/namedict.hpp | 104 - include/pocketpy/objects/object.h | 19 +- include/pocketpy/objects/object.hpp | 37 - include/pocketpy/objects/tuplelist.hpp | 77 - .../pocketpy/{objects/public.h => pocketpy.h} | 24 +- include/pocketpy/pocketpy.hpp | 25 - include/pocketpy/pocketpy_c.h | 107 - include/pocketpy/xmacros/smallmap.h | 13 + include/pocketpy_c.h | 3 - src/common/strname.c | 112 +- src/error.c | 4 +- src/interpreter/{ceval.cpp => ceval.c} | 12 +- src/interpreter/cffi.cpp | 289 --- src/interpreter/frame.c | 133 ++ src/interpreter/frame.cpp | 122 -- src/interpreter/gc.c | 28 +- src/interpreter/iter.cpp | 135 -- src/interpreter/profiler.cpp | 131 -- src/interpreter/vm.c | 187 +- src/interpreter/vm.cpp | 75 +- src/modules/array2d.cpp | 406 ---- src/modules/base64.cpp | 175 -- src/modules/csv.cpp | 87 - src/modules/dataclasses.cpp | 120 -- src/modules/easing.cpp | 218 -- src/modules/io.cpp | 247 --- src/modules/linalg.cpp | 717 ------- src/modules/modules.cpp | 355 ---- src/modules/random.cpp | 225 --- src/objects/base.c | 8 +- src/objects/namedict.c | 2 +- src/objects/public.cpp | 21 - src/objects/tuplelist.cpp | 56 - src/{public.c => pocketpy.c} | 17 +- src/pocketpy.cpp | 1767 ----------------- src/pocketpy_c.cpp | 575 ------ src2/main.c | 42 + src2/pocketpy_c.c | 265 --- 78 files changed, 808 insertions(+), 9157 deletions(-) create mode 100644 .github/workflows.zip delete mode 100644 .github/workflows/main.yml delete mode 100644 .github/workflows/website.yml delete mode 100644 include/pocketpy/common/str.hpp delete mode 100644 include/pocketpy/common/traits.hpp delete mode 100644 include/pocketpy/common/types.hpp delete mode 100644 include/pocketpy/common/vector.hpp delete mode 100644 include/pocketpy/interpreter/bindings.hpp rename include/pocketpy/interpreter/{ceval.hpp => ceval.h} (100%) delete mode 100644 include/pocketpy/interpreter/cffi.hpp create mode 100644 include/pocketpy/interpreter/frame.h delete mode 100644 include/pocketpy/interpreter/frame.hpp delete mode 100644 include/pocketpy/interpreter/iter.hpp delete mode 100644 include/pocketpy/interpreter/profiler.hpp delete mode 100644 include/pocketpy/modules/array2d.hpp delete mode 100644 include/pocketpy/modules/base64.hpp delete mode 100644 include/pocketpy/modules/csv.hpp delete mode 100644 include/pocketpy/modules/dataclasses.hpp delete mode 100644 include/pocketpy/modules/easing.hpp delete mode 100644 include/pocketpy/modules/io.hpp delete mode 100644 include/pocketpy/modules/linalg.hpp delete mode 100644 include/pocketpy/modules/modules.hpp delete mode 100644 include/pocketpy/modules/random.hpp delete mode 100644 include/pocketpy/objects/base.hpp delete mode 100644 include/pocketpy/objects/builtins.hpp delete mode 100644 include/pocketpy/objects/codeobject.hpp delete mode 100644 include/pocketpy/objects/dict.hpp delete mode 100644 include/pocketpy/objects/error.hpp delete mode 100644 include/pocketpy/objects/namedict.hpp delete mode 100644 include/pocketpy/objects/object.hpp delete mode 100644 include/pocketpy/objects/tuplelist.hpp rename include/pocketpy/{objects/public.h => pocketpy.h} (59%) delete mode 100644 include/pocketpy/pocketpy.hpp delete mode 100644 include/pocketpy/pocketpy_c.h delete mode 100644 include/pocketpy_c.h rename src/interpreter/{ceval.cpp => ceval.c} (99%) delete mode 100644 src/interpreter/cffi.cpp create mode 100644 src/interpreter/frame.c delete mode 100644 src/interpreter/frame.cpp delete mode 100644 src/interpreter/iter.cpp delete mode 100644 src/interpreter/profiler.cpp delete mode 100644 src/modules/array2d.cpp delete mode 100644 src/modules/base64.cpp delete mode 100644 src/modules/csv.cpp delete mode 100644 src/modules/dataclasses.cpp delete mode 100644 src/modules/easing.cpp delete mode 100644 src/modules/io.cpp delete mode 100644 src/modules/linalg.cpp delete mode 100644 src/modules/modules.cpp delete mode 100644 src/modules/random.cpp delete mode 100644 src/objects/public.cpp delete mode 100644 src/objects/tuplelist.cpp rename src/{public.c => pocketpy.c} (67%) delete mode 100644 src/pocketpy.cpp delete mode 100644 src/pocketpy_c.cpp create mode 100644 src2/main.c delete mode 100644 src2/pocketpy_c.c diff --git a/.github/workflows.zip b/.github/workflows.zip new file mode 100644 index 0000000000000000000000000000000000000000..70028bb0e53688144c63c146bba38cf7b7a77c7e GIT binary patch literal 2482 zcmZ`*c{mj87N0R>COcs=vXnKuk=-b*Bf!J`( z%p}e?&rm)&!46E*ye8vXIQY=MI%8bzoyMxupa61cA#g;`vl|ZQb&B|gTXzp232&pek{2uTQ1q@=lOO{Yr2AlM?h|Z8eMg2fqLzojaEyPE zFTEOjcBzG5nF^QQ5i$2}3__720-A!p<4=QTyO$o&9~Q9kn#w^6AgZmY0n*FC_Q&B0 zg6ZC3W)c}L>+$N7#zjwPggWEwif0|y&m>IsN;EtJJ@;yxM76SP%s+NuMI+d)d7}|p zB@O)qCQh6_eK&;>t9BjAT*5B%%{+Hll}lLBwvV}R&nLk9eXYf&P|LVGYI2>n5U|KK zK-$QR&#!=mu&z&VGcwrLY2;8}ZG=t}R5z=7T#U7kLrIA2&U9-4z<7qzg_mRV{6STR z%3TbMF5l=OgI%wG&{S8jv#2BlBJ&M*gcV&Z0k?qI6anv%BS&=5)HX#>DUCS{$Ae3V&lVkoPW)|sBGf|!)N&u*vq$%V7`J&O{=4i(aW$4K4W z5P!!(r8bA%QaB+oqWwHS=~ekyXI$^xrXs)5velI$rCw-jPp*rixn@oz<>evU#qf91 zW@|G1r^FYy=kBK&R>}$WZj?o0t4iOtrN+HU?rdP`PRNKBFug*wrRG^0Y+oAgsdRWi ziodAaZl0hHqy;!vhj(!&(8*aJ4{KQ;IA4X6jG<0b(@Kij&Pu5?$AaG78wGo+>cF^VT6FreR>z>tSBXaB_=$7I z^kyC*Ke2Z&W=Nd9vbLxtm^LEOKL)=}uyy!66Z<6q&RSS>Uu{i%^OdJC#Edw-4yg(E z5LCaMIzINek1^VjgYcRi7*b+q_ra_Q8Bm=cD=-`CwzGBYs#wdXz1_5(E3J#%zMcy= zxr^#(peu9RP#09^y9s3TGBjKk$G9P?+%p8I1$^a>TLPC!q(EO2*R@|d5J zpKUyA`O?%~v?(!Yu1M?==PPBk^{m4PBIEXHy^SKL?1;C?pa}u&jHiU2o)b@b(L?^y z-36D_;naKzEhxsIad#&&v`+L$>WEGb>B7lWRn`UiQ+$>WN*_KVjGH@C(bX1xE3ERo~f|VB=%4V2N#O5 z7HonWL&C>HnIeIe5Gy`Wu{)D|uCkfs^L;B_KozsHkUQ|IcT+47`_y}V;JSHX6=sy z2g^v_*6vKg_y!n8;osSo-CRn~_)~1#Hm$z;NO>*2TBT<8vAXSv{^AKNLnbNE{>cXe zhq0F?5rSM~kg`vV5{yd+%SRTcic76mbd-v)b|1c>bKfNmRK2D<3U%8z*G^(GF>5ti>AXYR zV-m72I7;$WE+yp#Z*}t45#~UBV=}mEh*f`7T`unE8*wzZZpJLzypaeS0*-gZ4M2j! zPwBb5lQXnx`C6<8A6D$~k&i%=p+hX()0gSAY*T z78oUlHJ0fGG@p}hs-N4%_L}z2y^VDIQ&}=fg;?cwJkbv`D&(9A)PnitamA%*bSfa{ zp7VihKo^jq=uy8!yl&*SSVrqfG%U#tbrj9jCFNm`6yTryG-Wq}xgXD+|JatYOyNbH zKw?TD8S-K_X`I%`vp3o$dI%{gs@47Sbq$Zy7-ZkWEs-$%~S77x@EQNQ)kEa zx^$>a(#JEEjhquJu+68KOiNp64Upfh5gG0yGmUTXgq?;LE|JgF72$C5 zO&spq0iO}&2gIqAr{|Xby2QA2KB+n0Uq~ToFzbq&(|l>`>TW$Dv4<(i6=Y0Go(>k9 z!Ju6Qvu3?~?$BE}Z!T?5wP}2}-Z(vTbFFe`K%E?2s-fg-4*9YH<({n5_{ejknf@=l z#n#u-6}Gc*gh>-FdgtqE3TZ6~OB~i(npofl8yDNI$+B#0bZ|vs3bS*K(u2a;2A|j% zNGw(qv@jx8VOA(0i#Xt)WQWw=)9)Maf41L5$U%U_4-5!^0t){MabPrm2DZog!Q$IL z10gj5UE~_tUPvU~p`9K7%S8&6|ii~s-t literal 0 HcmV?d00001 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index d9b5a246..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,204 +0,0 @@ -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 - 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/x86_64 - python cmake_build.py - cp main.exe output/x86_64 - cp pocketpy.dll output/x86_64 - - uses: actions/upload-artifact@v4 - with: - name: windows - 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 and Test - run: | - mkdir -p output/x86_64 - python cmake_build.py - python scripts/run_tests.py - cp main output/x86_64 - cp libpocketpy.so output/x86_64 - env: - CXX: clang++ - CC: clang - - uses: actions/upload-artifact@v4 - with: - name: linux - 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 output - # xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO - # cp -r build/Release/pocketpy.bundle output - # - uses: actions/upload-artifact@v4 - # with: - # name: macos - # 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/arm64-v8a - mkdir -p output/armeabi-v7a - mkdir -p output/x86_64 - - cp build/android/arm64-v8a/libpocketpy.so output/arm64-v8a - cp build/android/armeabi-v7a/libpocketpy.so output/armeabi-v7a - cp build/android/x86_64/libpocketpy.so output/x86_64 - env: - ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} - - uses: actions/upload-artifact@v4 - with: - name: android - 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 - cp -r build/pocketpy.xcframework output/pocketpy.xcframework - - uses: actions/upload-artifact@v4 - with: - name: ios - path: output - - merge: - runs-on: ubuntu-latest - needs: [ build_win32, build_linux, build_darwin, build_android, build_ios ] - steps: - - name: "Create output directory" - run: "mkdir $GITHUB_WORKSPACE/output" - - - name: "Merge win32" - uses: actions/download-artifact@v4.1.7 - with: - name: windows - path: $GITHUB_WORKSPACE/output/windows - - - name: "Merge linux" - uses: actions/download-artifact@v4.1.7 - with: - name: linux - path: $GITHUB_WORKSPACE/output/linux - - # - name: "Merge darwin" - # uses: actions/download-artifact@v4.1.7 - # with: - # name: macos - # path: $GITHUB_WORKSPACE/output/macos - - - name: "Merge android" - uses: actions/download-artifact@v4.1.7 - with: - name: android - path: $GITHUB_WORKSPACE/output/android - - - name: "Merge ios" - uses: actions/download-artifact@v4.1.7 - with: - name: ios - path: $GITHUB_WORKSPACE/output/ios - - - name: "Upload merged artifact" - uses: actions/upload-artifact@v4.3.3 - with: - name: all-in-one - path: $GITHUB_WORKSPACE/output diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml deleted file mode 100644 index 7d80a048..00000000 --- a/.github/workflows/website.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: website - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -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' diff --git a/compile_flags.txt b/compile_flags.txt index a6a2aa66..7484a44b 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1,9 +1,9 @@ -Wall -W* --xc++ +-xc --std=c++17 +-std=c11 -Iinclude/ -I3rd/cjson/include/ --I3rd/lua_bridge/include/ + diff --git a/include/pocketpy.h b/include/pocketpy.h index b200f148..51c3fa13 100644 --- a/include/pocketpy.h +++ b/include/pocketpy.h @@ -1,3 +1,3 @@ #pragma once -#include "pocketpy/pocketpy.hpp" +#include "pocketpy/pocketpy.h" diff --git a/include/pocketpy.hpp b/include/pocketpy.hpp index b200f148..51c3fa13 100644 --- a/include/pocketpy.hpp +++ b/include/pocketpy.hpp @@ -1,3 +1,3 @@ #pragma once -#include "pocketpy/pocketpy.hpp" +#include "pocketpy/pocketpy.h" diff --git a/include/pocketpy/common/str.h b/include/pocketpy/common/str.h index ac75d29c..3866e013 100644 --- a/include/pocketpy/common/str.h +++ b/include/pocketpy/common/str.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "pocketpy/common/vector.h" #include "pocketpy/common/utils.h" diff --git a/include/pocketpy/common/str.hpp b/include/pocketpy/common/str.hpp deleted file mode 100644 index 6e356746..00000000 --- a/include/pocketpy/common/str.hpp +++ /dev/null @@ -1,404 +0,0 @@ -#pragma once - -#include "pocketpy/common/sstream.h" -#include "pocketpy/common/utils.h" -#include "pocketpy/common/memorypool.h" -#include "pocketpy/common/vector.h" -#include "pocketpy/common/vector.hpp" -#include "pocketpy/common/str.h" -#include "pocketpy/common/strname.h" - -#include -#include -#include -#include - -namespace pkpy { - -struct Str: pkpy_Str { - bool is_inlined() const { return is_sso; } - - Str(){ - pkpy_Str__ctor2(this, "", 0); - } - - Str(pkpy_Str&& s){ - std::memcpy(this, &s, sizeof(pkpy_Str)); - } - - Str(const std::string& s){ - pkpy_Str__ctor2(this, s.data(), s.size()); - } - - Str(std::string_view s){ - pkpy_Str__ctor2(this, s.data(), s.size()); - } - - Str(const char* s){ - pkpy_Str__ctor2(this, s, strlen(s)); - } - - Str(const char* s, int len){ - pkpy_Str__ctor2(this, s, len); - } - - Str(pair detached) { - this->size = detached.second; - this->is_ascii = c11__isascii(detached.first, detached.second); - this->is_sso = false; - this->_ptr = detached.first; - assert(_ptr[size] == '\0'); - } - - Str(const Str& other){ - pkpy_Str__ctor2(this, pkpy_Str__data(&other), other.size); - } - - Str(Str&& other){ - std::memcpy(this, &other, sizeof(pkpy_Str)); - other.size = 0; - other.is_sso = true; - } - - operator std::string_view () const { return sv(); } - const char* begin() const { return pkpy_Str__data(this); } - const char* end() const { return pkpy_Str__data(this) + size; } - int length() const { return size; } - char operator[] (int idx) const { return pkpy_Str__data(this)[idx]; } - bool empty() const { return size == 0; } - size_t hash() const { return std::hash()(sv()); } - - Str& operator= (const Str& other){ - pkpy_Str__dtor(this); - pkpy_Str__ctor2(this, pkpy_Str__data(&other), other.size); - return *this; - } - - Str operator+ (const Str& other) const{ - return pkpy_Str__concat(this, &other); - } - - Str operator+ (const char* other) const{ - return pkpy_Str__concat2(this, other, strlen(other)); - } - - friend Str operator+ (const char* self, const Str& other){ - pkpy_Str tmp; - pkpy_Str__ctor2(&tmp, self, strlen(self)); - pkpy_Str retval = pkpy_Str__concat(&tmp, &other); - pkpy_Str__dtor(&tmp); - return retval; - } - - bool operator== (const std::string_view other) const{ - int res = pkpy_Str__cmp2(this, other.data(), other.size()); - return res == 0; - } - - bool operator!= (const std::string_view other) const{ - int res = pkpy_Str__cmp2(this, other.data(), other.size()); - return res != 0; - } - - bool operator< (const std::string_view other) const{ - int res = pkpy_Str__cmp2(this, other.data(), other.size()); - return res < 0; - } - - friend bool operator< (const std::string_view other, const Str& str){ - int res = pkpy_Str__cmp2(&str, other.data(), other.size()); - return res > 0; - } - - bool operator== (const char* p) const{ - int res = pkpy_Str__cmp2(this, p, strlen(p)); - return res == 0; - } - - bool operator!= (const char* p) const{ - int res = pkpy_Str__cmp2(this, p, strlen(p)); - return res != 0; - } - - bool operator== (const Str& other) const{ - return pkpy_Str__cmp(this, &other) == 0; - } - bool operator!= (const Str& other) const{ - return pkpy_Str__cmp(this, &other) != 0; - } - bool operator< (const Str& other) const{ - return pkpy_Str__cmp(this, &other) < 0; - } - bool operator> (const Str& other) const{ - return pkpy_Str__cmp(this, &other) > 0; - } - bool operator<= (const Str& other) const{ - return pkpy_Str__cmp(this, &other) <= 0; - } - bool operator>= (const Str& other) const{ - return pkpy_Str__cmp(this, &other) >= 0; - } - - ~Str(){ - pkpy_Str__dtor(this); - } - - friend std::ostream& operator<< (std::ostream& os, const Str& self){ - os.write(pkpy_Str__data(&self), self.size); - return os; - } - - const char* c_str() const { return pkpy_Str__data(this); } - - std::string_view sv() const { - return std::string_view(pkpy_Str__data(this), size); - } - - std::string str() const { - return std::string(pkpy_Str__data(this), size); - } - - Str slice(int start, int stop) const{ - return pkpy_Str__slice2(this, start, stop); - } - - Str slice(int start) const{ - return pkpy_Str__slice(this, start); - } - - Str substr(int start) const{ - return pkpy_Str__slice(this, start); - } - - Str strip(bool left, bool right, const Str& chars) const{ - return pkpy_Str__strip2(this, left, right, &chars); - } - - Str strip(bool left = true, bool right = true) const{ - return pkpy_Str__strip(this, left, right); - } - - Str lstrip() const { return strip(true, false); } - - Str rstrip() const { return strip(false, true); } - - Str lower() const{ - return pkpy_Str__lower(this); - } - Str upper() const{ - return pkpy_Str__upper(this); - } - Str replace(char old, char new_) const{ - return pkpy_Str__replace(this, old, new_); - } - Str replace(const Str& old, const Str& new_) const{ - return pkpy_Str__replace2(this, &old, &new_); - } - - Str escape(char quote='\'') const{ - return pkpy_Str__escape(this, quote); - } - - vector split(const Str& sep) const{ - c11_vector/* T=c11_string */ res = pkpy_Str__split2(this, &sep); - vector retval(res.count); - for(int i = 0; i < res.count; i++){ - c11_string tmp = c11__getitem(c11_string, &res, i); - retval[i] = std::string_view(tmp.data, tmp.size); - } - c11_vector__dtor(&res); - return retval; - } - - vector split(char sep) const{ - c11_vector/* T=c11_string */ res = pkpy_Str__split(this, sep); - vector retval(res.count); - for(int i = 0; i < res.count; i++){ - c11_string tmp = c11__getitem(c11_string, &res, i); - retval[i] = std::string_view(tmp.data, tmp.size); - } - c11_vector__dtor(&res); - return retval; - } - - int index(const Str& sub, int start = 0) const{ - return pkpy_Str__index(this, &sub, start); - } - - int count(const Str& sub) const{ - return pkpy_Str__count(this, &sub); - } - - /*************unicode*************/ - int _unicode_index_to_byte(int i) const{ - return pkpy_Str__unicode_index_to_byte(this, i); - } - - int _byte_index_to_unicode(int n) const{ - return pkpy_Str__byte_index_to_unicode(this, n); - } - - Str u8_getitem(int i) const{ - return pkpy_Str__u8_getitem(this, i); - } - - Str u8_slice(int start, int stop, int step) const{ - return pkpy_Str__u8_slice(this, start, stop, step); - } - - int u8_length() const{ - return pkpy_Str__u8_length(this); - } -}; - -struct StrName { - uint16_t index; - - StrName() : index(0) {} - - StrName(uint16_t index) : index(index) {} - - StrName(const char* s) : index(get(s).index) {} - - StrName(const Str& s) : index(get(s.sv()).index) {} - - bool empty() const { return index == 0; } - - Str escape() const { return Str(sv()).escape(); } - - bool operator== (const StrName& other) const noexcept { return this->index == other.index; } - - bool operator!= (const StrName& other) const noexcept { return this->index != other.index; } - - bool operator< (const StrName& other) const noexcept { return sv() < other.sv(); } - - bool operator> (const StrName& other) const noexcept { return sv() > other.sv(); } - - inline static StrName get(std::string_view s){ - uint16_t index = pkpy_StrName__map2({s.data(), (int)s.size()}); - return StrName(index); - } - - std::string_view sv() const{ - return pkpy_StrName__rmap(index); - } - - const char* c_str() const{ - return pkpy_StrName__rmap(index); - } -}; - -struct SStream: pk_SStream { - PK_ALWAYS_PASS_BY_POINTER(SStream) - - int _precision = -1; - bool _submited = false; - bool empty() const { return data.count == 0; } - - void setprecision(int precision) { _precision = precision; } - - SStream() { - pk_SStream__ctor(this); - } - - SStream(int guess_size) { c11_vector__reserve(&data, guess_size); } - - ~SStream() { - // in case of error - if(!_submited) pk_SStream__dtor(this); - } - - Str str(){ - assert(!_submited); - _submited = true; - return pk_SStream__submit(this); - } - - SStream& operator<< (const Str& val){ - pk_SStream__write_Str(this, &val); - return *this; - } - - SStream& operator<< (const char* val){ - pk_SStream__write_cstr(this, val); - return *this; - } - - SStream& operator<< (int val){ - pk_SStream__write_int(this, val); - return *this; - } - - SStream& operator<< (size_t val){ - // size_t could overflow int64, but nevermind... - pk_SStream__write_i64(this, val); - return *this; - } - - SStream& operator<< (i64 val){ - pk_SStream__write_i64(this, val); - return *this; - } - - SStream& operator<< (f64 val){ - pk_SStream__write_double(this, val, _precision); - return *this; - } - - SStream& operator<< (const std::string& val){ - pk_SStream__write_cstrn(this, val.data(), val.size()); - return *this; - } - - SStream& operator<< (std::string_view val){ - pk_SStream__write_cstrn(this, val.data(), val.size()); - return *this; - } - - SStream& operator<< (c11_string val){ - pk_SStream__write_cstrn(this, val.data, val.size); - return *this; - } - - SStream& operator<< (char val){ - pk_SStream__write_char(this, val); - return *this; - } - - SStream& operator<< (StrName name){ - std::string_view sv = name.sv(); - pk_SStream__write_cstrn(this, sv.data(), sv.size()); - return *this; - } - - void write_hex(unsigned char val, bool non_zero = false){ - pk_SStream__write_hex(this, val, non_zero); - } - - void write_ptr(void* p){ - pk_SStream__write_ptr(this, p); - } -}; - -#ifdef _S -#undef _S -#endif - -template -Str _S(Args&&... args) { - SStream ss; - (ss << ... << args); - return ss.str(); -} - -struct CString { - const char* ptr; - - CString(const char* ptr) : ptr(ptr) {} - - operator const char* () const { return ptr; } -}; - -#define DEF_SNAME(name) const static StrName name(#name) - -} // namespace pkpy diff --git a/include/pocketpy/common/strname.h b/include/pocketpy/common/strname.h index 0a3583d7..10991d41 100644 --- a/include/pocketpy/common/strname.h +++ b/include/pocketpy/common/strname.h @@ -7,14 +7,14 @@ extern "C" { #endif -typedef uint16_t pkpy_StrName; +typedef uint16_t StrName; -uint16_t pkpy_StrName__map(const char*); -uint16_t pkpy_StrName__map2(c11_string); -const char* pkpy_StrName__rmap(uint16_t index); +uint16_t pk_StrName__map(const char*); +uint16_t pk_StrName__map2(c11_string); +const char* pk_StrName__rmap(uint16_t index); -void pkpy_StrName__initialize(); -void pkpy_StrName__finalize(); +void pk_StrName__initialize(); +void pk_StrName__finalize(); #ifdef __cplusplus } diff --git a/include/pocketpy/common/traits.hpp b/include/pocketpy/common/traits.hpp deleted file mode 100644 index 0110a4ff..00000000 --- a/include/pocketpy/common/traits.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include - -namespace pkpy { - -// is_pod_v<> for c++17 and c++20 -template -constexpr inline bool is_pod_v = std::is_trivially_copyable_v && std::is_standard_layout_v; - -// https://en.cppreference.com/w/cpp/types/is_integral -template -constexpr inline bool is_integral_v = !std::is_same_v && std::is_integral_v; - -template -constexpr inline bool is_floating_point_v = std::is_same_v || std::is_same_v; - -// by default, only `int` and `float` enable SSO -// users can specialize this template to enable SSO for other types -// SSO types cannot have instance dict -template -constexpr inline bool is_sso_v = is_integral_v || is_floating_point_v; - -template -using obj_get_t = T&; - -template -constexpr inline bool is_trivially_relocatable_v = - std::is_trivially_copyable_v && std::is_trivially_destructible_v; - -template -struct has_gc_marker : std::false_type {}; - -template -struct has_gc_marker> : std::true_type {}; - -template -constexpr inline int py_sizeof = 16 + sizeof(T); - -#define PK_ALWAYS_PASS_BY_POINTER(T) \ - T(const T&) = delete; \ - T& operator= (const T&) = delete; \ - T(T&&) = delete; \ - T& operator= (T&&) = delete; - -} // namespace pkpy diff --git a/include/pocketpy/common/types.hpp b/include/pocketpy/common/types.hpp deleted file mode 100644 index 352ae400..00000000 --- a/include/pocketpy/common/types.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -namespace pkpy { - -using i64 = int64_t; // always 64-bit -using f64 = double; // always 64-bit - -static_assert(sizeof(i64) == 8); -static_assert(sizeof(f64) == 8); - -// Explicitly allow copying if copy constructor is deleted -struct explicit_copy_t { - explicit explicit_copy_t() = default; -}; - -template -struct pair { - K first; - V second; - pair(K first, V second) : first(first), second(second) {} -}; - -// Dummy types -struct DummyInstance {}; - -struct DummyModule {}; - -struct NoReturn {}; - -// Forward declarations -struct PyObject; -struct Frame; -class VM; - -}; // namespace pkpy diff --git a/include/pocketpy/common/utils.h b/include/pocketpy/common/utils.h index 3a8399a1..4e903fc7 100644 --- a/include/pocketpy/common/utils.h +++ b/include/pocketpy/common/utils.h @@ -33,6 +33,8 @@ extern const char* kPlatformStrings[]; #define PK_MIN(a, b) ((a) < (b) ? (a) : (b)) #define PK_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define PK_ARRAY_COUNT(a) (sizeof(a) / sizeof(a[0])) + // NARGS #define PK_NARGS_SEQ(_1, _2, _3, _4, N, ...) N #define PK_NARGS(...) PK_NARGS_SEQ(__VA_ARGS__, 4, 3, 2, 1, 0) diff --git a/include/pocketpy/common/vector.hpp b/include/pocketpy/common/vector.hpp deleted file mode 100644 index 66e035a0..00000000 --- a/include/pocketpy/common/vector.hpp +++ /dev/null @@ -1,459 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "pocketpy/common/traits.hpp" -#include "pocketpy/common/types.hpp" -#include "pocketpy/common/algorithm.h" - -namespace pkpy { - -template -struct array { - static_assert(is_pod_v); - - T* _data; - int _size; - - using size_type = int; - - array() : _data(nullptr), _size(0) {} - - array(int size) : _data((T*)std::malloc(sizeof(T) * size)), _size(size) {} - - array(array&& other) noexcept : _data(other._data), _size(other._size) { - other._data = nullptr; - other._size = 0; - } - - array(const array& other) = delete; - - array(explicit_copy_t, const array& other) { - _data = (T*)std::malloc(sizeof(T) * other._size); - _size = other._size; - for(int i = 0; i < _size; i++) - _data[i] = other._data[i]; - } - - array(T* data, int size) : _data(data), _size(size) {} - - array& operator= (array&& other) noexcept { - if(_data) std::free(_data); - _data = other._data; - _size = other._size; - other._data = nullptr; - other._size = 0; - return *this; - } - - array& operator= (const array& other) = delete; - - T& operator[] (int i) { - assert(i >= 0 && i < _size); - return _data[i]; - } - - const T& operator[] (int i) const { - assert(i >= 0 && i < _size); - return _data[i]; - } - - int size() const { return _size; } - - T* begin() const { return _data; } - - T* end() const { return _data + _size; } - - T* data() const { return _data; } - - pair detach() noexcept { - pair retval(_data, _size); - _data = nullptr; - _size = 0; - return retval; - } - - ~array() { - if(_data) std::free(_data); - } -}; - -template -void uninitialized_copy_n(const T* src, int n, T* dest) { - if(n == 0) return; - if constexpr(std::is_trivially_copyable_v) { - if constexpr(may_alias) { - std::memmove(dest, src, sizeof(T) * n); - } else { - std::memcpy(dest, src, sizeof(T) * n); - } - } else { - for(int i = 0; i < n; i++) { - new (dest + i) T(*(src + i)); - } - } -} - -template -void uninitialized_relocate_n(T* src, int n, T* dest) { - if(n == 0) return; - if constexpr(is_trivially_relocatable_v) { - if constexpr(may_alias) { - std::memmove(dest, src, sizeof(T) * n); - } else { - std::memcpy(dest, src, sizeof(T) * n); - } - } else { - if constexpr(backward) { - for(int i = n - 1; i >= 0; i--) { - new (dest + i) T(std::move(*(src + i))); - (src + i)->~T(); - } - } else { - for(int i = 0; i < n; i++) { - new (dest + i) T(std::move(*(src + i))); - (src + i)->~T(); - } - } - } -} - -template -struct vector { - T* _data; - int _capacity; - int _size; - - using size_type = int; - - vector() : _data(nullptr), _capacity(0), _size(0) {} - - vector(int size) : _data((T*)std::malloc(sizeof(T) * size)), _capacity(size), _size(size) {} - - vector(vector&& other) noexcept : _data(other._data), _capacity(other._capacity), _size(other._size) { - other._data = nullptr; - other._capacity = 0; - other._size = 0; - } - - vector(const vector& other) = delete; - - vector(explicit_copy_t, const vector& other) : _capacity(other._size), _size(other._size) { - _data = (T*)std::malloc(sizeof(T) * _capacity); - uninitialized_copy_n(other._data, _size, _data); - } - - // allow move - vector& operator= (vector&& other) noexcept { - if(_data) { - std::destroy(begin(), end()); - std::free(_data); - } - new (this) vector(std::move(other)); - return *this; - } - - // disallow copy - vector& operator= (const vector& other) = delete; - - bool empty() const { return _size == 0; } - - int size() const { return _size; } - - int capacity() const { return _capacity; } - - T& back() { - assert(_size > 0); - return _data[_size - 1]; - } - - T* begin() const { return _data; } - - T* end() const { return _data + _size; } - - T* data() const { return _data; } - - T& operator[] (int i) { - assert(i >= 0 && i < _size); - return _data[i]; - } - - const T& operator[] (int i) const { - assert(i >= 0 && i < _size); - return _data[i]; - } - - void clear() { - std::destroy(begin(), end()); - _size = 0; - } - - void reserve(int cap) { - if(cap < 4) cap = 4; // minimum capacity - if(cap <= capacity()) return; - T* new_data = (T*)std::malloc(sizeof(T) * cap); - uninitialized_relocate_n(_data, _size, new_data); - if(_data) std::free(_data); - _data = new_data; - _capacity = cap; - } - - template - void emplace_back(Args&&... args) { - if(_size == _capacity) reserve(_capacity * 2); - new (_data + _size) T(std::forward(args)...); - _size++; - } - - void push_back(const T& t) { emplace_back(t); } - - void push_back(T&& t) { emplace_back(std::move(t)); } - - bool contains(const T& t) const { - for(int i = 0; i < _size; i++) { - if(_data[i] == t) return true; - } - return false; - } - - void extend(const T* begin, const T* end) { - int n = end - begin; - reserve(_size + n); - uninitialized_copy_n(begin, n, _data + _size); - _size += n; - } - - void insert(const T* it, const T& t) { - assert(it >= begin() && it <= end()); - int pos = it - begin(); - if(_size == _capacity) { - int new_capacity = (_capacity == 0) ? 4 : _capacity * 2; - T* new_data = (T*)std::malloc(sizeof(T) * new_capacity); - uninitialized_relocate_n(_data, pos, new_data); - new (new_data + pos) T(t); - uninitialized_relocate_n(_data + pos, _size - pos, new_data + pos + 1); - if(_data) std::free(_data); - _data = new_data; - _capacity = new_capacity; - } else { - uninitialized_relocate_n(_data + pos, _size - pos, _data + pos + 1); - new (_data + pos) T(t); - } - _size++; - } - - void erase(T* it) { - assert(it >= begin() && it < end()); - int pos = it - begin(); - _data[pos].~T(); - uninitialized_relocate_n(_data + pos + 1, _size - pos, _data + pos); - _size--; - } - - void pop_back() { - assert(_size > 0); - _size--; - _data[_size].~T(); - } - - [[nodiscard]] T popx_back() { - T retval = std::move(back()); - pop_back(); - return retval; - } - - pair detach() noexcept { - pair retval(_data, _size); - _data = nullptr; - _capacity = 0; - _size = 0; - return retval; - } - - void swap(vector& other) { - std::swap(_data, other._data); - std::swap(_capacity, other._capacity); - std::swap(_size, other._size); - } - - ~vector() { - if(_data) { - std::destroy(begin(), end()); - std::free(_data); - } - } -}; - -template -struct small_vector { - static_assert(is_pod_v); - - alignas(T) char _buffer[sizeof(T) * N]; - T* _begin; - T* _end; - T* _capacity; - - [[nodiscard]] bool is_small() const { return _begin == reinterpret_cast(_buffer); } - - [[nodiscard]] int size() const { return _end - _begin; } - - [[nodiscard]] int capacity() const { return _capacity - _begin; } - - [[nodiscard]] bool empty() const { return _begin == _end; } - - [[nodiscard]] T* data() const { return _begin; } - - [[nodiscard]] T* begin() const { return _begin; } - - [[nodiscard]] T* end() const { return _end; } - - [[nodiscard]] T& back() const { return *(end() - 1); } - - [[nodiscard]] T& operator[] (int index) { return _begin[index]; } - - [[nodiscard]] const T& operator[] (int index) const { return _begin[index]; } - - small_vector() : _begin(reinterpret_cast(_buffer)), _end(_begin), _capacity(_begin + N) {} - - small_vector(const small_vector& other) noexcept { - const auto size = other.size(); - const auto capacity = other.capacity(); - _begin = reinterpret_cast(other.is_small() ? _buffer : std::malloc(sizeof(T) * capacity)); - uninitialized_copy_n(other._begin, size, this->_begin); - _end = _begin + size; - _capacity = _begin + capacity; - } - - small_vector(small_vector&& other) noexcept { - if(other.is_small()) { - _begin = reinterpret_cast(_buffer); - uninitialized_relocate_n((T*)other._buffer, other.size(), (T*)_buffer); - _end = _begin + other.size(); - _capacity = _begin + N; - } else { - _begin = other._begin; - _end = other._end; - _capacity = other._capacity; - } - other._begin = reinterpret_cast(other._buffer); - other._end = other._begin; - other._capacity = other._begin + N; - } - - small_vector& operator= (const small_vector& other) = delete; - - small_vector& operator= (small_vector&& other) noexcept { - if(this != &other) { - ~small_vector(); - ::new (this) small_vector(std::move(other)); - } - return *this; - } - - ~small_vector() { - std::destroy(_begin, _end); - if(!is_small()) std::free(_begin); - } - - template - void emplace_back(Args&&... args) noexcept { - if(_end == _capacity) { - const auto new_capacity = capacity() * 2; - const auto size = this->size(); - auto new_data = (T*)std::malloc(sizeof(T) * new_capacity); - uninitialized_relocate_n(_begin, size, new_data); - if(!is_small()) std::free(_begin); - _begin = new_data; - _end = _begin + size; - _capacity = _begin + new_capacity; - } - ::new (_end) T(std::forward(args)...); - _end++; - } - - void push_back(const T& value) { emplace_back(value); } - - void push_back(T&& value) { emplace_back(std::move(value)); } - - void pop_back() { - _end--; - _end->~T(); - } - - void clear() { - std::destroy(_begin, _end); - _end = _begin; - } -}; - -template -class small_vector_2 : public small_vector { -public: - small_vector_2() = default; - small_vector_2(const small_vector_2& other) = delete; - small_vector_2& operator= (const small_vector_2& other) = delete; - small_vector_2(small_vector_2&& other) = delete; - small_vector_2& operator= (small_vector_2&& other) = delete; -}; - -template -struct small_map { - struct Item { - K first; - V second; - - bool operator< (const K& other) const { return first < other; } - - bool operator< (const Item& other) const { return first < other.first; } - }; - - vector _data; - - small_map() = default; - - using size_type = int; - - int size() const { return _data.size(); } - - bool empty() const { return _data.empty(); } - - Item* begin() const { return _data.begin(); } - - Item* end() const { return _data.end(); } - - Item* data() const { return _data.data(); } - - void insert(const K& key, const V& value) { - Item* it = std::lower_bound(_data.begin(), _data.end(), key); - assert(it == _data.end() || it->first != key); - _data.insert(it, {key, value}); - } - - V* try_get(const K& key) const { - auto it = std::lower_bound(_data.begin(), _data.end(), key); - if(it == _data.end() || it->first != key) return nullptr; - return &it->second; - } - - V get(const K& key, V default_value) const { - static_assert(is_pod_v); - auto it = try_get(key); - return it ? *it : default_value; - } - - bool contains(const K& key) const { return try_get(key) != nullptr; } - - void clear() { _data.clear(); } - - const V& operator[] (const K& key) const { - auto it = try_get(key); - assert(it != nullptr); - return *it; - } -}; - -} // namespace pkpy diff --git a/include/pocketpy/interpreter/bindings.hpp b/include/pocketpy/interpreter/bindings.hpp deleted file mode 100644 index 00d05d55..00000000 --- a/include/pocketpy/interpreter/bindings.hpp +++ /dev/null @@ -1,229 +0,0 @@ -#pragma once - -#include "pocketpy/interpreter/cffi.hpp" - -namespace pkpy { -struct NativeProxyFuncCBase { - virtual PyVar operator() (VM* vm, ArgsView args) = 0; -}; - -template -struct NativeProxyFuncC final : NativeProxyFuncCBase { - constexpr static int N = sizeof...(Params); - using _Fp = Ret (*)(Params...); - _Fp func; - - NativeProxyFuncC(_Fp func) : func(func) {} - - PyVar operator() (VM* vm, ArgsView args) override { - assert(args.size() == N); - return call(vm, args, std::make_index_sequence()); - } - - template - PyVar call(VM* vm, ArgsView args, std::index_sequence) { - if constexpr(std::is_void_v<__Ret>) { - func(py_cast(vm, args[Is])...); - return vm->None; - } else { - __Ret ret = func(py_cast(vm, args[Is])...); - return VAR(std::move(ret)); - } - } -}; - -template -struct NativeProxyMethodC final : NativeProxyFuncCBase { - constexpr static int N = sizeof...(Params); - using _Fp = Ret (T::*)(Params...); - _Fp func; - - NativeProxyMethodC(_Fp func) : func(func) {} - - PyVar operator() (VM* vm, ArgsView args) override { - assert(args.size() == N + 1); - return call(vm, args, std::make_index_sequence()); - } - - template - PyVar call(VM* vm, ArgsView args, std::index_sequence) { - obj_get_t self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes - if constexpr(std::is_void_v<__Ret>) { - (self.*func)(py_cast(vm, args[Is + 1])...); - return vm->None; - } else { - __Ret ret = (self.*func)(py_cast(vm, args[Is + 1])...); - return VAR(std::move(ret)); - } - } -}; - -/*****************************************************************/ -inline PyVar __proxy_wrapper(VM* vm, ArgsView args) { - NativeProxyFuncCBase* pf = lambda_get_userdata(args.begin()); - return (*pf)(vm, args); -} - -template -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 -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 -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 -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 -PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) { - static_assert(!std::is_reference_v); - 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); - auto fget = [](VM* vm, ArgsView args) -> PyVar { - obj_get_t self = PK_OBJ_GET(T, args[0]); - F T::*field = lambda_get_userdata(args.begin()); - return VAR(self.*field); - }; - PyVar _0 = new_object(tp_native_func, fget, 1, field); - PyVar _1 = vm->None; - if constexpr(!ReadOnly) { - auto fset = [](VM* vm, ArgsView args) { - obj_get_t self = PK_OBJ_GET(T, args[0]); - F T::*field = lambda_get_userdata(args.begin()); - self.*field = py_cast(vm, args[1]); - return vm->None; - }; - _1 = new_object(tp_native_func, fset, 2, field); - } - PyObject* prop = new_object(tp_property, _0, _1).get(); - obj->attr().set(StrName(name_sv), prop); - return prop; -} - -/*****************************************************************/ - -#define PY_FIELD(T, NAME, EXPR) \ - vm->bind_property( \ - type, \ - NAME, \ - [](VM* vm, ArgsView args) { \ - obj_get_t self = PK_OBJ_GET(T, args[0]); \ - return VAR(self.EXPR); \ - }, \ - [](VM* vm, ArgsView args) { \ - obj_get_t self = PK_OBJ_GET(T, args[0]); \ - self.EXPR = CAST(decltype(self.EXPR), args[1]); \ - return vm->None; \ - }); - -#define PY_READONLY_FIELD(T, NAME, EXPR) \ - vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \ - obj_get_t self = PK_OBJ_GET(T, args[0]); \ - return VAR(self.EXPR); \ - }); - -#define PY_PROPERTY(T, NAME, FGET, FSET) \ - vm->bind_property( \ - type, \ - NAME, \ - [](VM* vm, ArgsView args) { \ - obj_get_t self = PK_OBJ_GET(T, args[0]); \ - return VAR(self.FGET()); \ - }, \ - [](VM* vm, ArgsView args) { \ - obj_get_t self = PK_OBJ_GET(T, args[0]); \ - using __NT = decltype(self.FGET()); \ - self.FSET(CAST(__NT, args[1])); \ - return vm->None; \ - }); - -#define PY_READONLY_PROPERTY(T, NAME, FGET) \ - vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \ - obj_get_t self = PK_OBJ_GET(T, args[0]); \ - return VAR(self.FGET()); \ - }); -/*****************************************************************/ -#define PY_STRUCT_LIKE(wT) \ - static_assert(std::is_trivially_copyable::value); \ - static_assert(!is_sso_v); \ - type->attr().set("__struct__", vm->True); \ - vm->bind_func( \ - type, \ - "fromstruct", \ - 1, \ - [](VM* vm, ArgsView args) { \ - Struct& s = CAST(Struct&, args[0]); \ - if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \ - PyVar obj = vm->new_user_object(); \ - std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \ - return obj; \ - }, \ - {}, \ - BindType_STATICMETHOD); \ - vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) { \ - wT& self = _CAST(wT&, args[0]); \ - return vm->new_user_object(&self, sizeof(wT)); \ - }); \ - vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args) { \ - wT& self = _CAST(wT&, args[0]); \ - return vm->new_user_object(&self); \ - }); \ - vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) { \ - wT& self = _CAST(wT&, args[0]); \ - return vm->new_user_object(self); \ - }); \ - vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { \ - return VAR(sizeof(wT)); \ - }); \ - 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); \ - return VAR(self == other); \ - }); - -#define PY_POINTER_SETGETITEM(T) \ - 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__(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); \ - tgt[i] = CAST(T, _2); \ - }); - -#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; \ - }) - -} // namespace pkpy diff --git a/include/pocketpy/interpreter/ceval.hpp b/include/pocketpy/interpreter/ceval.h similarity index 100% rename from include/pocketpy/interpreter/ceval.hpp rename to include/pocketpy/interpreter/ceval.h diff --git a/include/pocketpy/interpreter/cffi.hpp b/include/pocketpy/interpreter/cffi.hpp deleted file mode 100644 index 59521fa8..00000000 --- a/include/pocketpy/interpreter/cffi.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include "pocketpy/interpreter/vm.hpp" - -namespace pkpy { - -#define PY_CLASS(T, mod, name) \ - [[deprecated]] static Type _type(VM* vm) { return vm->_cxx_typeid_map[typeid(T)]; } \ - [[deprecated]] static PyVar register_class(VM* vm, PyVar mod, Type base = VM::tp_object) { \ - return vm->register_user_class(mod, #name, base); \ - } - -struct VoidP { - void* ptr; - - VoidP(const void* ptr) : ptr(const_cast(ptr)) {} - - bool operator== (const VoidP& other) const { return ptr == other.ptr; } - - bool operator!= (const VoidP& other) const { return ptr != other.ptr; } - - bool operator< (const VoidP& other) const { return ptr < other.ptr; } - - bool operator<= (const VoidP& other) const { return ptr <= other.ptr; } - - bool operator> (const VoidP& other) const { return ptr > other.ptr; } - - bool operator>= (const VoidP& other) const { return ptr >= other.ptr; } - - Str hex() const { - SStream ss; - ss.write_ptr(ptr); - return ss.str(); - } - - static void _register(VM* vm, PyObject* mod, PyObject* type); -}; - -#define POINTER_VAR(Tp, NAME) \ - inline PyVar py_var(VM* vm, Tp val) { \ - const static pair P("c", NAME); \ - PyVar type = vm->_modules[P.first]->attr()[P.second]; \ - return vm->new_object(type->as(), val); \ - } - -POINTER_VAR(char*, "char_p") -// const char* is special, need to rethink about it -POINTER_VAR(const unsigned char*, "uchar_p") -POINTER_VAR(const short*, "short_p") -POINTER_VAR(const unsigned short*, "ushort_p") -POINTER_VAR(const int*, "int_p") -POINTER_VAR(const unsigned int*, "uint_p") -POINTER_VAR(const long*, "long_p") -POINTER_VAR(const unsigned long*, "ulong_p") -POINTER_VAR(const long long*, "longlong_p") -POINTER_VAR(const unsigned long long*, "ulonglong_p") -POINTER_VAR(const float*, "float_p") -POINTER_VAR(const double*, "double_p") -POINTER_VAR(const bool*, "bool_p") - -#undef POINTER_VAR - -struct Struct { - constexpr static int INLINE_SIZE = 24; - - char _inlined[INLINE_SIZE]; - char* p; - int size; - - Struct(int new_size, bool zero_init = true) { - this->size = new_size; - if(size <= INLINE_SIZE) { - p = _inlined; - } else { - p = (char*)std::malloc(size); - } - if(zero_init) std::memset(p, 0, size); - } - - Struct(void* p, int size) : Struct(size, false) { - if(p != nullptr) std::memcpy(this->p, p, size); - } - - Struct(const Struct& other) : Struct(other.p, other.size) {} - - ~Struct() { - if(p != _inlined) std::free(p); - } - - static void _register(VM* vm, PyObject* mod, PyObject* type); -}; - -/***********************************************/ -template -Tp to_void_p(VM* vm, PyVar var) { - static_assert(std::is_pointer_v); - if(is_none(var)) return nullptr; // None can be casted to any pointer implicitly - VoidP& p = CAST(VoidP&, var); - return reinterpret_cast(p.ptr); -} - -/*****************************************************************/ -void add_module_c(VM* vm); - -} // namespace pkpy diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h new file mode 100644 index 00000000..118bf363 --- /dev/null +++ b/include/pocketpy/interpreter/frame.h @@ -0,0 +1,102 @@ +#pragma once + +#include "pocketpy/common/memorypool.h" +#include "pocketpy/objects/codeobject.h" +#include "pocketpy/objects/namedict.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/common/config.h" +#include "pocketpy/common/strname.h" + +#ifdef __cplusplus +extern "C" { +#endif + +PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, StrName name); +pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co); + +typedef struct ValueStack { + // We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`. + PyVar* sp; + PyVar* end; + PyVar begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128]; +} ValueStack; + +void ValueStack__ctor(ValueStack* self); +void ValueStack__clear(ValueStack* self); + +typedef struct UnwindTarget { + struct UnwindTarget* next; + int iblock; + int offset; +} UnwindTarget; + +UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset); +void UnwindTarget__delete(UnwindTarget* self); + +typedef struct Frame { + struct Frame* f_back; // TODO: set this + const Bytecode* ip; + const CodeObject* co; + PyObject* module_; + PyObject* function; // a function object or NULL (global scope) + PyVar* p0; // unwinding base + PyVar* locals; // locals base + const CodeObject* locals_co; + UnwindTarget* uw_list; +} Frame; + + +Frame* Frame__new(Frame* f_back, const CodeObject* co, PyObject* module_, PyObject* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co); +void Frame__delete(Frame* self); + +PK_INLINE int Frame__ip(const Frame* self){ + return self->ip - (Bytecode*)self->co->codes.data; +} + +PK_INLINE int Frame__lineno(const Frame* self){ + int ip = Frame__ip(self); + return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).lineno; +} + +PK_INLINE int Frame__iblock(const Frame* self){ + int ip = Frame__ip(self); + return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).iblock; +} + +PK_INLINE pk_NameDict* Frame__f_globals(Frame* self){ + return self->module_->dict; +} + +PK_INLINE PyVar* Frame__f_globals_try_get(Frame* self, StrName name){ + return pk_NameDict__try_get(self->module_->dict, name); +} + +PyVar* Frame__f_closure_try_get(Frame* self, StrName name); + +int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*); +void Frame__prepare_jump_break(Frame* self, ValueStack*, int); +int Frame__prepare_loop_break(Frame* self, ValueStack*); +int Frame__exit_block(Frame* self, ValueStack*, int); + +void Frame__gc_mark(Frame* self); +UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock); +void Frame__set_unwind_target(Frame* self, PyVar* sp); + +#ifdef __cplusplus +} +#endif + + +// some patch here +#ifdef __cplusplus +#include "pocketpy/objects/codeobject.hpp" + +extern "C"{ + inline PyVar* Frame__f_closure_try_get(Frame* self, StrName name){ + if(self->function == NULL) return NULL; + pkpy::Function* fn = PyObject__as(pkpy::Function, self->function); + if(fn->_closure == nullptr) return nullptr; + return pk_NameDict__try_get(fn->_closure, name); + } +} +#endif \ No newline at end of file diff --git a/include/pocketpy/interpreter/frame.hpp b/include/pocketpy/interpreter/frame.hpp deleted file mode 100644 index e016595f..00000000 --- a/include/pocketpy/interpreter/frame.hpp +++ /dev/null @@ -1,214 +0,0 @@ -#pragma once - -#include "pocketpy/objects/codeobject.h" -#include "pocketpy/objects/codeobject.hpp" - -namespace pkpy { - -// weak reference fast locals -struct FastLocals { - // this is a weak reference - const CodeObject* co; - PyVar* a; - - int size() const { return co->nlocals; } - - PyVar& operator[] (int i) { return a[i]; } - - PyVar operator[] (int i) const { return a[i]; } - - FastLocals(const CodeObject* co, PyVar* a) : co(co), a(a) {} - - PyVar* try_get_name(StrName name); - NameDict* to_namedict(); - - PyVar* begin() const { return a; } - - PyVar* end() const { return a + size(); } -}; - -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; - PyVar* _max_end; - - constexpr static size_t max_size() { return PK_VM_STACK_SIZE; } - - ValueStack() : _sp(_begin), _max_end(_begin + PK_VM_STACK_SIZE) {} - - PyVar& top() { return _sp[-1]; } - - PyVar top() const { return _sp[-1]; } - - PyVar& second() { return _sp[-2]; } - - PyVar second() const { return _sp[-2]; } - - PyVar& third() { return _sp[-3]; } - - PyVar third() const { return _sp[-3]; } - - PyVar& peek(int n) { return _sp[-n]; } - - PyVar peek(int n) const { return _sp[-n]; } - - void push(PyVar v) { *_sp++ = v; } - - void push(std::nullptr_t) { std::memset(_sp++, 0, sizeof(PyVar)); } - - void pop() { --_sp; } - - PyVar popx() { - --_sp; - return *_sp; - } - - ArgsView view(int n) { return ArgsView(_sp - n, _sp); } - - void shrink(int n) { _sp -= n; } - - int size() const { return _sp - _begin; } - - bool empty() const { return _sp == _begin; } - - PyVar* begin() { return _begin; } - - PyVar* end() { return _sp; } - - void reset(PyVar* sp) { _sp = sp; } - - void clear() { _sp = _begin; } - - bool is_overflow() const { return _sp >= _max_end; } - - template - void emplace(Args&&... args) { - new (_sp) PyVar(std::forward(args)...); - ++_sp; - } -}; - -struct UnwindTarget { - UnwindTarget* next; - int iblock; - int offset; - - UnwindTarget(int iblock, int offset) : next(nullptr), iblock(iblock), offset(offset) {} -}; - -struct Frame { - PK_ALWAYS_PASS_BY_POINTER(Frame) - - const Bytecode* _ip; - // This is for unwinding only, use `actual_sp_base()` for value stack access - PyVar* _sp_base; - - const CodeObject* co; - 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); - - int ip() const { return _ip - (Bytecode*)co->codes.data; } - - // function scope - Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) : - _ip((Bytecode*)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, PyObject* _module, PyObject* _callable, FastLocals _locals) : - _ip((Bytecode*)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, PyObject* _module) : - _ip((Bytecode*)co->codes.data - 1), _sp_base(p0), co(co), _module(_module), _callable(nullptr), - _locals(co, p0), _uw_list(nullptr) {} - - PyVar* actual_sp_base() const { return _locals.a; } - - ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); } - - [[nodiscard]] int prepare_jump_exception_handler(ValueStack*); - void prepare_jump_break(ValueStack*, int); - int _exit_block(ValueStack*, int); - - [[nodiscard]] int prepare_loop_break(ValueStack* s_data) { - int iblock = c11__getitem(BytecodeEx, &co->codes_ex, ip()).iblock; - int target = c11__getitem(CodeBlock, &co->blocks, iblock).end; - prepare_jump_break(s_data, target); - return target; - } - - int curr_lineno() const { - return c11__getitem(BytecodeEx, &co->codes_ex, ip()).lineno; - } - - void set_unwind_target(PyVar* _sp); - UnwindTarget* find_unwind_target(int iblock); - - void _gc_mark(VM* vm) const; - ~Frame(); -}; - -struct LinkedFrame { - LinkedFrame* f_back; - Frame frame; - - template - LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward(args)...) {} -}; - -struct CallStack { - static_assert(sizeof(LinkedFrame) <= 128); - - LinkedFrame* _tail; - int _size; - - CallStack() : _tail(nullptr), _size(0) {} - - int size() const { return _size; } - - bool empty() const { return _size == 0; } - - void clear() { - while(!empty()) - pop(); - } - - template - void emplace(Args&&... args) { - static_assert(sizeof(LinkedFrame) <= kPoolFrameBlockSize); - _tail = new (PoolFrame_alloc()) LinkedFrame(_tail, std::forward(args)...); - ++_size; - } - - void pop(); - LinkedFrame* popx(); - void pushx(LinkedFrame* p); - - Frame& top() const { - assert(!empty()); - return _tail->frame; - } - - template - void apply(Func&& f) { - for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) - f(p->frame); - } - - ~CallStack() { clear(); } -}; - -}; // namespace pkpy diff --git a/include/pocketpy/interpreter/gc.h b/include/pocketpy/interpreter/gc.h index 229121de..6cc92f2e 100644 --- a/include/pocketpy/interpreter/gc.h +++ b/include/pocketpy/interpreter/gc.h @@ -13,13 +13,13 @@ typedef struct pk_ManagedHeap{ int gc_threshold; int gc_counter; int gc_lock_counter; - pkpy_VM* vm; + pk_VM* vm; - void (*_gc_on_delete)(pkpy_VM*, PyObject*); - void (*_gc_marker_ex)(pkpy_VM*); + void (*_gc_on_delete)(pk_VM*, PyObject*); + void (*_gc_marker_ex)(pk_VM*); } pk_ManagedHeap; -void pk_ManagedHeap__ctor(pk_ManagedHeap* self, pkpy_VM* vm); +void pk_ManagedHeap__ctor(pk_ManagedHeap* self, pk_VM* vm); void pk_ManagedHeap__dtor(pk_ManagedHeap* self); void pk_ManagedHeap__push_lock(pk_ManagedHeap* self); @@ -29,7 +29,8 @@ void pk_ManagedHeap__collect_if_needed(pk_ManagedHeap* self); int pk_ManagedHeap__collect(pk_ManagedHeap* self); int pk_ManagedHeap__sweep(pk_ManagedHeap* self); -PyObject* pk_ManagedHeap__new(pk_ManagedHeap* self, pkpy_Type type, int size, bool gc); +PyObject* pk_ManagedHeap__new(pk_ManagedHeap* self, Type type, int size); +PyObject* pk_ManagedHeap__gcnew(pk_ManagedHeap* self, Type type, int size); // external implementation void pk_ManagedHeap__mark(pk_ManagedHeap* self); diff --git a/include/pocketpy/interpreter/iter.hpp b/include/pocketpy/interpreter/iter.hpp deleted file mode 100644 index a1917679..00000000 --- a/include/pocketpy/interpreter/iter.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include "pocketpy/interpreter/bindings.hpp" - -namespace pkpy { - -struct RangeIter { // step > 0 - Range r; - i64 current; - - RangeIter(Range r) : r(r), current(r.start) {} - - static void _register(VM* vm, PyObject* mod, PyObject* type); -}; - -struct RangeIterR { // step < 0 - Range r; - i64 current; - - RangeIterR(Range r) : r(r), current(r.start) {} - - static void _register(VM* vm, PyObject* mod, PyObject* type); -}; - -struct ArrayIter { - PyObject* ref; - PyVar* end; - PyVar* current; - - ArrayIter(PyObject* ref, PyVar* begin, PyVar* end) : ref(ref), end(end), current(begin) {} - - void _gc_mark(VM* vm) const { vm->__obj_gc_mark(ref); } - - 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 { vm->obj_gc_mark(ref); } - - static void _register(VM* vm, PyObject* mod, PyObject* type); -}; - -struct Generator { - LinkedFrame* lf; - int state; // 0,1,2 - List s_backup; - - Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) { - for(PyVar obj: buffer) - s_backup.push_back(obj); - } - - void _gc_mark(VM* vm) { - if(lf == nullptr) return; - lf->frame._gc_mark(vm); - vm->__stack_gc_mark(s_backup.begin(), s_backup.end()); - } - - PyVar next(VM* vm); - static void _register(VM* vm, PyObject* mod, PyObject* type); - - ~Generator() { - if(lf) { - lf->~LinkedFrame(); - PoolFrame_dealloc(lf); - } - } -}; - -struct DictItemsIter { - PyVar ref; - pkpy_DictIter it; - - DictItemsIter(PyVar ref) : ref(ref) { it = PK_OBJ_GET(Dict, ref).iter(); } - - void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); } - - static void _register(VM* vm, PyObject* mod, PyObject* type); -}; - -} // namespace pkpy diff --git a/include/pocketpy/interpreter/profiler.hpp b/include/pocketpy/interpreter/profiler.hpp deleted file mode 100644 index b157d48b..00000000 --- a/include/pocketpy/interpreter/profiler.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "pocketpy/common/config.h" -#include "pocketpy/interpreter/frame.hpp" - -#if PK_ENABLE_PROFILER -#include - -namespace pkpy { - -struct _LineRecord { - int line; - i64 hits; - clock_t time; - - _LineRecord() : line(-1), hits(0), time(0) {} - - bool is_valid() const { return line != -1; } -}; - -struct _FrameRecord { - int callstack_size; - Frame* frame; - clock_t prev_time; - _LineRecord* prev_record; -}; - -struct LineProfiler { - // filename -> records - small_map records; - vector<_FrameRecord> frames; - vector functions; - - void begin(); - void _step(int, Frame*); - void _step_end(int, Frame*, int); - void end(); - Str stats(); - ~LineProfiler(); -}; - -} // namespace pkpy - -#endif \ No newline at end of file diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 00c5c8f8..6f9d3b02 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -1,12 +1,82 @@ -#include "pocketpy/objects/object.h" +#pragma once -typedef struct pkpy_VM{ - PyVar True; - PyVar False; - PyVar None; - PyVar NotImplemented; - PyVar Ellipsis; -} pkpy_VM; +#include "pocketpy/pocketpy.h" +#include "pocketpy/interpreter/gc.h" +#include "pocketpy/interpreter/frame.h" -void pkpy_VM__ctor(pkpy_VM* self); -void pkpy_VM__dtor(pkpy_VM* self); +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pk_TypeInfo{ + StrName name; + Type base; + + PyObject* obj; // the type object itself + PyObject* module; // the module where the type is defined + bool subclass_enabled; + + void (*dtor)(void*); + void (*gc_mark)(void*); + + c11_vector/*T=StrName*/ annotated_fields; + + /* Magic Caches */ + // unary operators + py_CFunction m__repr__, m__str__, m__hash__, m__len__; + py_CFunction m__iter__, m__next__, m__neg__, m__invert__; + // binary operators + py_CFunction m__eq__, m__lt__, m__le__, m__gt__, m__ge__, m__contains__; + py_CFunction m__add__, m__sub__, m__mul__, m__truediv__, m__floordiv__; + py_CFunction m__mod__, m__pow__, m__matmul__; + py_CFunction m__lshift__, m__rshift__, m__and__, m__xor__, m__or__; + // indexer + py_CFunction m__getitem__, m__setitem__, m__delitem__; + // attribute access (internal use only) + py_CFunction m__getattr__, m__setattr__, m__delattr__; + // backdoors + py_CFunction on_end_subclass; // for enum module +} pk_TypeInfo; + +void pk_TypeInfo__ctor(pk_TypeInfo *self, StrName name, Type base, PyObject* obj, PyObject* module, bool subclass_enabled); +void pk_TypeInfo__dtor(pk_TypeInfo* self); + +typedef struct pk_VM { + Frame* top_frame; + + pk_NameDict modules; + c11_vector/*T=pk_TypeInfo*/ types; + + PyObject* StopIteration; // a special Exception class + PyObject* builtins; // builtins module + PyObject* main; // __main__ module + + void (*_ceval_on_step)(struct pk_VM*, Frame*, Bytecode); + unsigned char* (*_import_file)(struct pk_VM*, const char*); + void (*_stdout)(struct pk_VM*, const char*); + void (*_stderr)(struct pk_VM*, const char*); + + // singleton objects + PyVar True, False, None, NotImplemented, Ellipsis; + + PyObject* __last_exception; + PyObject* __curr_class; + PyObject* __cached_object_new; + FuncDecl_ __dynamic_func_decl; + PyVar __vectorcall_buffer[PK_MAX_CO_VARNAMES]; + + void* userdata; // for user-defined data (unused by pkpy itself) + + pk_ManagedHeap heap; + ValueStack stack; // put `stack` at the end for better cache locality +} pk_VM; + +void pk_VM__ctor(pk_VM* self); +void pk_VM__dtor(pk_VM* self); + +Type pk_VM__new_type(pk_VM* self, const char* name, Type base, PyObject* module, bool subclass_enabled); +PyObject* pk_VM__new_module(pk_VM* self, const char* name, const char* package); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/pocketpy/interpreter/vm.hpp b/include/pocketpy/interpreter/vm.hpp index cc0c7304..0eef3b5f 100644 --- a/include/pocketpy/interpreter/vm.hpp +++ b/include/pocketpy/interpreter/vm.hpp @@ -1,11 +1,12 @@ #pragma once -#include "pocketpy/objects/object.hpp" +#include "pocketpy/objects/object.h" +#include "pocketpy/objects/base.h" #include "pocketpy/objects/dict.hpp" #include "pocketpy/objects/error.hpp" #include "pocketpy/objects/builtins.hpp" #include "pocketpy/interpreter/gc.h" -#include "pocketpy/interpreter/frame.hpp" +#include "pocketpy/interpreter/frame.h" #include "pocketpy/interpreter/profiler.hpp" #include @@ -14,14 +15,15 @@ namespace pkpy { /* Stack manipulation macros */ // https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123 -#define TOP() (s_data.top()) -#define SECOND() (s_data.second()) -#define THIRD() (s_data.third()) -#define STACK_SHRINK(n) (s_data.shrink(n)) -#define PUSH(v) (s_data.push(v)) -#define POP() (s_data.pop()) -#define POPX() (s_data.popx()) -#define STACK_VIEW(n) (s_data.view(n)) +#define TOP() (s_data.sp[-1]) +#define SECOND() (s_data.sp[-2]) +#define THIRD() (s_data.sp[-3]) +#define STACK_SHRINK(n) (s_data.sp -= (n)) +#define PUSH(v) (*s_data.sp++ = (v)) +#define PUSH_NULL() memset(s_data.sp++, 0, sizeof(PyVar)) +#define POP() (--s_data.sp) +#define POPX() (*--s_data.sp) +#define STACK_VIEW(n) (ArgsView(s_data.sp - (n), s_data.sp)) typedef PyVar (*BinaryFuncC)(VM*, PyVar, PyVar); typedef void (*RegisterFunc)(VM*, PyObject*, PyObject*); @@ -163,12 +165,11 @@ class VM { public: pk_ManagedHeap heap; - ValueStack s_data; - CallStack callstack; + Frame* top_frame; vector _all_types; - NameDict _modules; // loaded modules - small_map _lazy_modules; // lazy loaded modules + pk_NameDict _modules; // loaded modules + small_map _lazy_modules; // lazy loaded modules struct { PyObject* error; @@ -200,13 +201,10 @@ public: void (*_stdout)(const char*, int); void (*_stderr)(const char*, int); unsigned char* (*_import_handler)(const char*, int*); - // function _stdout; - // function _stderr; - // function _import_handler; // for quick access constexpr static Type tp_object = Type(1), tp_type = Type(2); - constexpr static Type tp_int = Type(kTpIntIndex), tp_float = Type(kTpFloatIndex), tp_bool = Type(5), + constexpr static Type tp_int = Type(3), tp_float = Type(4), tp_bool = Type(5), tp_str = Type(6); constexpr static Type tp_list = Type(7), tp_tuple = Type(8); constexpr static Type tp_slice = Type(9), tp_range = Type(10), tp_module = Type(11); @@ -214,7 +212,7 @@ public: constexpr static Type tp_super = Type(15), tp_exception = Type(16), tp_bytes = Type(17), tp_mappingproxy = Type(18); constexpr static Type tp_dict = Type(19), tp_property = Type(20), tp_star_wrapper = Type(21); constexpr static Type tp_staticmethod = Type(22), tp_classmethod = Type(23); - constexpr static Type tp_none_type = Type(kTpNoneTypeIndex), tp_not_implemented_type = Type(kTpNotImplementedTypeIndex); + constexpr static Type tp_none_type = Type(24), tp_not_implemented_type = Type(25); constexpr static Type tp_ellipsis = Type(26); PyVar True; @@ -224,6 +222,10 @@ public: PyVar Ellipsis; const bool enable_os; + + // put s_data at the end of VM struct to improve cache locality + ValueStack s_data; + VM(bool enable_os = true); // clang-format off @@ -255,10 +257,10 @@ public: return !py_eq(lhs, rhs); } - PyVar py_op(std::string_view name); // (name) -> operator.name + PyVar py_op(const char* name); // (name) -> operator.name - void py_exec(std::string_view, PyVar, PyVar); // exec(source, globals, locals) - PyVar py_eval(std::string_view, PyVar, PyVar); // eval(source, globals, locals) + void py_exec(const char*, PyVar, PyVar); // exec(source, globals, locals) + PyVar py_eval(const char*, PyVar, PyVar); // eval(source, globals, locals) #endif #if PK_REGION("Utility Methods") @@ -267,7 +269,7 @@ 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(PyVar obj) { if(obj.is_ptr) __obj_gc_mark(obj._obj); } void obj_gc_mark(PyObject* p) { if(p) __obj_gc_mark(p); } #endif @@ -288,7 +290,7 @@ public: template PyVar _exec(Args&&... args){ - callstack.emplace(s_data._sp, std::forward(args)...); + callstack.emplace(s_data.sp, std::forward(args)...); return __run_top_frame(); } #endif @@ -298,7 +300,7 @@ public: template PyVar call(PyVar callable, Args&&... args){ - PUSH(callable); PUSH(PY_NULL); + PUSH(callable); PUSH_NULL(); __push_varargs(args...); return vectorcall(sizeof...(args)); } @@ -433,44 +435,44 @@ public: template bool is_user_type(PyVar obj){ return _tp(obj) == _tp_user(); } - template - PyObject* register_user_class(PyObject*, StrName, RegisterFunc, Type base=tp_object, bool subclass_enabled=false); - template - PyObject* register_user_class(PyObject*, StrName, Type base=tp_object, bool subclass_enabled=false); + // template + // PyObject* register_user_class(PyObject*, StrName, RegisterFunc, Type base=tp_object, bool subclass_enabled=false); + // template + // PyObject* register_user_class(PyObject*, StrName, Type base=tp_object, bool subclass_enabled=false); - template - PyVar new_user_object(Args&&... args){ - return new_object(_tp_user(), std::forward(args)...); - } + // template + // PyVar new_user_object(Args&&... args){ + // return new_object(_tp_user(), std::forward(args)...); + // } template PyVar new_object(Type type, Args&&... args){ static_assert(!is_sso_v); static_assert(std::is_same_v>); - PyObject* p = (PyObject*)pk_ManagedHeap__new(&heap, type, py_sizeof, true); - new (p->_value_ptr()) T(std::forward(args)...); + PyObject* p = pk_ManagedHeap__new(&heap, type, py_sizeof, true); + new (PyObject__value_ptr(p)) T(std::forward(args)...); // backdoor for important builtin types if constexpr(std::is_same_v || std::is_same_v || std::is_same_v) { - p->_attr = new NameDict(); + p->_attr = pk_NameDict__new(); } - return p; + return PyVar__fromobj(p); } template PyVar new_object_no_gc(Type type, Args&&... args){ static_assert(!is_sso_v); static_assert(std::is_same_v>); - PyObject* p = (PyObject*)pk_ManagedHeap__new(&heap, type, py_sizeof, false); - new (p->_value_ptr()) T(std::forward(args)...); + PyObject* p = pk_ManagedHeap__new(&heap, type, py_sizeof, true); + new (PyObject__value_ptr(p)) T(std::forward(args)...); // backdoor for important builtin types if constexpr(std::is_same_v || std::is_same_v || std::is_same_v) { - p->_attr = new NameDict(); + p->_attr = pk_NameDict__new(); } - return p; + return PyVar__fromobj(p); } #endif @@ -499,7 +501,7 @@ public: PyVar __format_object(PyVar, Str); PyVar __run_top_frame(); void __pop_frame(); - PyVar __py_generator(LinkedFrame* frame, ArgsView buffer); + PyVar __py_generator(Frame* frame, ArgsView buffer); void __op_unpack_sequence(uint16_t arg); void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl*); void __unpack_as_list(ArgsView args, List& list); @@ -686,32 +688,32 @@ __T _py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, false>(vm, obj); } -template -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.insert(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 = args[0]->as(); - return vm->new_object(cls_t); - }); - } else { - bind_func(type, __new__, -1, [](VM* vm, ArgsView args) { - vm->NotImplementedError(); - return vm->None; - }); - } - } - return type; -} +// template +// 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.insert(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 = args[0]->as(); +// return vm->new_object(cls_t); +// }); +// } else { +// bind_func(type, __new__, -1, [](VM* vm, ArgsView args) { +// vm->NotImplementedError(); +// return vm->None; +// }); +// } +// } +// return type; +// } -template -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); -} +// template +// 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); +// } } // namespace pkpy diff --git a/include/pocketpy/modules/array2d.hpp b/include/pocketpy/modules/array2d.hpp deleted file mode 100644 index eaa4340d..00000000 --- a/include/pocketpy/modules/array2d.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" - -namespace pkpy { - -void add_module_array2d(VM* vm); - -} // namespace pkpy diff --git a/include/pocketpy/modules/base64.hpp b/include/pocketpy/modules/base64.hpp deleted file mode 100644 index aca8f52d..00000000 --- a/include/pocketpy/modules/base64.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" - -namespace pkpy { - -void add_module_base64(VM* vm); - -} // namespace pkpy diff --git a/include/pocketpy/modules/csv.hpp b/include/pocketpy/modules/csv.hpp deleted file mode 100644 index 07422744..00000000 --- a/include/pocketpy/modules/csv.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" - -namespace pkpy { - -void add_module_csv(VM* vm); - -} // namespace pkpy diff --git a/include/pocketpy/modules/dataclasses.hpp b/include/pocketpy/modules/dataclasses.hpp deleted file mode 100644 index 87d2d27f..00000000 --- a/include/pocketpy/modules/dataclasses.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" - -namespace pkpy { - -void add_module_dataclasses(VM* vm); - -} // namespace pkpy diff --git a/include/pocketpy/modules/easing.hpp b/include/pocketpy/modules/easing.hpp deleted file mode 100644 index 4f31e6dc..00000000 --- a/include/pocketpy/modules/easing.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" - -namespace pkpy { - -void add_module_easing(VM* vm); - -} // namespace pkpy diff --git a/include/pocketpy/modules/io.hpp b/include/pocketpy/modules/io.hpp deleted file mode 100644 index c566b8ce..00000000 --- a/include/pocketpy/modules/io.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" - -namespace pkpy { -unsigned char* _default_import_handler(const char*, int*); -void add_module_os(VM* vm); -void add_module_io(VM* vm); -} // namespace pkpy diff --git a/include/pocketpy/modules/linalg.hpp b/include/pocketpy/modules/linalg.hpp deleted file mode 100644 index 630eb572..00000000 --- a/include/pocketpy/modules/linalg.hpp +++ /dev/null @@ -1,215 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" -#include "pocketpy/common/traits.hpp" - -#include - -namespace pkpy { - -inline bool isclose(float a, float b) { return std::fabs(a - b) < 1e-4; } - -struct Vec2 { - static void _register(VM* vm, PyObject* mod, PyObject* type); - - float x, y; - - Vec2() : x(0.0f), y(0.0f) {} - - Vec2(float x, float y) : x(x), y(y) {} - - Vec2 operator+ (const Vec2& v) const { return Vec2(x + v.x, y + v.y); } - - Vec2 operator- (const Vec2& v) const { return Vec2(x - v.x, y - v.y); } - - Vec2 operator* (float s) const { return Vec2(x * s, y * s); } - - Vec2 operator* (const Vec2& v) const { return Vec2(x * v.x, y * v.y); } - - Vec2 operator/ (float s) const { return Vec2(x / s, y / s); } - - Vec2 operator- () const { return Vec2(-x, -y); } - - bool operator== (const Vec2& v) const { return isclose(x, v.x) && isclose(y, v.y); } - - bool operator!= (const Vec2& v) const { return !isclose(x, v.x) || !isclose(y, v.y); } - - float operator[] (int i) const { return (&x)[i]; } - - float dot(const Vec2& v) const { return x * v.x + y * v.y; } - - float cross(const Vec2& v) const { return x * v.y - y * v.x; } - - float length() const { return sqrtf(x * x + y * y); } - - float length_squared() const { return x * x + y * y; } - - Vec2 normalize() const { - float l = length(); - return Vec2(x / l, y / l); - } - - Vec2 rotate(float radian) const { - float cr = cosf(radian), sr = sinf(radian); - return Vec2(x * cr - y * sr, x * sr + y * cr); - } -}; - -struct Vec3 { - static void _register(VM* vm, PyObject* mod, PyObject* type); - - float x, y, z; - - Vec3() : x(0.0f), y(0.0f), z(0.0f) {} - - Vec3(float x, float y, float z) : x(x), y(y), z(z) {} - - Vec3 operator+ (const Vec3& v) const { return Vec3(x + v.x, y + v.y, z + v.z); } - - Vec3 operator- (const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); } - - Vec3 operator* (float s) const { return Vec3(x * s, y * s, z * s); } - - Vec3 operator* (const Vec3& v) const { return Vec3(x * v.x, y * v.y, z * v.z); } - - Vec3 operator/ (float s) const { return Vec3(x / s, y / s, z / s); } - - Vec3 operator- () const { return Vec3(-x, -y, -z); } - - bool operator== (const Vec3& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z); } - - bool operator!= (const Vec3& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z); } - - float operator[] (int i) const { return (&x)[i]; } - - float dot(const Vec3& v) const { return x * v.x + y * v.y + z * v.z; } - - Vec3 cross(const Vec3& v) const { return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } - - float length() const { return sqrtf(x * x + y * y + z * z); } - - float length_squared() const { return x * x + y * y + z * z; } - - Vec3 normalize() const { - float l = length(); - return Vec3(x / l, y / l, z / l); - } -}; - -struct Vec4 { - 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) {} - - Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} - - Vec4 operator+ (const Vec4& v) const { return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); } - - Vec4 operator- (const Vec4& v) const { return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); } - - Vec4 operator* (float s) const { return Vec4(x * s, y * s, z * s, w * s); } - - Vec4 operator* (const Vec4& v) const { return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); } - - Vec4 operator/ (float s) const { return Vec4(x / s, y / s, z / s, w / s); } - - Vec4 operator- () const { return Vec4(-x, -y, -z, -w); } - - bool operator== (const Vec4& v) const { - return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w); - } - - bool operator!= (const Vec4& v) const { - return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w); - } - - float operator[] (int i) const { return (&x)[i]; } - - float dot(const Vec4& v) const { return x * v.x + y * v.y + z * v.z + w * v.w; } - - float length() const { return sqrtf(x * x + y * y + z * z + w * w); } - - float length_squared() const { return x * x + y * y + z * z + w * w; } - - Vec4 normalize() const { - float l = length(); - return Vec4(x / l, y / l, z / l, w / l); - } - - NoReturn normalize_() { - float l = length(); - x /= l; - y /= l; - z /= l; - w /= l; - return {}; - } - - NoReturn copy_(const Vec4& v) { - x = v.x; - y = v.y; - z = v.z; - w = v.w; - return {}; - } -}; - -struct Mat3x3 { - static void _register(VM* vm, PyObject* mod, PyObject* type); - - union { - struct { - float _11, _12, _13; - float _21, _22, _23; - float _31, _32, _33; - }; - - float m[3][3]; - float v[9]; - }; - - Mat3x3(); - Mat3x3(float, float, float, float, float, float, float, float, float); - - static Mat3x3 zeros(); - static Mat3x3 ones(); - static Mat3x3 identity(); - - Mat3x3 operator+ (const Mat3x3& other) const; - Mat3x3 operator- (const Mat3x3& other) const; - Mat3x3 operator* (float scalar) const; - Mat3x3 operator/ (float scalar) const; - - bool operator== (const Mat3x3& other) const; - bool operator!= (const Mat3x3& other) const; - - Mat3x3 matmul(const Mat3x3& other) const; - Vec3 matmul(const Vec3& other) const; - - float determinant() const; - Mat3x3 transpose() const; - bool inverse(Mat3x3& out) const; - - /*************** affine transformations ***************/ - static Mat3x3 trs(Vec2 t, float radian, Vec2 s); - bool is_affine() const; - Vec2 _t() const; - float _r() const; - Vec2 _s() const; -}; - -void add_module_linalg(VM* vm); - -static_assert(is_pod_v); -static_assert(is_pod_v); -static_assert(is_pod_v); -static_assert(is_pod_v); - -// template <> -// constexpr inline bool is_sso_v = true; -// template <> -// constexpr inline bool is_sso_v = true; - -} // namespace pkpy diff --git a/include/pocketpy/modules/modules.hpp b/include/pocketpy/modules/modules.hpp deleted file mode 100644 index 942f96e3..00000000 --- a/include/pocketpy/modules/modules.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" - -namespace pkpy { - -void add_module_time(VM* vm); -void add_module_sys(VM* vm); -void add_module_json(VM* vm); -void add_module_math(VM* vm); -void add_module_traceback(VM* vm); -void add_module_dis(VM* vm); -void add_module_gc(VM* vm); -void add_module_line_profiler(VM* vm); -void add_module_enum(VM* vm); -void add_module___builtins(VM* vm); - -} // namespace pkpy diff --git a/include/pocketpy/modules/random.hpp b/include/pocketpy/modules/random.hpp deleted file mode 100644 index cd892c99..00000000 --- a/include/pocketpy/modules/random.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" - -namespace pkpy { - -void add_module_random(VM* vm); - -} // namespace pkpy diff --git a/include/pocketpy/objects/base.h b/include/pocketpy/objects/base.h index 483807ee..834b6633 100644 --- a/include/pocketpy/objects/base.h +++ b/include/pocketpy/objects/base.h @@ -7,14 +7,16 @@ #include "string.h" #include "pocketpy/common/utils.h" -#include "pocketpy/objects/public.h" +#include "pocketpy/pocketpy.h" #ifdef __cplusplus extern "C" { #endif +typedef int16_t Type; + typedef struct PyVar{ - pkpy_Type type; + Type type; bool is_ptr; int extra; union { @@ -37,22 +39,23 @@ typedef struct PyVar{ static_assert(sizeof(PyVar) == 16, "sizeof(PyVar) != 16"); /* predefined vars */ -static const pkpy_Type tp_object = 1, tp_type = 2; -static const pkpy_Type tp_int = 3, tp_float = 4, tp_bool = 5, tp_str = 6; -static const pkpy_Type tp_list = 7, tp_tuple = 8; -static const pkpy_Type tp_slice = 9, tp_range = 10, tp_module = 11; -static const pkpy_Type tp_function = 12, tp_native_func = 13, tp_bound_method = 14; -static const pkpy_Type tp_super = 15, tp_exception = 16, tp_bytes = 17, tp_mappingproxy = 18; -static const pkpy_Type tp_dict = 19, tp_property = 20, tp_star_wrapper = 21; -static const pkpy_Type tp_staticmethod = 22, tp_classmethod = 23; -static const pkpy_Type tp_none_type = 24, tp_not_implemented_type = 25; -static const pkpy_Type tp_ellipsis = 26; -static const pkpy_Type tp_op_call = 27, tp_op_yield = 28; +static const Type tp_object = {1}, tp_type = {2}; +static const Type tp_int = {3}, tp_float = {4}, tp_bool = {5}, tp_str = {6}; +static const Type tp_list = {7}, tp_tuple = {8}; +static const Type tp_slice = {9}, tp_range = {10}, tp_module = {11}; +static const Type tp_function = {12}, tp_native_func = {13}, tp_bound_method = {14}; +static const Type tp_super = {15}, tp_exception = {16}, tp_bytes = {17}, tp_mappingproxy = {18}; +static const Type tp_dict = {19}, tp_property = {20}, tp_star_wrapper = {21}; +static const Type tp_staticmethod = {22}, tp_classmethod = {23}; +static const Type tp_none_type = {24}, tp_not_implemented_type = {25}; +static const Type tp_ellipsis = {26}; +static const Type tp_op_call = {27}, tp_op_yield = {28}; +static const Type tp_syntax_error = {29}, tp_stop_iteration = {30}; PK_INLINE bool PyVar__is_null(const PyVar* self) { return self->type == 0; } PK_INLINE int64_t PyVar__hash(const PyVar* self) { return self->extra + self->_i64; } -PK_INLINE void PyVar__ctor(PyVar* self, pkpy_Type type, PyObject* obj){ +PK_INLINE void PyVar__ctor(PyVar* self, Type type, PyObject* obj){ self->type = type; self->is_ptr = true; self->_obj = obj; @@ -67,7 +70,7 @@ PK_INLINE bool PyVar__IS_OP(const PyVar* a, const PyVar* b){ #define pkpy_Var__is_null(self) ((self)->type == 0) #define pkpy_Var__set_null(self) do { (self)->type = 0; } while(0) -extern PyVar pkpy_NULL, pkpy_OP_CALL, pkpy_OP_YIELD; +extern PyVar PY_NULL, PY_OP_CALL, PY_OP_YIELD; #ifdef __cplusplus } diff --git a/include/pocketpy/objects/base.hpp b/include/pocketpy/objects/base.hpp deleted file mode 100644 index 9948e400..00000000 --- a/include/pocketpy/objects/base.hpp +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include "pocketpy/common/types.hpp" -#include "pocketpy/common/traits.hpp" -#include "pocketpy/objects/base.h" - -namespace pkpy { - -struct Type { - pkpy_Type index; - constexpr Type() : index(0) {} - constexpr Type(pkpy_Type index) : index(index) {} - bool operator== (Type other) const { return this->index == other.index; } - bool operator!= (Type other) const { return this->index != other.index; } - constexpr operator pkpy_Type () const { return index; } -}; - -struct PyVar final: ::PyVar { - // uninitialized - PyVar() = default; - - // implict conversion - PyVar(PyObject* existing){ - PyVar__ctor3(this, (::PyObject*)existing); - } - - /* We must initialize all members to allow == operator to work correctly */ - // zero initialized - PyVar(std::nullptr_t){ - set_null(); - } - - // PyObject* initialized (is_sso = false) - PyVar(Type type, PyObject* p){ - PyVar__ctor(this, type, (::PyObject*)p); - } - - PyVar(Type type, i64 value){ - this->type = type; - this->is_ptr = false; - this->_i64 = value; - } - - explicit operator bool () const { return (bool)type; } - - void set_null() { - memset(this, 0, sizeof(PyVar)); - } - - bool operator==(PyObject* other){ - return is_ptr && (PyObject*)_obj == other; - } - bool operator!=(PyObject* other){ - return !is_ptr || (PyObject*)_obj != other; - } - bool operator==(std::nullptr_t){ - return type == 0; - } - bool operator!=(std::nullptr_t){ - return type != 0; - } - - PyObject* get() const { - assert(is_ptr); - return (PyObject*)_obj; - } - - PyObject* operator->() const { - assert(is_ptr); - return (PyObject*)_obj; - } - - i64 hash() const { return PyVar__hash(this); } - - template - obj_get_t obj_get(); - - // implicit convert from ::PyVar - PyVar(const ::PyVar& var) { - memcpy(this, &var, sizeof(var)); - } -}; - -static_assert(sizeof(PyVar) == 16 && is_pod_v); -} // namespace pkpy diff --git a/include/pocketpy/objects/builtins.hpp b/include/pocketpy/objects/builtins.hpp deleted file mode 100644 index a80b9240..00000000 --- a/include/pocketpy/objects/builtins.hpp +++ /dev/null @@ -1,141 +0,0 @@ -#pragma once - -#include "pocketpy/common/vector.hpp" -#include "pocketpy/objects/object.hpp" - -namespace pkpy { - -struct BoundMethod { - PyVar self; - PyVar func; - - BoundMethod(PyVar self, PyVar func) : self(self), func(func) {} - - void _gc_mark(VM*) const; -}; - -struct StaticMethod { - PyVar func; - - StaticMethod(PyVar func) : func(func) {} - - void _gc_mark(VM*) const; -}; - -struct ClassMethod { - PyVar func; - - ClassMethod(PyVar func) : func(func) {} - - void _gc_mark(VM*) const; -}; - -struct Property { - PyVar getter; - PyVar setter; - - Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {} - - void _gc_mark(VM*) const; -}; - -struct Range { - i64 start = 0; - i64 stop = -1; - i64 step = 1; -}; - -struct StarWrapper { - int level; // either 1 or 2 - PyVar obj; - - StarWrapper(int level, PyVar obj) : level(level), obj(obj) {} - - void _gc_mark(VM*) const; -}; - -using Bytes = array; - -struct Super { - PyVar first; - Type second; - - Super(PyVar first, Type second) : first(first), second(second) {} - - void _gc_mark(VM*) const; -}; - -struct Slice { - PyVar start; - PyVar stop; - PyVar step; - - Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {} - - void _gc_mark(VM*) const; -}; - -const inline int16_t kTpIntIndex = 3; -const inline int16_t kTpFloatIndex = 4; -const inline int16_t kTpNoneTypeIndex = 24; -const inline int16_t kTpNotImplementedTypeIndex = 25; - -inline bool is_tagged(PyVar p) noexcept { return !p.is_ptr; } - -inline bool is_float(PyVar p) noexcept { return p.type == kTpFloatIndex; } - -inline bool is_int(PyVar p) noexcept { return p.type == kTpIntIndex; } - -inline bool is_none(PyVar p) noexcept { return p.type == kTpNoneTypeIndex; } - -inline bool is_not_implemented(PyVar p) noexcept { return p.type == kTpNotImplementedTypeIndex; } - -inline bool is_type(PyVar obj, Type type) { - assert(obj != nullptr); - return obj.type == type; -} - -inline bool is_type(PyObject* p, Type type) { - assert(p != nullptr); - return p->type == type; -} - -struct MappingProxy { - PyObject* obj; - - MappingProxy(PyObject* obj) : obj(obj) {} - - NameDict& attr() { return obj->attr(); } - - void _gc_mark(VM*) const; -}; - -StrName _type_name(VM* vm, Type type); -template -T to_void_p(VM*, PyVar); -PyVar from_void_p(VM*, void*); - -template -T& PyVar::obj_get() { - static_assert(!is_sso_v, "unsupported"); - assert(is_ptr); - void* v = PyObject__value_ptr(_obj); - return *reinterpret_cast(v); -} - -#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) -#define _CAST(T, x) _py_cast(vm, x) - -#define CAST_F(x) py_cast(vm, x) -#define CAST_DEFAULT(T, x, default_value) (x != vm->None) ? py_cast(vm, x) : (default_value) - -/*****************************************************************/ -#define PY_NULL nullptr - -} // namespace pkpy diff --git a/include/pocketpy/objects/codeobject.hpp b/include/pocketpy/objects/codeobject.hpp deleted file mode 100644 index 37cc4371..00000000 --- a/include/pocketpy/objects/codeobject.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include "pocketpy/common/any.h" -#include "pocketpy/common/traits.hpp" -#include "pocketpy/objects/tuplelist.hpp" -#include "pocketpy/objects/namedict.hpp" -#include "pocketpy/objects/sourcedata.h" -#include "pocketpy/common/smallmap.h" -#include "pocketpy/objects/codeobject.h" - -namespace pkpy { - -typedef PyVar (*NativeFuncC)(VM*, ArgsView); - -struct NativeFunc { - NativeFuncC f; - int argc; // old style argc-based call - FuncDecl_ decl; // new style decl-based call - any _userdata; - - NativeFunc(NativeFuncC f, int argc, any userdata = {}) : - f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {} - - NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata = {}) : - f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {} - - PyVar call(VM* vm, ArgsView args) const { return f(vm, args); } - - void _gc_mark(VM*) const; - - ~NativeFunc() { - if(decl) PK_DECREF(decl); - } -}; - -struct Function { - PK_ALWAYS_PASS_BY_POINTER(Function) - - FuncDecl_ decl; - PyObject* _module; // weak ref - PyObject* _class; // weak ref - NameDict* _closure; // strong ref - - Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict* _closure) : - decl(decl), _module(_module), _class(_class), _closure(_closure) { - PK_INCREF(decl); - } - - void _gc_mark(VM*) const; - - ~Function() { - PK_DECREF(decl); - delete _closure; - } -}; - -template -T lambda_get_userdata(PyVar* p) { - static_assert(std::is_same_v>); - static_assert(is_pod_v); - int offset = p[-1] != nullptr ? -1 : -2; - NativeFunc& nf = p[offset].obj_get(); - return nf._userdata.as(); -} - -} // namespace pkpy diff --git a/include/pocketpy/objects/dict.hpp b/include/pocketpy/objects/dict.hpp deleted file mode 100644 index 98b8b748..00000000 --- a/include/pocketpy/objects/dict.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include "pocketpy/objects/base.hpp" -#include "pocketpy/objects/tuplelist.hpp" -#include "pocketpy/objects/dict.h" - -namespace pkpy { - -struct Dict : private pkpy_Dict { - Dict() { - pkpy_Dict__ctor(this); - } - - Dict(Dict&& other) { - std::memcpy(this, &other, sizeof(Dict)); - pkpy_Dict__ctor(&other); - } - - Dict(const Dict& other) { - // OPTIMIZEME: reduce copy - auto clone = pkpy_Dict__copy(&other); - std::memcpy(this, &clone, sizeof(Dict)); - } - - Dict& operator= (const Dict&) = delete; - Dict& operator= (Dict&&) = delete; - - int size() const { return count; } - - void set(VM* vm, PyVar key, PyVar val) { - pkpy_Dict__set(this, *(::PyVar*)(&key), *(::PyVar*)(&val)); - } - - PyVar try_get(VM* vm, PyVar key) const { - auto res = pkpy_Dict__try_get(this, *(::PyVar*)(&key)); - if (!res) return nullptr; - return *(const PyVar*)(res); - } - - bool contains(VM* vm, PyVar key) const { - return pkpy_Dict__contains(this, *(::PyVar*)(&key)); - } - - bool del(VM* vm, PyVar key) { - return pkpy_Dict__del(this, *(::PyVar*)(&key)); - } - - void update(VM* vm, const Dict& other) { - pkpy_Dict__update(this, &other); - } - - template - void apply(__Func f) const { - pkpy_DictIter it = iter(); - PyVar key, val; - while(pkpy_DictIter__next(&it, (::PyVar*)(&key), (::PyVar*)(&val))) { - f(key, val); - } - } - - Tuple keys() const { - Tuple res(count); - pkpy_DictIter it = iter(); - PyVar key, val; - int i = 0; - while(pkpy_DictIter__next(&it, (::PyVar*)(&key), (::PyVar*)(&val))) { - res[i++] = key; - } - return res; - } - - Tuple values() const { - Tuple res(count); - pkpy_DictIter it = iter(); - PyVar key, val; - int i = 0; - while(pkpy_DictIter__next(&it, (::PyVar*)(&key), (::PyVar*)(&val))) { - res[i++] = val; - } - return res; - } - - pkpy_DictIter iter() const { - return pkpy_Dict__iter(this); - } - - void clear() { - pkpy_Dict__clear(this); - } - - ~Dict() { - pkpy_Dict__dtor(this); - } - - void _gc_mark(VM*) const; -}; - -} // namespace pkpy diff --git a/include/pocketpy/objects/error.h b/include/pocketpy/objects/error.h index ffb15d3a..946ffd09 100644 --- a/include/pocketpy/objects/error.h +++ b/include/pocketpy/objects/error.h @@ -17,7 +17,7 @@ typedef struct pkpy_ExceptionFrame { } pkpy_ExceptionFrame; typedef struct pkpy_Exception { - pkpy_StrName type; + pk_StrName type; pkpy_Str msg; bool is_re; @@ -29,7 +29,7 @@ typedef struct pkpy_Exception { c11_vector/*T=pkpy_ExceptionFrame*/ stacktrace; } pkpy_Exception; -void pkpy_Exception__ctor(pkpy_Exception* self, pkpy_StrName type); +void pkpy_Exception__ctor(pkpy_Exception* self, pk_StrName type); void pkpy_Exception__dtor(pkpy_Exception* self); void pkpy_Exception__stpush(pkpy_Exception* self, pkpy_SourceData_ src, int lineno, const char* cursor, const char* name); pkpy_Str pkpy_Exception__summary(pkpy_Exception* self); diff --git a/include/pocketpy/objects/error.hpp b/include/pocketpy/objects/error.hpp deleted file mode 100644 index 4acc6528..00000000 --- a/include/pocketpy/objects/error.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "pocketpy/common/str.hpp" -#include "pocketpy/common/traits.hpp" -#include "pocketpy/objects/sourcedata.h" -#include "pocketpy/objects/error.h" - -namespace pkpy { - -struct NeedMoreLines { - NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {} - - bool is_compiling_class; -}; - -enum class InternalExceptionType : int { Null, Handled, Unhandled, ToBeRaised }; - -struct InternalException final { - InternalExceptionType type; - int arg; - - InternalException() : type(InternalExceptionType::Null), arg(-1) {} - - InternalException(InternalExceptionType type, int arg = -1) : type(type), arg(arg) {} -}; - -struct Exception: pkpy_Exception{ - PK_ALWAYS_PASS_BY_POINTER(Exception) - - Exception(uint16_t type){ - pkpy_Exception__ctor(this, type); - } - - ~Exception(){ - pkpy_Exception__dtor(this); - } - - void stpush(pkpy_SourceData_ src, int lineno, const char* cursor, const char* name){ - pkpy_Exception__stpush(this, src, lineno, cursor, name); - } - - Str summary(){ - return pkpy_Exception__summary(this); - } -}; - -struct TopLevelException : std::exception { - VM* vm; - Exception* ptr; - - TopLevelException(VM* vm, Exception* ptr) : vm(vm), ptr(ptr) {} - - Str summary() const { return ptr->summary(); } - - const char* what() const noexcept override { - static Str cached_summary; - cached_summary = summary(); - return cached_summary.c_str(); - } -}; - - - -} // namespace pkpy diff --git a/include/pocketpy/objects/namedict.h b/include/pocketpy/objects/namedict.h index 7e515697..4e3966c9 100644 --- a/include/pocketpy/objects/namedict.h +++ b/include/pocketpy/objects/namedict.h @@ -12,7 +12,7 @@ extern "C" { #define SMALLMAP_T__HEADER #define K uint16_t #define V PyVar -#define NAME pkpy_NameDict +#define NAME pk_NameDict #include "pocketpy/xmacros/smallmap.h" #undef SMALLMAP_T__HEADER diff --git a/include/pocketpy/objects/namedict.hpp b/include/pocketpy/objects/namedict.hpp deleted file mode 100644 index 32cb75c4..00000000 --- a/include/pocketpy/objects/namedict.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include "pocketpy/common/config.h" -#include "pocketpy/common/str.hpp" -#include "pocketpy/common/utils.h" -#include "pocketpy/objects/object.hpp" -#include "pocketpy/objects/namedict.h" - -#include - -namespace pkpy { - -struct NameDict: pkpy_NameDict { - PK_ALWAYS_PASS_BY_POINTER(NameDict) - - using Item = pair; - - NameDict() { - pkpy_NameDict__ctor(this); - } - - ~NameDict() { - pkpy_NameDict__dtor(this); - } - - uint16_t size() const { - return count; - } - - void set(StrName key, PyVar val){ - PyVar* p = (PyVar*)&val; - pkpy_NameDict__set(this, key.index, *p); - } - - PyVar try_get(StrName key) const{ - PyVar* p = try_get_2(key); - if(p) return *p; - return nullptr; - } - - PyVar* try_get_2(StrName key) const{ - PyVar* p = (PyVar*)pkpy_NameDict__try_get(this, key.index); - return p; - } - - PyVar try_get_likely_found(StrName key) const{ - return try_get(key); - } - - PyVar* try_get_2_likely_found(StrName key) const{ - return try_get_2(key); - } - - bool del(StrName key){ - return pkpy_NameDict__del(this, key.index); - } - - bool contains(StrName key) const{ - return pkpy_NameDict__contains(this, key.index); - } - - PyVar operator[] (StrName key) const{ - PyVar* val = try_get_2_likely_found(key); - if(val == nullptr){ - PK_FATAL_ERROR("NameDict key not found: %d (%s)\n", (int)key.index, key.escape().c_str()) - } - return *val; - } - - void clear(){ - pkpy_NameDict__clear(this); - } - - array keys() const{ - array retval((int)size()); - for(int i=0; ikey); - } - return retval; - } - - array items() const{ - array retval((int)size()); - for(int i=0; ivalue; - retval[i] = Item(StrName(it->key), *p); - } - return retval; - } - - void apply(void (*f)(StrName, PyVar, void*), void* data){ - for(int i=0; ivalue; - f(StrName(it->key), *p, data); - } - } -}; - -static_assert(sizeof(NameDict) <= 128); - -} // namespace pkpy diff --git a/include/pocketpy/objects/object.h b/include/pocketpy/objects/object.h index 83beed72..a6e2faab 100644 --- a/include/pocketpy/objects/object.h +++ b/include/pocketpy/objects/object.h @@ -8,22 +8,33 @@ extern "C" { #endif typedef struct PyObject{ - pkpy_Type type; // we have a duplicated type here for convenience + Type type; // we have a duplicated type here for convenience bool gc_is_large; bool gc_marked; - pkpy_NameDict* _attr; // gc will delete this on destruction + pk_NameDict* dict; // gc will delete this on destruction } PyObject; static_assert(sizeof(PyObject) <= 16, "!(sizeof(PyObject) <= 16)"); #define PyObject__value_ptr(self) ((char*)self + 16) #define PyObject__as(T, self) (T*)(PyObject__value_ptr(self)) +#define PK_OBJ_GET(T, val) (*(T*)(PyObject__value_ptr((val)._obj))) +#define PK_OBJ_SIZEOF(T) (sizeof(T) + 16) -PK_INLINE void PyObject__ctor(PyObject* self, pkpy_Type type, bool gc_is_large){ +PK_INLINE void PyObject__ctor(PyObject* self, Type type, bool gc_is_large){ self->type = type; self->gc_is_large = gc_is_large; self->gc_marked = false; - self->_attr = NULL; + self->dict = NULL; +} + +PK_INLINE PyVar PyVar__fromobj(PyObject* obj){ + PyVar retval = { + .type = obj->type, + .is_ptr = true, + ._obj = obj; + }; + return retval; } #ifdef __cplusplus diff --git a/include/pocketpy/objects/object.hpp b/include/pocketpy/objects/object.hpp deleted file mode 100644 index b55a81ba..00000000 --- a/include/pocketpy/objects/object.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "pocketpy/common/str.hpp" -#include "pocketpy/common/config.h" -#include "pocketpy/objects/base.hpp" -#include "pocketpy/objects/object.h" - -namespace pkpy { - -struct NameDict; - -struct PyObject final: ::PyObject { - bool is_attr_valid() const noexcept { return _attr != nullptr; } - - void* _value_ptr() noexcept { return PyObject__value_ptr(this); } - - NameDict& attr() const{ - assert(is_attr_valid()); - return *(NameDict*)_attr; - } - - PyVar attr(StrName name) const; - - template - T& as() noexcept { - static_assert(std::is_same_v>); - return *reinterpret_cast(_value_ptr()); - } - - PyObject(Type type, bool gc_is_large){ - PyObject__ctor(this, type, gc_is_large); - } -}; - -static_assert(sizeof(PyObject) <= 16); - -} // namespace pkpy diff --git a/include/pocketpy/objects/tuplelist.hpp b/include/pocketpy/objects/tuplelist.hpp deleted file mode 100644 index e344cb3c..00000000 --- a/include/pocketpy/objects/tuplelist.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -#include "pocketpy/common/vector.hpp" -#include "pocketpy/objects/base.hpp" - -namespace pkpy { - -struct Tuple { - const static int INLINED_SIZE = 3; - - PyVar* _args; - PyVar _inlined[INLINED_SIZE]; - int _size; - - Tuple(int n); - Tuple(Tuple&& other) noexcept; - Tuple(const Tuple& other) = delete; - Tuple& operator= (const Tuple& other) = delete; - Tuple& operator= (Tuple&& other) = delete; - ~Tuple(); - - Tuple(PyVar, PyVar); - Tuple(PyVar, PyVar, PyVar); - - bool is_inlined() const { return _args == _inlined; } - - PyVar& operator[] (int i) { return _args[i]; } - - PyVar operator[] (int i) const { return _args[i]; } - - int size() const { return _size; } - - PyVar* begin() const { return _args; } - - PyVar* end() const { return _args + _size; } - - PyVar* data() const { return _args; } - - void _gc_mark(VM*) const; -}; - -struct List : public vector { - using vector::vector; - void _gc_mark(VM*) const; - - Tuple to_tuple() const { - Tuple ret(size()); - for(int i = 0; i < size(); i++) - ret[i] = (*this)[i]; - return ret; - } -}; - -// a lightweight view for function args, it does not own the memory -struct ArgsView { - PyVar* _begin; - PyVar* _end; - - ArgsView(PyVar* begin, PyVar* end) : _begin(begin), _end(end) {} - - ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {} - - PyVar* begin() const { return _begin; } - - PyVar* end() const { return _end; } - - int size() const { return _end - _begin; } - - bool empty() const { return _begin == _end; } - - PyVar operator[] (int i) const { return _begin[i]; } - - List to_list() const; - Tuple to_tuple() const; -}; - -} // namespace pkpy diff --git a/include/pocketpy/objects/public.h b/include/pocketpy/pocketpy.h similarity index 59% rename from include/pocketpy/objects/public.h rename to include/pocketpy/pocketpy.h index 9aa01488..6d806cac 100644 --- a/include/pocketpy/objects/public.h +++ b/include/pocketpy/pocketpy.h @@ -1,5 +1,3 @@ -#pragma once - #include "stdint.h" #include "stdbool.h" @@ -7,19 +5,27 @@ extern "C" { #endif -typedef int16_t pkpy_Type; typedef struct PyObject PyObject; typedef struct PyVar PyVar; -typedef struct pkpy_VM pkpy_VM; +typedef struct pk_VM pk_VM; +typedef struct py_Error py_Error; -struct pkpy_G { - pkpy_VM* vm; -} extern pkpy_g; +typedef unsigned (*py_CFunction)(const PyVar*, int); + +extern pk_VM* pk_vm; void py_initialize(); -void py_switch_vm(const char* name); +// void py_switch_vm(const char* name); void py_finalize(); +py_Error* py_exec_simple(const char*); +py_Error* py_eval_simple(const char*, PyVar*); + +/* py_error */ +void py_Error__print(const py_Error*); +void py_Error__delete(py_Error*); + + bool py_eq(const PyVar*, const PyVar*); bool py_le(const PyVar*, const PyVar*); int64_t py_hash(const PyVar*); @@ -34,6 +40,8 @@ void py_newstr2(PyVar*, const char*, int); void py_newbytes(PyVar*, const uint8_t*, int); void py_newnone(PyVar*); +#define py_isnull(self) ((self)->type == 0) + #ifdef __cplusplus } #endif diff --git a/include/pocketpy/pocketpy.hpp b/include/pocketpy/pocketpy.hpp deleted file mode 100644 index 4449724f..00000000 --- a/include/pocketpy/pocketpy.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "pocketpy/common/traits.hpp" -#include "pocketpy/objects/builtins.hpp" -#include "pocketpy/interpreter/vm.hpp" -#include "pocketpy/interpreter/iter.hpp" -#include "pocketpy/interpreter/bindings.hpp" -#include "pocketpy/compiler/compiler.hpp" -#include "pocketpy/modules/linalg.hpp" -#include "pocketpy/tools/repl.hpp" - -namespace pkpy { -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 80); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -static_assert(py_sizeof <= 64); -} // namespace pkpy diff --git a/include/pocketpy/pocketpy_c.h b/include/pocketpy/pocketpy_c.h deleted file mode 100644 index 86adab25..00000000 --- a/include/pocketpy/pocketpy_c.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef POCKETPY_C_H -#define POCKETPY_C_H - -#include -#include - -#include "pocketpy/common/export.h" - -#ifdef __cplusplus -extern "C" { - namespace pkpy{ -#endif - typedef struct pkpy_vm_handle pkpy_vm; - typedef int (*pkpy_CFunction)(pkpy_vm*); - typedef void (*pkpy_COutputHandler)(const char*, int); - typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*); - typedef int pkpy_CName; - typedef int pkpy_CType; - typedef const char* pkpy_CString; - - /* Basic Functions */ - PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os); - PK_EXPORT void pkpy_delete_vm(pkpy_vm*); - PK_EXPORT bool pkpy_exec(pkpy_vm*, const char* source); - PK_EXPORT bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module); - PK_EXPORT void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv); - - /* Stack Manipulation */ - PK_EXPORT bool pkpy_dup(pkpy_vm*, int i); - PK_EXPORT bool pkpy_pop(pkpy_vm*, int n); - PK_EXPORT bool pkpy_pop_top(pkpy_vm*); - PK_EXPORT bool pkpy_dup_top(pkpy_vm*); - PK_EXPORT bool pkpy_rot_two(pkpy_vm*); - PK_EXPORT int pkpy_stack_size(pkpy_vm*); - - // int - PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val); - PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i); - PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out); - - // float - PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val); - PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i); - PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out); - - // bool - PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val); - PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i); - PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out); - - // string - PK_EXPORT bool pkpy_push_string(pkpy_vm*, pkpy_CString val); - PK_EXPORT bool pkpy_is_string(pkpy_vm*, int i); - PK_EXPORT bool pkpy_to_string(pkpy_vm*, int i, pkpy_CString* out); - - // void_p - PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val); - PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i); - PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out); - - // none - PK_EXPORT bool pkpy_push_none(pkpy_vm*); - PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i); - - // special push - PK_EXPORT bool pkpy_push_null(pkpy_vm*); - PK_EXPORT bool pkpy_push_function(pkpy_vm*, const char* sig, pkpy_CFunction val); - PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name); - - // some opt - PK_EXPORT bool pkpy_getattr(pkpy_vm*, pkpy_CName name); - PK_EXPORT bool pkpy_setattr(pkpy_vm*, pkpy_CName name); - PK_EXPORT bool pkpy_getglobal(pkpy_vm*, pkpy_CName name); - PK_EXPORT bool pkpy_setglobal(pkpy_vm*, pkpy_CName name); - PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source); - PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size); - PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name); - PK_EXPORT bool pkpy_py_repr(pkpy_vm*); - PK_EXPORT bool pkpy_py_str(pkpy_vm*); - PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name); - - /* Error Handling */ - PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg); - PK_EXPORT bool pkpy_check_error(pkpy_vm*); - PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message); - - /* Callables */ - PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc); - - /* Special APIs */ - PK_EXPORT void pkpy_free(void* p); -#define pkpy_string(__s) (__s) - PK_EXPORT pkpy_CName pkpy_name(const char* s); - PK_EXPORT pkpy_CString pkpy_name_to_string(pkpy_CName name); - PK_EXPORT void pkpy_set_output_handler(pkpy_vm*, pkpy_COutputHandler handler); - PK_EXPORT void pkpy_set_import_handler(pkpy_vm*, pkpy_CImportHandler handler); - - /* REPL */ - PK_EXPORT void* pkpy_new_repl(pkpy_vm*); - PK_EXPORT bool pkpy_repl_input(void* r, const char* line); - PK_EXPORT void pkpy_delete_repl(void* repl); -#ifdef __cplusplus -} -} -#endif - -#endif diff --git a/include/pocketpy/xmacros/smallmap.h b/include/pocketpy/xmacros/smallmap.h index 0a1278f6..7dd26bf9 100644 --- a/include/pocketpy/xmacros/smallmap.h +++ b/include/pocketpy/xmacros/smallmap.h @@ -37,6 +37,8 @@ typedef c11_vector NAME; void METHOD(ctor)(NAME* self); void METHOD(dtor)(NAME* self); +NAME* METHOD(new)(); +void METHOD(delete)(NAME* self); void METHOD(set)(NAME* self, K key, V value); V* METHOD(try_get)(const NAME* self, K key); V METHOD(get)(const NAME* self, K key, V default_value); @@ -58,6 +60,17 @@ void METHOD(dtor)(NAME* self) { c11_vector__dtor(self); } +NAME* METHOD(new)() { + NAME* self = malloc(sizeof(NAME)); + METHOD(ctor)(self); + return self; +} + +void METHOD(delete)(NAME* self) { + METHOD(dtor)(self); + free(self); +} + void METHOD(set)(NAME* self, K key, V value) { int index; c11__lower_bound(KV, self->data, self->count, key, partial_less, &index); diff --git a/include/pocketpy_c.h b/include/pocketpy_c.h deleted file mode 100644 index 517bcb0d..00000000 --- a/include/pocketpy_c.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "pocketpy/pocketpy_c.h" diff --git a/src/common/strname.c b/src/common/strname.c index 892e4760..59721c87 100644 --- a/src/common/strname.c +++ b/src/common/strname.c @@ -10,7 +10,7 @@ static c11_smallmap_s2n _interned; static c11_vector/*T=char* */ _r_interned; static bool _initialized = false; -void pkpy_StrName__initialize(){ +void pk_StrName__initialize(){ if(_initialized) return; c11_smallmap_s2n__ctor(&_interned); for(int i=0; i<_r_interned.count; i++){ @@ -20,77 +20,77 @@ void pkpy_StrName__initialize(){ _initialized = true; // unary operators - __repr__ = pkpy_StrName__map("__repr__"); - __str__ = pkpy_StrName__map("__str__"); - __hash__ = pkpy_StrName__map("__hash__"); - __len__ = pkpy_StrName__map("__len__"); - __iter__ = pkpy_StrName__map("__iter__"); - __next__ = pkpy_StrName__map("__next__"); - __neg__ = pkpy_StrName__map("__neg__"); + __repr__ = pk_StrName__map("__repr__"); + __str__ = pk_StrName__map("__str__"); + __hash__ = pk_StrName__map("__hash__"); + __len__ = pk_StrName__map("__len__"); + __iter__ = pk_StrName__map("__iter__"); + __next__ = pk_StrName__map("__next__"); + __neg__ = pk_StrName__map("__neg__"); // logical operators - __eq__ = pkpy_StrName__map("__eq__"); - __lt__ = pkpy_StrName__map("__lt__"); - __le__ = pkpy_StrName__map("__le__"); - __gt__ = pkpy_StrName__map("__gt__"); - __ge__ = pkpy_StrName__map("__ge__"); - __contains__ = pkpy_StrName__map("__contains__"); + __eq__ = pk_StrName__map("__eq__"); + __lt__ = pk_StrName__map("__lt__"); + __le__ = pk_StrName__map("__le__"); + __gt__ = pk_StrName__map("__gt__"); + __ge__ = pk_StrName__map("__ge__"); + __contains__ = pk_StrName__map("__contains__"); // binary operators - __add__ = pkpy_StrName__map("__add__"); - __radd__ = pkpy_StrName__map("__radd__"); - __sub__ = pkpy_StrName__map("__sub__"); - __rsub__ = pkpy_StrName__map("__rsub__"); - __mul__ = pkpy_StrName__map("__mul__"); - __rmul__ = pkpy_StrName__map("__rmul__"); - __truediv__ = pkpy_StrName__map("__truediv__"); - __floordiv__ = pkpy_StrName__map("__floordiv__"); - __mod__ = pkpy_StrName__map("__mod__"); - __pow__ = pkpy_StrName__map("__pow__"); - __matmul__ = pkpy_StrName__map("__matmul__"); - __lshift__ = pkpy_StrName__map("__lshift__"); - __rshift__ = pkpy_StrName__map("__rshift__"); - __and__ = pkpy_StrName__map("__and__"); - __or__ = pkpy_StrName__map("__or__"); - __xor__ = pkpy_StrName__map("__xor__"); - __invert__ = pkpy_StrName__map("__invert__"); + __add__ = pk_StrName__map("__add__"); + __radd__ = pk_StrName__map("__radd__"); + __sub__ = pk_StrName__map("__sub__"); + __rsub__ = pk_StrName__map("__rsub__"); + __mul__ = pk_StrName__map("__mul__"); + __rmul__ = pk_StrName__map("__rmul__"); + __truediv__ = pk_StrName__map("__truediv__"); + __floordiv__ = pk_StrName__map("__floordiv__"); + __mod__ = pk_StrName__map("__mod__"); + __pow__ = pk_StrName__map("__pow__"); + __matmul__ = pk_StrName__map("__matmul__"); + __lshift__ = pk_StrName__map("__lshift__"); + __rshift__ = pk_StrName__map("__rshift__"); + __and__ = pk_StrName__map("__and__"); + __or__ = pk_StrName__map("__or__"); + __xor__ = pk_StrName__map("__xor__"); + __invert__ = pk_StrName__map("__invert__"); // indexer - __getitem__ = pkpy_StrName__map("__getitem__"); - __setitem__ = pkpy_StrName__map("__setitem__"); - __delitem__ = pkpy_StrName__map("__delitem__"); + __getitem__ = pk_StrName__map("__getitem__"); + __setitem__ = pk_StrName__map("__setitem__"); + __delitem__ = pk_StrName__map("__delitem__"); // specials - __new__ = pkpy_StrName__map("__new__"); - __init__ = pkpy_StrName__map("__init__"); - __call__ = pkpy_StrName__map("__call__"); - __divmod__ = pkpy_StrName__map("__divmod__"); - __enter__ = pkpy_StrName__map("__enter__"); - __exit__ = pkpy_StrName__map("__exit__"); - __name__ = pkpy_StrName__map("__name__"); - __all__ = pkpy_StrName__map("__all__"); - __package__ = pkpy_StrName__map("__package__"); - __path__ = pkpy_StrName__map("__path__"); - __class__ = pkpy_StrName__map("__class__"); - __missing__ = pkpy_StrName__map("__missing__"); + __new__ = pk_StrName__map("__new__"); + __init__ = pk_StrName__map("__init__"); + __call__ = pk_StrName__map("__call__"); + __divmod__ = pk_StrName__map("__divmod__"); + __enter__ = pk_StrName__map("__enter__"); + __exit__ = pk_StrName__map("__exit__"); + __name__ = pk_StrName__map("__name__"); + __all__ = pk_StrName__map("__all__"); + __package__ = pk_StrName__map("__package__"); + __path__ = pk_StrName__map("__path__"); + __class__ = pk_StrName__map("__class__"); + __missing__ = pk_StrName__map("__missing__"); - pk_id_add = pkpy_StrName__map("add"); - pk_id_set = pkpy_StrName__map("set"); - pk_id_long = pkpy_StrName__map("long"); - pk_id_complex = pkpy_StrName__map("complex"); + pk_id_add = pk_StrName__map("add"); + pk_id_set = pk_StrName__map("set"); + pk_id_long = pk_StrName__map("long"); + pk_id_complex = pk_StrName__map("complex"); } -void pkpy_StrName__finalize(){ +void pk_StrName__finalize(){ if(!_initialized) return; c11_smallmap_s2n__dtor(&_interned); c11_vector__dtor(&_r_interned); } -uint16_t pkpy_StrName__map(const char* name){ - return pkpy_StrName__map2((c11_string){name, strlen(name)}); +uint16_t pk_StrName__map(const char* name){ + return pk_StrName__map2((c11_string){name, strlen(name)}); } -uint16_t pkpy_StrName__map2(c11_string name){ +uint16_t pk_StrName__map2(c11_string name){ // TODO: PK_GLOBAL_SCOPE_LOCK() if(!_initialized){ - pkpy_StrName__initialize(); // lazy init + pk_StrName__initialize(); // lazy init } uint16_t index = c11_smallmap_s2n__get(&_interned, name, 0); if(index != 0) return index; @@ -110,7 +110,7 @@ uint16_t pkpy_StrName__map2(c11_string name){ return index; } -const char* pkpy_StrName__rmap(uint16_t index){ +const char* pk_StrName__rmap(uint16_t index){ assert(_initialized); assert(index > 0 && index <= _interned.count); return c11__getitem(char*, &_r_interned, index - 1); diff --git a/src/error.c b/src/error.c index 96af79ee..89fba2ae 100644 --- a/src/error.c +++ b/src/error.c @@ -2,7 +2,7 @@ #include "pocketpy/common/strname.h" #include "pocketpy/common/sstream.h" -void pkpy_Exception__ctor(pkpy_Exception* self, pkpy_StrName type){ +void pkpy_Exception__ctor(pkpy_Exception* self, pk_StrName type){ self->type = type; self->is_re = true; self->_ip_on_error = -1; @@ -48,7 +48,7 @@ pkpy_Str pkpy_Exception__summary(pkpy_Exception* self){ pk_SStream__write_cstr(&ss, "\n"); } - const char* name = pkpy_StrName__rmap(self->type); + const char* name = pk_StrName__rmap(self->type); pk_SStream__write_cstr(&ss, name); if(self->msg.size > 0){ diff --git a/src/interpreter/ceval.cpp b/src/interpreter/ceval.c similarity index 99% rename from src/interpreter/ceval.cpp rename to src/interpreter/ceval.c index 9c48e4ca..aeb2f554 100644 --- a/src/interpreter/ceval.cpp +++ b/src/interpreter/ceval.c @@ -25,7 +25,7 @@ namespace pkpy { } else { \ PyVar self; \ PyVar _2 = get_unbound_method(_0, func, &self, false); \ - if(_2) \ + if(_2.type) \ ret = call_method(self, _2, _1); \ else \ ret = NotImplemented; \ @@ -33,7 +33,7 @@ namespace pkpy { if(is_not_implemented(ret)) { \ PyVar self; \ PyVar _2 = get_unbound_method(_1, rfunc, &self, false); \ - if(_2) \ + if(_2.type) \ ret = call_method(self, _2, _0); \ else \ BinaryOptError(op, _0, _1); \ @@ -192,7 +192,7 @@ PyVar VM::__run_top_frame() { if(decl->nested) { NameDict* captured = frame->_locals.to_namedict(); obj = new_object(tp_function, decl, frame->_module, nullptr, captured); - uint16_t name = pkpy_StrName__map2(pkpy_Str__sv(&decl->code->name)); + uint16_t name = pk_StrName__map2(pkpy_Str__sv(&decl->code->name)); captured->set(name, obj); } else { obj = new_object(tp_function, decl, frame->_module, nullptr, nullptr); @@ -863,7 +863,7 @@ PyVar VM::__run_top_frame() { } } DISPATCH() - case OP_YIELD_VALUE: return pkpy_OP_YIELD; + case OP_YIELD_VALUE: return PY_OP_YIELD; /*****************************************/ case OP_LIST_APPEND: { PyVar _0 = POPX(); @@ -935,7 +935,7 @@ PyVar VM::__run_top_frame() { DISPATCH_JUMP_ABSOLUTE(target) } else { PUSH(_0); - return pkpy_OP_YIELD; + return PY_OP_YIELD; } } case OP_FOR_ITER_UNPACK: { @@ -1075,7 +1075,7 @@ PyVar VM::__run_top_frame() { DISPATCH() /*****************************************/ case OP_TRY_ENTER: { - frame->set_unwind_target(s_data._sp); + frame->set_unwind_target(s_data.sp); DISPATCH() } case OP_EXCEPTION_MATCH: { diff --git a/src/interpreter/cffi.cpp b/src/interpreter/cffi.cpp deleted file mode 100644 index f4f16106..00000000 --- a/src/interpreter/cffi.cpp +++ /dev/null @@ -1,289 +0,0 @@ -#include "pocketpy/interpreter/cffi.hpp" - -namespace pkpy { - -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__(type->as(), [](VM* vm, PyVar obj) { - obj_get_t self = PK_OBJ_GET(VoidP, obj); - return reinterpret_cast(self.ptr); - }); - - 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(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; \ - return VAR(_0 op _1); \ - }); - - BIND_CMP(__eq__, ==) - BIND_CMP(__lt__, <) - BIND_CMP(__le__, <=) - BIND_CMP(__gt__, >) - BIND_CMP(__ge__, >=) - -#undef BIND_CMP -} - -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]); - return vm->new_object(cls, size); - }); - - vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) { - const Struct& self = _CAST(Struct&, args[0]); - SStream ss; - for(int i = 0; i < self.size; i++) - ss.write_hex((unsigned char)self.p[i]); - return VAR(ss.str()); - }); - - // @staticmethod - vm->bind_func( - type, - "fromhex", - 1, - [](VM* vm, ArgsView args) { - const Str& s = CAST(Str&, args[0]); - if(s.size < 2 || s.size % 2 != 0) vm->ValueError("invalid hex string"); - Struct buffer(s.size / 2, false); - for(int i = 0; i < s.size; i += 2) { - char c = 0; - if(s[i] >= '0' && s[i] <= '9') - c += s[i] - '0'; - else if(s[i] >= 'A' && s[i] <= 'F') - c += s[i] - 'A' + 10; - else if(s[i] >= 'a' && s[i] <= 'f') - c += s[i] - 'a' + 10; - else - vm->ValueError(_S("invalid hex char: '", s[i], "'")); - c <<= 4; - if(s[i + 1] >= '0' && s[i + 1] <= '9') - c += s[i + 1] - '0'; - else if(s[i + 1] >= 'A' && s[i + 1] <= 'F') - c += s[i + 1] - 'A' + 10; - else if(s[i + 1] >= 'a' && s[i + 1] <= 'f') - c += s[i + 1] - 'a' + 10; - else - vm->ValueError(_S("invalid hex char: '", s[i + 1], "'")); - buffer.p[i / 2] = c; - } - return vm->new_user_object(std::move(buffer)); - }, - {}, - BindType_STATICMETHOD); - - vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) { - Struct& self = _CAST(Struct&, obj); - SStream ss; - ss << ""; - return ss.str(); - }); - - vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args) { - Struct& self = _CAST(Struct&, args[0]); - return vm->new_user_object(self.p); - }); - - vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { - Struct& self = _CAST(Struct&, args[0]); - return VAR(self.size); - }); - - vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) { - const Struct& self = _CAST(Struct&, args[0]); - return vm->new_object(vm->_tp(args[0]), self); - }); - - 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); - bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0; - return VAR(ok); - }); - -#define BIND_SETGET(T, name) \ - vm->bind(type, "read_" name "(self, offset=0)", [](VM* vm, ArgsView args) { \ - Struct& self = _CAST(Struct&, args[0]); \ - i64 offset = CAST(i64, args[1]); \ - void* ptr = self.p + offset; \ - return VAR(*(T*)ptr); \ - }); \ - vm->bind(type, "write_" name "(self, value, offset=0)", [](VM* vm, ArgsView args) { \ - Struct& self = _CAST(Struct&, args[0]); \ - i64 offset = CAST(i64, args[2]); \ - void* ptr = self.p + offset; \ - *(T*)ptr = CAST(T, args[1]); \ - return vm->None; \ - }); - BIND_SETGET(char, "char") - BIND_SETGET(unsigned char, "uchar") - BIND_SETGET(short, "short") - BIND_SETGET(unsigned short, "ushort") - BIND_SETGET(int, "int") - BIND_SETGET(unsigned int, "uint") - BIND_SETGET(long, "long") - BIND_SETGET(unsigned long, "ulong") - BIND_SETGET(long long, "longlong") - BIND_SETGET(unsigned long long, "ulonglong") - BIND_SETGET(float, "float") - BIND_SETGET(double, "double") - BIND_SETGET(bool, "bool") - BIND_SETGET(void*, "void_p") -#undef BIND_SETGET -} - -void add_module_c(VM* vm) { - PyObject* mod = vm->new_module("c"); - - vm->bind_func(mod, "malloc", 1, [](VM* vm, ArgsView args) { - i64 size = CAST(i64, args[0]); - return VAR(std::malloc(size)); - }); - - vm->bind_func(mod, "free", 1, [](VM* vm, ArgsView args) { - void* p = CAST(void*, args[0]); - std::free(p); - return vm->None; - }); - - vm->bind_func(mod, "memset", 3, [](VM* vm, ArgsView args) { - void* p = CAST(void*, args[0]); - std::memset(p, CAST(int, args[1]), CAST(size_t, args[2])); - return vm->None; - }); - - vm->bind_func(mod, "memcpy", 3, [](VM* vm, ArgsView args) { - void* dst = CAST(void*, args[0]); - void* src = CAST(void*, args[1]); - i64 size = CAST(i64, args[2]); - std::memcpy(dst, src, size); - return vm->None; - }); - - vm->register_user_class(mod, "void_p", VM::tp_object, true); - vm->register_user_class(mod, "struct", VM::tp_object, true); - - mod->attr().set("NULL", vm->new_user_object(nullptr)); - - vm->bind(mod, "p_cast(ptr: 'void_p', cls: type[T]) -> T", [](VM* vm, ArgsView args) { - VoidP& ptr = CAST(VoidP&, args[0]); - vm->check_type(args[1], vm->tp_type); - Type cls = PK_OBJ_GET(Type, args[1]); - if(!vm->issubclass(cls, vm->_tp_user())) { vm->ValueError("expected a subclass of void_p"); } - return vm->new_object(cls, ptr.ptr); - }); - - vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args) { - VoidP& ptr = CAST(VoidP&, args[0]); - return VAR(reinterpret_cast(ptr.ptr)); - }); - - vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args) { - VoidP& ptr = CAST(VoidP&, args[0]); - void* value = *reinterpret_cast(ptr.ptr); - return vm->new_object(args[0].type, value); - }); - - PyObject* type; - Type type_t; - -#define BIND_PRIMITIVE(T, CNAME) \ - vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args) { \ - T val = CAST(T, args[0]); \ - return vm->new_user_object(&val, sizeof(T)); \ - }); \ - type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user(), true); \ - mod->attr().set(CNAME "_p", 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; \ - return VAR(*target); \ - }); \ - vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args) { \ - obj_get_t voidp = PK_OBJ_GET(VoidP, args[0]); \ - T val = CAST(T, args[1]); \ - T* target = (T*)voidp.ptr; \ - *target = val; \ - return vm->None; \ - }); \ - vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index) { \ - obj_get_t voidp = PK_OBJ_GET(VoidP, obj); \ - i64 offset = CAST(i64, index); \ - T* target = (T*)voidp.ptr; \ - return VAR(target[offset]); \ - }); \ - vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value) { \ - obj_get_t voidp = PK_OBJ_GET(VoidP, obj); \ - i64 offset = CAST(i64, index); \ - T* target = (T*)voidp.ptr; \ - target[offset] = CAST(T, value); \ - }); \ - vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs) { \ - obj_get_t voidp = PK_OBJ_GET(VoidP, lhs); \ - i64 offset = CAST(i64, rhs); \ - T* target = (T*)voidp.ptr; \ - return vm->new_object(lhs.type, target + offset); \ - }); \ - vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs) { \ - obj_get_t voidp = PK_OBJ_GET(VoidP, lhs); \ - i64 offset = CAST(i64, rhs); \ - T* target = (T*)voidp.ptr; \ - return vm->new_object(lhs.type, target - offset); \ - }); \ - vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str { \ - VoidP& self = _CAST(VoidP&, obj); \ - return _S("<", CNAME, "* at ", self.hex(), ">"); \ - }); - - BIND_PRIMITIVE(char, "char") - BIND_PRIMITIVE(unsigned char, "uchar") - BIND_PRIMITIVE(short, "short") - BIND_PRIMITIVE(unsigned short, "ushort") - BIND_PRIMITIVE(int, "int") - BIND_PRIMITIVE(unsigned int, "uint") - BIND_PRIMITIVE(long, "long") - BIND_PRIMITIVE(unsigned long, "ulong") - BIND_PRIMITIVE(long long, "longlong") - BIND_PRIMITIVE(unsigned long long, "ulonglong") - BIND_PRIMITIVE(float, "float") - BIND_PRIMITIVE(double, "double") - BIND_PRIMITIVE(bool, "bool") - -#undef BIND_PRIMITIVE - - 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; - return VAR(target); - }); - - vm->bind(char_p_t, "write_string(self, value: str)", [](VM* vm, ArgsView args) { - obj_get_t voidp = PK_OBJ_GET(VoidP, args[0]); - std::string_view sv = CAST(Str&, args[1]).sv(); - char* target = (char*)voidp.ptr; - std::memcpy(target, sv.data(), sv.size()); - target[sv.size()] = '\0'; - return vm->None; - }); -} - -PyVar from_void_p(VM* vm, void* p) { return vm->new_user_object(p); } - -} // namespace pkpy diff --git a/src/interpreter/frame.c b/src/interpreter/frame.c new file mode 100644 index 00000000..7ae144d2 --- /dev/null +++ b/src/interpreter/frame.c @@ -0,0 +1,133 @@ +#include "pocketpy/interpreter/frame.h" +#include "pocketpy/objects/object.h" + +void ValueStack__ctor(ValueStack* self) { + self->sp = self->begin; + self->end = self->begin + PK_VM_STACK_SIZE; +} + +void ValueStack__clear(ValueStack* self) { + self->sp = self->begin; +} + +PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, StrName name){ + int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1); + if(index == -1) return NULL; + return &locals[index]; +} + +pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co) { + pk_NameDict* dict = pk_NameDict__new(); + c11_vector__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) { + PyVar value = locals[entry->value]; + if(!py_isnull(&value)){ + pk_NameDict__set(dict, entry->key, value); + } + } + return dict; +} + +UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset){ + UnwindTarget* self = malloc(sizeof(UnwindTarget)); + self->next = next; + self->iblock = iblock; + self->offset = offset; + return self; +} + +void UnwindTarget__delete(UnwindTarget* self){ + free(self); +} + +Frame* Frame__new(Frame* f_back, const CodeObject* co, PyObject* module_, PyObject* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co){ + static_assert(sizeof(Frame) <= kPoolFrameBlockSize); + Frame* self = PoolFrame_alloc(); + self->f_back = f_back; + self->ip = (Bytecode*)co->codes.data - 1; + self->co = co; + self->module_ = module_; + self->function = function; + self->p0 = p0; + self->locals = locals; + self->locals_co = locals_co; + self->uw_list = NULL; + return self; +} + +void Frame__delete(Frame* self){ + while(self->uw_list) { + UnwindTarget* p = self->uw_list; + self->uw_list = p->next; + UnwindTarget__delete(p); + } + PoolFrame_dealloc(self); +} + +int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s){ + // try to find a parent try block + int iblock = Frame__iblock(self); + while(iblock >= 0) { + CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, iblock); + if(block->type == CodeBlockType_TRY_EXCEPT) break; + iblock = block->parent; + } + if(iblock < 0) return -1; + PyVar obj = *--_s->sp; // pop exception object + UnwindTarget* uw = Frame__find_unwind_target(self, iblock); + _s->sp = (self->locals + uw->offset); // unwind the stack + *(_s->sp++) = obj; // push it back + return c11__at(CodeBlock, &self->co->blocks, iblock)->end; +} + +void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target){ + int iblock = Frame__iblock(self); + if(target >= self->co->codes.count) { + while(iblock >= 0) iblock = Frame__exit_block(self, _s, iblock); + } else { + // BUG (solved) + // for i in range(4): + // _ = 0 + // # if there is no op here, the block check will fail + // while i: --i + int next_block = c11__at(BytecodeEx, &self->co->codes_ex, target)->iblock; + while(iblock >= 0 && iblock != next_block) + iblock = Frame__exit_block(self, _s, iblock); + assert(iblock == next_block); + } +} + +int Frame__prepare_loop_break(Frame* self, ValueStack* _s){ + int iblock = Frame__iblock(self); + int target = c11__getitem(CodeBlock, &self->co->blocks, iblock).end; + Frame__prepare_jump_break(self, _s, target); + return target; +} + +int Frame__exit_block(Frame* self, ValueStack* _s, int iblock){ + CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, iblock); + if(block->type == CodeBlockType_FOR_LOOP) { + _s->sp--; // pop iterator + } else if(block->type == CodeBlockType_CONTEXT_MANAGER) { + _s->sp--; // pop context variable + } + return block->parent; +} + +UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock){ + UnwindTarget* uw; + for(uw = self->uw_list; uw; uw = uw->next) { + if(uw->iblock == iblock) return uw; + } + return NULL; +} + +void Frame__set_unwind_target(Frame* self, PyVar* sp) { + int iblock = Frame__iblock(self); + UnwindTarget* existing = Frame__find_unwind_target(self, iblock); + if(existing) { + existing->offset = sp - self->locals; + } else { + UnwindTarget* prev = self->uw_list; + self->uw_list = UnwindTarget__new(prev, iblock, sp - self->locals); + } +} diff --git a/src/interpreter/frame.cpp b/src/interpreter/frame.cpp deleted file mode 100644 index 22c8deee..00000000 --- a/src/interpreter/frame.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "pocketpy/interpreter/frame.hpp" -#include "pocketpy/common/smallmap.h" - -namespace pkpy { -PyVar* FastLocals::try_get_name(StrName name) { - int index = c11_smallmap_n2i__get(&co->varnames_inv, name.index, -1); - if(index == -1) return nullptr; - return &a[index]; -} - -NameDict* FastLocals::to_namedict() { - NameDict* dict = new NameDict(); - for(int i=0; ivarnames_inv.count; i++){ - auto entry = c11__getitem(c11_smallmap_n2i_KV, &co->varnames_inv, i); - PyVar value = a[entry.value]; - if(value) dict->set(StrName(entry.key), value); - } - return dict; -} - -PyVar* Frame::f_closure_try_get(StrName name) { - if(_callable == nullptr) return nullptr; - Function& fn = _callable->as(); - if(fn._closure == nullptr) return nullptr; - return fn._closure->try_get_2(name); -} - -int Frame::prepare_jump_exception_handler(ValueStack* _s) { - // try to find a parent try block - int i = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock; - while(i >= 0) { - CodeBlock* block = c11__at(CodeBlock, &co->blocks, i); - if(block->type == CodeBlockType_TRY_EXCEPT) break; - i = block->parent; - } - if(i < 0) return -1; - PyVar obj = _s->popx(); // pop exception object - UnwindTarget* uw = find_unwind_target(i); - _s->reset(actual_sp_base() + uw->offset); // unwind the stack - _s->push(obj); // push it back - return c11__at(CodeBlock, &co->blocks, i)->end; -} - -int Frame::_exit_block(ValueStack* _s, int i) { - CodeBlock* block = c11__at(CodeBlock, &co->blocks, i); - if(block->type == CodeBlockType_FOR_LOOP) { - _s->pop(); // pop the iterator - } else if(block->type == CodeBlockType_CONTEXT_MANAGER) { - _s->pop(); - } - return block->parent; -} - -void Frame::prepare_jump_break(ValueStack* _s, int target) { - int i = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock; - if(target >= co->codes.count) { - while(i >= 0) i = _exit_block(_s, i); - } else { - // BUG (solved) - // for i in range(4): - // _ = 0 - // # if there is no op here, the block check will fail - // while i: --i - int next_block = c11__at(BytecodeEx, &co->codes_ex, target)->iblock; - while(i >= 0 && i != next_block) - i = _exit_block(_s, i); - assert(i == next_block); - } -} - -void Frame::set_unwind_target(PyVar* _sp) { - int iblock = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock; - UnwindTarget* existing = find_unwind_target(iblock); - if(existing) { - existing->offset = _sp - actual_sp_base(); - } else { - UnwindTarget* prev = _uw_list; - _uw_list = new UnwindTarget(iblock, _sp - actual_sp_base()); - _uw_list->next = prev; - } -} - -UnwindTarget* Frame::find_unwind_target(int iblock) { - UnwindTarget* p; - for(p = _uw_list; p != nullptr; p = p->next) { - if(p->iblock == iblock) return p; - } - return nullptr; -} - -Frame::~Frame() { - while(_uw_list != nullptr) { - UnwindTarget* p = _uw_list; - _uw_list = p->next; - delete p; - } -} - -void CallStack::pop() { - assert(!empty()); - LinkedFrame* p = _tail; - _tail = p->f_back; - p->~LinkedFrame(); - PoolFrame_dealloc(p); - --_size; -} - -LinkedFrame* CallStack::popx() { - assert(!empty()); - LinkedFrame* p = _tail; - _tail = p->f_back; - --_size; - p->f_back = nullptr; // unlink - return p; -} - -void CallStack::pushx(LinkedFrame* p) { - p->f_back = _tail; - _tail = p; - ++_size; -} -} // namespace pkpy diff --git a/src/interpreter/gc.c b/src/interpreter/gc.c index e373adb1..8da80cf4 100644 --- a/src/interpreter/gc.c +++ b/src/interpreter/gc.c @@ -1,7 +1,7 @@ #include "pocketpy/interpreter/gc.h" #include "pocketpy/common/memorypool.h" -void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pkpy_VM *vm){ +void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pk_VM *vm){ c11_vector__ctor(&self->no_gc, sizeof(PyObject*)); c11_vector__ctor(&self->gen, sizeof(PyObject*)); @@ -88,9 +88,8 @@ int pk_ManagedHeap__sweep(pk_ManagedHeap *self){ return freed; } -PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, pkpy_Type type, int size, bool gc){ +PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, Type type, int size){ PyObject* obj; - // TODO: can we use compile time check? if(size <= kPoolObjectBlockSize){ obj = PoolObject_alloc(); PyObject__ctor(obj, type, false); @@ -98,12 +97,21 @@ PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, pkpy_Type type, int size, bo obj = malloc(size); PyObject__ctor(obj, type, true); } - // TODO: can we use compile time check? - if(gc){ - c11_vector__push(PyObject*, &self->gen, obj); - self->gc_counter++; - }else{ - c11_vector__push(PyObject*, &self->no_gc, obj); - } + c11_vector__push(PyObject*, &self->no_gc, obj); return obj; } + +PyObject* pk_ManagedHeap__gcnew(pk_ManagedHeap *self, Type type, int size){ + PyObject* obj; + if(size <= kPoolObjectBlockSize){ + obj = PoolObject_alloc(); + PyObject__ctor(obj, type, false); + }else{ + obj = malloc(size); + PyObject__ctor(obj, type, true); + } + c11_vector__push(PyObject*, &self->gen, obj); + self->gc_counter++; + return obj; +} + diff --git a/src/interpreter/iter.cpp b/src/interpreter/iter.cpp deleted file mode 100644 index 4f30bfc2..00000000 --- a/src/interpreter/iter.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "pocketpy/interpreter/iter.hpp" -#include "pocketpy/objects/base.h" - -namespace pkpy { - -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); - self.current += self.r.step; - return 1; - }); -} - -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); - self.current += self.r.step; - return 1; - }); -} - -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++); - return 1; - }); -} - -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; - int start = self.i; - int len = c11__u8_header(s[self.i], false); - self.i += len; - vm->s_data.push(VAR(s.slice(start, self.i))); - return 1; - }); -} - -PyVar Generator::next(VM* vm) { - if(state == 2) return vm->StopIteration; - // reset frame._sp_base - lf->frame._sp_base = vm->s_data._sp; - lf->frame._locals.a = vm->s_data._sp; - // restore the context - for(PyVar obj: s_backup) - vm->s_data.push(obj); - s_backup.clear(); - vm->callstack.pushx(lf); - lf = nullptr; - - PyVar ret; - try { - ret = vm->__run_top_frame(); - } catch(...) { - state = 2; // end this generator immediately when an exception is thrown - throw; - } - - if(ret.type == tp_op_yield) { - // backup the context - lf = vm->callstack.popx(); - ret = vm->s_data.popx(); - for(PyVar obj: lf->frame.stack_view(&vm->s_data)) - s_backup.push_back(obj); - vm->s_data.reset(lf->frame._sp_base); - // TODO: should we add this snippet here? - // #if PK_ENABLE_PROFILER - // if(!_next_breakpoint.empty() && callstack.size()<_next_breakpoint.callstack_size){ - // _next_breakpoint = NextBreakpoint(); - // } - // #endif - state = 1; - if(ret == vm->StopIteration) state = 2; - return ret; - } else { - state = 2; - return vm->StopIteration; - } -} - -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; - vm->s_data.push(retval); - return 1; - }); -} - -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); - PyVar key, val; - if (pkpy_DictIter__next(&self.it, (PyVar*)(&key), (PyVar*)(&val))) { - vm->s_data.push(key); - vm->s_data.push(val); - return 2; - } - return 0; - }); -} - -PyVar VM::__py_generator(LinkedFrame* frame, ArgsView buffer) { - return vm->new_user_object(std::move(frame), buffer); -} - -} // namespace pkpy diff --git a/src/interpreter/profiler.cpp b/src/interpreter/profiler.cpp deleted file mode 100644 index 2482f4d2..00000000 --- a/src/interpreter/profiler.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "pocketpy/interpreter/profiler.hpp" - -#if PK_ENABLE_PROFILER -namespace pkpy { - -static std::string left_pad(std::string s, int width) { - int n = width - s.size(); - if(n <= 0) return s; - return std::string(n, ' ') + s; -} - -static std::string to_string_1f(f64 x) { - char buf[32]; - snprintf(buf, 32, "%.1f", x); - return buf; -} - -void LineProfiler::begin() { frames.clear(); } - -void LineProfiler::_step(int callstack_size, Frame* frame) { - auto line_info = frame->co->lines[frame->ip()]; - if(line_info.is_virtual) return; - std::string_view filename = frame->co->src.filename().sv(); - int line = line_info.lineno; - - if(frames.empty()) { - frames.push_back({callstack_size, frame, clock(), nullptr}); - } else { - _step_end(callstack_size, frame, line); - } - - _LineRecord* file_records; - - auto p = records.try_get(filename); - if(p == nullptr) { - int total_lines = frame->co->src->line_starts.size(); - file_records = new _LineRecord[total_lines + 1]; - for(int i = 1; i <= total_lines; i++) file_records[i].line = i; - records.insert(filename, file_records); - }else{ - file_records = *p; - } - - frames.back().prev_record = &file_records[line]; -} - -void LineProfiler::_step_end(int callstack_size, Frame* frame, int line) { - clock_t now = clock(); - _FrameRecord& top_frame_record = frames.back(); - _LineRecord* prev_record = top_frame_record.prev_record; - - int id_delta = callstack_size - top_frame_record.callstack_size; - assert(abs(id_delta) <= 1); - - // current line is about to change - if(prev_record->line != line) { - clock_t delta = now - top_frame_record.prev_time; - top_frame_record.prev_time = now; - if(id_delta != 1) prev_record->hits++; - prev_record->time += delta; - } - - if(id_delta == 1) { - frames.push_back({callstack_size, frame, now, nullptr}); - } else { - if(id_delta == -1) frames.pop_back(); - } -} - -void LineProfiler::end() { - clock_t now = clock(); - _FrameRecord& top_frame_record = frames.back(); - _LineRecord* prev_record = top_frame_record.prev_record; - - clock_t delta = now - top_frame_record.prev_time; - top_frame_record.prev_time = now; - prev_record->hits++; - prev_record->time += delta; - - frames.pop_back(); - assert(frames.empty()); -} - -Str LineProfiler::stats() { - SStream ss; - for(FuncDecl* decl: functions) { - int start_line = decl->code->start_line; - int end_line = decl->code->end_line; - if(start_line == -1 || end_line == -1) continue; - std::string_view filename = decl->code->src.filename().sv(); - const _LineRecord* file_records = records[filename]; - clock_t total_time = 0; - for(int line = start_line; line <= end_line; line++) { - total_time += file_records[line].time; - } - ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n"; - ss << "File: " << filename << "\n"; - ss << "Function: " << decl->code->name << " at line " << start_line << "\n"; - ss << "Line # Hits Time Per Hit % Time Line Contents\n"; - ss << "==============================================================\n"; - for(int line = start_line; line <= end_line; line++) { - const _LineRecord& record = file_records[line]; - if(!record.is_valid()) continue; - ss << left_pad(std::to_string(line), 6); - if(record.hits == 0) { - ss << std::string(10 + 13 + 9 + 9, ' '); - } else { - ss << left_pad(std::to_string(record.hits), 10); - ss << left_pad(std::to_string(record.time), 13); - ss << left_pad(std::to_string(record.time / record.hits), 9); - if(total_time == 0) { - ss << left_pad("0.0", 9); - } else { - ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9); - } - } - // line_content - ss << " " << decl->code->src->get_line(line) << "\n"; - } - ss << "\n"; - } - return ss.str(); -} - -LineProfiler::~LineProfiler() { - for(auto& p: records) delete p.second; -} - -} // namespace pkpy - -#endif \ No newline at end of file diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index af63a36b..b787718d 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -1,40 +1,161 @@ -// #include "pocketpy/interpreter/vm.h" -// #include "pocketpy/objects/base.h" +#include "pocketpy/interpreter/vm.h" -// void pkpy_VM__ctor(pkpy_VM* self){ -// self->True = (PyVar){ -// .type=tp_bool, -// .is_ptr=true, -// .extra=1, -// ._obj=pkpy_VM__gcnew(self, tp_bool) -// }; +static unsigned char* pk_default_import_file(pk_VM* vm, const char* path){ + return NULL; +} -// self->False = (PyVar){ -// .type=tp_bool, -// .is_ptr=true, -// .extra=0, -// ._obj=pkpy_VM__gcnew(self, tp_bool) -// }; +static void pk_default_stdout(pk_VM* vm, const char* s){ + fprintf(stdout, "%s", s); +} -// self->None = (PyVar){ -// .type=tp_none_type, -// .is_ptr=true, -// ._obj=pkpy_VM__gcnew(self, tp_none_type) -// }; +static void pk_default_stderr(pk_VM* vm, const char* s){ + fprintf(stderr, "%s", s); +} -// self->NotImplemented = (PyVar){ -// .type=tp_not_implemented_type, -// .is_ptr=true, -// ._obj=pkpy_VM__gcnew(self, tp_not_implemented_type) -// }; +void pk_TypeInfo__ctor(pk_TypeInfo *self, StrName name, Type base, PyObject* obj, PyObject* module, bool subclass_enabled){ + memset(self, 0, sizeof(pk_TypeInfo)); + + self->name = name; + self->base = base; -// self->Ellipsis = (PyVar){ -// .type=tp_ellipsis, -// .is_ptr=true, -// ._obj=pkpy_VM__gcnew(self, tp_ellipsis) -// }; -// } + self->obj = obj; + self->module = module; + self->subclass_enabled = subclass_enabled; -// void pkpy_VM__dtor(pkpy_VM* self){ + c11_vector__ctor(&self->annotated_fields, sizeof(StrName)); +} -// } \ No newline at end of file +void pk_TypeInfo__dtor(pk_TypeInfo *self){ + c11_vector__dtor(&self->annotated_fields); +} + +void pk_VM__ctor(pk_VM* self){ + self->top_frame = NULL; + + pk_NameDict__ctor(&self->modules); + c11_vector__ctor(&self->types, sizeof(pk_TypeInfo)); + + self->StopIteration = NULL; + self->builtins = NULL; + self->main = NULL; + + self->_ceval_on_step = NULL; + self->_import_file = pk_default_import_file; + self->_stdout = pk_default_stdout; + self->_stderr = pk_default_stderr; + + self->__last_exception = NULL; + self->__curr_class = NULL; + self->__cached_object_new = NULL; + self->__dynamic_func_decl = NULL; + + pk_ManagedHeap__ctor(&self->heap, self); + ValueStack__ctor(&self->stack); + + self->True = (PyVar){.type=tp_bool, .is_ptr=true, .extra=1, + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 1), + }; + self->False = (PyVar){.type=tp_bool, .is_ptr=true, .extra=0, + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 1), + }; + self->None = (PyVar){.type=tp_none_type, .is_ptr=true, + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_none_type, 1), + }; + self->NotImplemented = (PyVar){.type=tp_not_implemented_type, .is_ptr=true, + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_not_implemented_type, 1), + }; + self->Ellipsis = (PyVar){.type=tp_ellipsis, .is_ptr=true, + ._obj=pk_ManagedHeap__gcnew(&self->heap, tp_ellipsis, 1), + }; + + /* Init Builtin Types */ + // 0: unused + pk_TypeInfo__ctor(c11_vector__emplace(&self->types), 0, 0, NULL, NULL); + #define validate(t, expr) if(t != (expr)) abort() + + validate(tp_object, pk_VM__new_type(self, "object", 0, NULL, true)); + validate(tp_type, pk_VM__new_type(self, "type", 1, NULL, false)); + + validate(tp_int, pk_VM__new_type(self, "int", tp_object, NULL, false)); + validate(tp_float, pk_VM__new_type(self, "float", tp_object, NULL, false)); + validate(tp_bool, pk_VM__new_type(self, "bool", tp_object, NULL, false)); + validate(tp_str, pk_VM__new_type(self, "str", tp_object, NULL, false)); + + validate(tp_list, pk_VM__new_type(self, "list", tp_object, NULL, false)); + validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false)); + + validate(tp_slice, pk_VM__new_type(self, "slice", tp_object, NULL, false)); + validate(tp_range, pk_VM__new_type(self, "range", tp_object, NULL, false)); + validate(tp_module, pk_VM__new_type(self, "module", tp_object, NULL, false)); + + validate(tp_function, pk_VM__new_type(self, "function", tp_object, NULL, false)); + validate(tp_native_func, pk_VM__new_type(self, "native_func", tp_object, NULL, false)); + validate(tp_bound_method, pk_VM__new_type(self, "bound_method", tp_object, NULL, false)); + + validate(tp_super, pk_VM__new_type(self, "super", tp_object, NULL, false)); + validate(tp_exception, pk_VM__new_type(self, "Exception", tp_object, NULL, true)); + validate(tp_bytes, pk_VM__new_type(self, "bytes", tp_object, NULL, false)); + validate(tp_mappingproxy, pk_VM__new_type(self, "mappingproxy", tp_object, NULL, false)); + + validate(tp_dict, pk_VM__new_type(self, "dict", tp_object, NULL, true)); + validate(tp_property, pk_VM__new_type(self, "property", tp_object, NULL, false)); + validate(tp_star_wrapper, pk_VM__new_type(self, "star_wrapper", tp_object, NULL, false)); + + validate(tp_staticmethod, pk_VM__new_type(self, "staticmethod", tp_object, NULL, false)); + validate(tp_classmethod, pk_VM__new_type(self, "classmethod", tp_object, NULL, false)); + + validate(tp_none_type, pk_VM__new_type(self, "NoneType", tp_object, NULL, false)); + validate(tp_not_implemented_type, pk_VM__new_type(self, "NotImplementedType", tp_object, NULL, false)); + validate(tp_ellipsis, pk_VM__new_type(self, "ellipsis", tp_object, NULL, false)); + + validate(tp_op_call, pk_VM__new_type(self, "__op_call", tp_object, NULL, false)); + validate(tp_op_yield, pk_VM__new_type(self, "__op_yield", tp_object, NULL, false)); + + validate(tp_syntax_error, pk_VM__new_type(self, "SyntaxError", tp_exception, NULL, false)); + validate(tp_stop_iteration, pk_VM__new_type(self, "StopIteration", tp_exception, NULL, false)); + #undef validate + + self->StopIteration = c11__at(pk_TypeInfo, &self->types, tp_stop_iteration)->obj; + self->builtins = pk_VM__new_module(self, "builtins", NULL); + + /* Setup Public Builtin Types */ + Type public_types[] = { + tp_object, tp_type, + tp_int, tp_float, tp_bool, tp_str, + tp_list, tp_tuple, + tp_slice, tp_range, + tp_bytes, tp_dict, tp_property, + tp_exception, tp_stop_iteration, tp_syntax_error + }; + + for(int i=0; itypes, t); + pk_NameDict__set(self->builtins->dict, ti->name, PyVar__fromobj(ti->obj)); + } + pk_NameDict__set(self->builtins->dict, pk_StrName__map("NotImplemented"), self->NotImplemented); + + /* Do Buildin Bindings*/ + // TODO: ... + self->main = pk_VM__new_module(self, "__main__", NULL); +} + +void pk_VM__dtor(pk_VM* self){ + PK_DECREF(self->__dynamic_func_decl); + // destroy all objects + pk_ManagedHeap__dtor(&self->heap); + // clear frames + // ... + pk_NameDict__dtor(&self->modules); + c11_vector__dtor(&self->types); + ValueStack__clear(&self->stack); +} + +Type pk_VM__new_type(pk_VM* self, const char* name, Type base, PyObject* module, bool subclass_enabled){ + Type type = self->types.count; + pk_TypeInfo* ti = c11_vector__emplace(&self->types); + PyObject* typeobj = pk_ManagedHeap__gcnew(&self->heap, tp_type, PK_OBJ_SIZEOF(Type)); + *PyObject__as(Type, typeobj) = type; + pk_TypeInfo__ctor(ti, pk_StrName__map(name), base, typeobj, module, subclass_enabled); + return type; +} diff --git a/src/interpreter/vm.cpp b/src/interpreter/vm.cpp index 904c0d65..5354229e 100644 --- a/src/interpreter/vm.cpp +++ b/src/interpreter/vm.cpp @@ -1,5 +1,6 @@ #include "pocketpy/interpreter/vm.hpp" #include "pocketpy/common/memorypool.h" +#include "pocketpy/interpreter/frame.h" #include "pocketpy/objects/base.h" #include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/public.h" @@ -86,10 +87,11 @@ struct JsonSerializer { }; VM::VM(bool enable_os) : enable_os(enable_os) { - pkpy_g.vm = (pkpy_VM*)this; // setup the current VM + pkpy_g.vm = (pk_VM*)this; // setup the current VM Pools_initialize(); - pkpy_StrName__initialize(); - pk_ManagedHeap__ctor(&heap, (pkpy_VM*)this); + pk_StrName__initialize(); + + pk_ManagedHeap__ctor(&heap, (pk_VM*)this); static ::PyObject __true_obj = {tp_bool, false, false, NULL}; static ::PyObject __false_obj = {tp_bool, false, false, NULL}; @@ -127,7 +129,7 @@ Str VM::py_str(PyVar obj) { if(ti->m__str__) return ti->m__str__(this, obj); PyVar self; PyVar f = get_unbound_method(obj, __str__, &self, false); - if(self) { + if(self.type) { PyVar retval = call_method(self, f); if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__str__ must return str"); } return PK_OBJ_GET(Str, retval); @@ -153,7 +155,7 @@ PyVar VM::py_iter(PyVar obj) { if(ti->m__iter__) return ti->m__iter__(this, obj); PyVar self; PyVar iter_f = get_unbound_method(obj, __iter__, &self, false); - if(self) return call_method(self, iter_f); + if(self.type) return call_method(self, iter_f); TypeError(_type_name(vm, _tp(obj)).escape() + " object is not iterable"); return nullptr; } @@ -223,8 +225,8 @@ PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject stderr_write(msg); } CodeObject__delete(code); - callstack.clear(); - s_data.clear(); + while(top_frame) __pop_frame(); // this changes s_data.sp, it must put before ValueStack__clear(); + ValueStack__clear(&s_data); return nullptr; } @@ -320,7 +322,7 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) { if(args_tuple.size() == 0) TypeError("expected at least 1 argument, got 0"); - ArgsView view(nullptr, nullptr); + ArgsView view; if(args_tuple.size() == 1) { view = cast_array_view(args_tuple[0]); } else { @@ -428,11 +430,11 @@ VM::~VM() { PK_DECREF(__dynamic_func_decl); // destroy all objects pk_ManagedHeap__dtor(&heap); + pk_NameDict__dtor(&_modules); // clear everything - callstack.clear(); - s_data.clear(); + while(top_frame) __pop_frame(); // this changes s_data.sp, it must put before ValueStack__clear(); + ValueStack__clear(&s_data); _all_types.clear(); - _modules.clear(); _lazy_modules.clear(); } @@ -608,7 +610,7 @@ PyVar VM::__py_exec_internal(const CodeObject* code, PyVar globals, PyVar locals }); PyObject* _callable = new_object(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure).get(); - retval = vm->_exec(code, globals_obj, _callable, vm->s_data._sp); + retval = vm->_exec(code, globals_obj, _callable, vm->s_data.sp); } if(globals_dict) { @@ -1063,7 +1065,7 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const } PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { - PyVar* p1 = s_data._sp - KWARGC * 2; + PyVar* p1 = (PyVar*)(s_data.sp - KWARGC * 2); PyVar* p0 = p1 - ARGC - 2; // [callable, , args..., kwargs...] // ^p0 ^p1 ^_sp @@ -1082,14 +1084,14 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { } ArgsView args((!p0[1]) ? (p0 + 2) : (p0 + 1), p1); - ArgsView kwargs(p1, s_data._sp); + ArgsView kwargs(p1, s_data.sp); PyVar* _base = args.begin(); if(callable_t == tp_function) { /*****************_py_call*****************/ // check stack overflow - if(s_data.is_overflow()) StackOverflowError(); + if(s_data.sp > s_data.end) StackOverflowError(); const Function& fn = PK_OBJ_GET(Function, callable); const CodeObject* co = fn.decl->code; @@ -1098,7 +1100,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { case FuncType_NORMAL: __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl); // copy buffer back to stack - s_data.reset(_base + co->nlocals); + s_data.sp = (_base + co->nlocals); for(int j = 0; j < co->nlocals; j++) _base[j] = __vectorcall_buffer[j]; break; @@ -1114,9 +1116,9 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { } // [callable, , args..., local_vars...] // ^p0 ^p1 ^_sp - s_data.reset(_base + co->nlocals); + s_data.sp = (_base + co->nlocals); // initialize local variables to PY_NULL - std::memset(p1, 0, (char*)s_data._sp - (char*)p1); + std::memset(p1, 0, (char*)s_data.sp - (char*)p1); break; case FuncType_EMPTY: if(args.size() != fn.decl->args.count){ @@ -1128,11 +1130,11 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { if(!kwargs.empty()){ TypeError(pk_format("{} takes no keyword arguments", &co->name)); } - s_data.reset(p0); + s_data.sp = p0; return None; case FuncType_GENERATOR: __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl); - s_data.reset(p0); + s_data.sp = p0; callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr); return __py_generator(callstack.popx(), ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals)); @@ -1141,7 +1143,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { // simple or normal callstack.emplace(p0, co, fn._module, callable.get(), args.begin()); - if(op_call) return pkpy_OP_CALL; + if(op_call) return PY_OP_CALL; return __run_top_frame(); /*****************_py_call*****************/ } @@ -1153,10 +1155,10 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { int co_nlocals = f.decl->code->nlocals; __prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl); // copy buffer back to stack - s_data.reset(_base + co_nlocals); + s_data.sp = (_base + co_nlocals); for(int j = 0; j < co_nlocals; j++) _base[j] = __vectorcall_buffer[j]; - ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp)); + ret = f.call(vm, ArgsView(s_data.sp - co_nlocals, s_data.sp)); } else { if(f.argc != -1) { if(KWARGC != 0) @@ -1166,7 +1168,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { } ret = f.call(this, args); } - s_data.reset(p0); + s_data.sp = (p0); return ret; } @@ -1180,7 +1182,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { obj = vm->new_object(PK_OBJ_GET(Type, callable)); } else { PUSH(new_f); - PUSH(PY_NULL); + PUSH_NULL(); PUSH(callable); // cls for(PyVar o: args) PUSH(o); @@ -1204,7 +1206,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) { // in cpython it raises a TypeError if the return value is not None } else { // manually reset the stack - s_data.reset(p0); + s_data.sp = (p0); } return obj; } @@ -1474,7 +1476,7 @@ void VM::_error(PyVar e_obj) { void VM::__raise_exc(bool re_raise) { Frame* frame = &callstack.top(); - Exception& e = PK_OBJ_GET(Exception, s_data.top()); + Exception& e = PK_OBJ_GET(Exception, (PyVar&)s_data.sp[-1]); if(!re_raise) { e._ip_on_error = frame->ip(); e._code_on_error = (void*)frame->co; @@ -1537,9 +1539,10 @@ void VM::bind__delitem__(Type type, void (*f)(VM*, PyVar, PyVar)) { PyVar VM::__pack_next_retval(unsigned n) { if(n == 0) return StopIteration; - if(n == 1) return s_data.popx(); - PyVar retval = VAR(s_data.view(n).to_tuple()); - s_data._sp -= n; + if(n == 1) return *--s_data.sp; + ArgsView view(s_data.sp - n, s_data.sp); + PyVar retval = VAR(view.to_tuple()); + s_data.sp -= n; return retval; } @@ -1692,8 +1695,12 @@ void NextBreakpoint::_step(VM* vm) { #endif void VM::__pop_frame() { - s_data.reset(callstack.top()._sp_base); - callstack.pop(); + assert(top_frame); + s_data.sp = top_frame->p0; + // callstack.pop() + Frame* p = top_frame; + top_frame = p->f_back; + Frame__delete(p); #if PK_ENABLE_PROFILER if(!_next_breakpoint.empty() && callstack.size() < _next_breakpoint.callstack_size) { @@ -1937,8 +1944,8 @@ extern "C"{ 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(self->_gc_marker_ex) self->_gc_marker_ex((pkpy_VM*)vm); + vm->__stack_gc_mark((PyVar*)vm->s_data.begin, (PyVar*)vm->s_data.end); + if(self->_gc_marker_ex) self->_gc_marker_ex((pk_VM*)vm); } void pk_ManagedHeap__delete_obj(pk_ManagedHeap* self, ::PyObject* __obj){ diff --git a/src/modules/array2d.cpp b/src/modules/array2d.cpp deleted file mode 100644 index 12e833a8..00000000 --- a/src/modules/array2d.cpp +++ /dev/null @@ -1,406 +0,0 @@ -#include "pocketpy/modules/array2d.hpp" -#include "pocketpy/interpreter/bindings.hpp" - -namespace pkpy { - -struct Array2d { - PK_ALWAYS_PASS_BY_POINTER(Array2d) - - PyVar* data; - int n_cols; - int n_rows; - int numel; - - Array2d() { - data = nullptr; - n_cols = 0; - n_rows = 0; - numel = 0; - } - - void init(int n_cols, int n_rows) { - this->n_cols = n_cols; - this->n_rows = n_rows; - this->numel = n_cols * n_rows; - this->data = new PyVar[numel]; - } - - bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; } - - void check_valid(VM* vm, int col, int row) const { - if(is_valid(col, row)) return; - vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')')); - } - - PyVar _get(int col, int row) { return data[row * n_cols + col]; } - - void _set(int col, int row, PyVar value) { data[row * n_cols + col] = value; } - - 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); - }); - - vm->bind(type, "__init__(self, n_cols: int, n_rows: int, default=None)", [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - int n_cols = CAST(int, args[1]); - int n_rows = CAST(int, args[2]); - if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); } - self.init(n_cols, n_rows); - if(vm->py_callable(args[3])) { - for(int i = 0; i < self.numel; i++) - self.data[i] = vm->call(args[3]); - } else { - for(int i = 0; i < self.numel; i++) - self.data[i] = args[3]; - } - return vm->None; - }); - - PY_READONLY_FIELD(Array2d, "n_cols", n_cols); - PY_READONLY_FIELD(Array2d, "n_rows", n_rows); - PY_READONLY_FIELD(Array2d, "width", n_cols); - PY_READONLY_FIELD(Array2d, "height", n_rows); - PY_READONLY_FIELD(Array2d, "numel", numel); - - // _get - vm->bind_func(type, "_get", 3, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - int col = CAST(int, args[1]); - int row = CAST(int, args[2]); - self.check_valid(vm, col, row); - return self._get(col, row); - }); - - // _set - vm->bind_func(type, "_set", 4, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - int col = CAST(int, args[1]); - int row = CAST(int, args[2]); - self.check_valid(vm, col, row); - self._set(col, row, args[3]); - return vm->None; - }); - - vm->bind_func(type, "is_valid", 3, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - int col = CAST(int, args[1]); - int row = CAST(int, args[2]); - return VAR(self.is_valid(col, row)); - }); - - vm->bind(type, "get(self, col: int, row: int, default=None)", [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - int col = CAST(int, args[1]); - int row = CAST(int, args[2]); - if(!self.is_valid(col, row)) return args[3]; - return self._get(col, row); - }); - -#define HANDLE_SLICE() \ - int start_col, stop_col, step_col; \ - int start_row, stop_row, step_row; \ - vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \ - vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \ - if(step_col != 1 || step_row != 1) vm->ValueError("slice step must be 1"); \ - int slice_width = stop_col - start_col; \ - 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__(type->as(), [](VM* vm, PyVar _0, PyVar _1) { - Array2d& self = PK_OBJ_GET(Array2d, _0); - const Tuple& xy = CAST(Tuple&, _1); - - if(is_int(xy[0]) && is_int(xy[1])) { - i64 col = xy[0]._i64; - i64 row = xy[1]._i64; - self.check_valid(vm, col, row); - return self._get(col, row); - } - - if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)) { - HANDLE_SLICE(); - PyVar new_array_obj = vm->new_user_object(); - Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj); - new_array.init(stop_col - start_col, stop_row - start_row); - for(int j = start_row; j < stop_row; j++) { - for(int i = start_col; i < stop_col; i++) { - new_array._set(i - start_col, j - start_row, self._get(i, j)); - } - } - return new_array_obj; - } - vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index"); - }); - - 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); - if(is_int(xy[0]) && is_int(xy[1])) { - i64 col = xy[0]._i64; - i64 row = xy[1]._i64; - self.check_valid(vm, col, row); - self._set(col, row, _2); - return; - } - - if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)) { - HANDLE_SLICE(); - - bool is_basic_type = false; - switch(vm->_tp(_2)) { - case VM::tp_int: is_basic_type = true; break; - case VM::tp_float: is_basic_type = true; break; - case VM::tp_str: is_basic_type = true; break; - case VM::tp_bool: is_basic_type = true; break; - default: is_basic_type = is_none(_2); - } - - if(is_basic_type) { - for(int j = 0; j < slice_height; j++) - for(int i = 0; i < slice_width; i++) - self._set(i + start_col, j + start_row, _2); - return; - } - - if(!vm->is_user_type(_2)) { - vm->TypeError(_S("expected int/float/str/bool/None or an array2d instance")); - } - - Array2d& other = PK_OBJ_GET(Array2d, _2); - if(slice_width != other.n_cols || slice_height != other.n_rows) { - vm->ValueError("array2d size does not match the slice size"); - } - for(int j = 0; j < slice_height; j++) - for(int i = 0; i < slice_width; i++) - self._set(i + start_col, j + start_row, other._get(i, j)); - return; - } - vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index"); - }); - -#undef HANDLE_SLICE - - vm->bind_func(type, "tolist", 1, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - List t(self.n_rows); - for(int j = 0; j < self.n_rows; j++) { - List row(self.n_cols); - for(int i = 0; i < self.n_cols; i++) - row[i] = self._get(i, j); - t[j] = VAR(std::move(row)); - } - return VAR(std::move(t)); - }); - - vm->bind__len__(type->as(), [](VM* vm, PyVar _0) { - Array2d& self = PK_OBJ_GET(Array2d, _0); - return (i64)self.numel; - }); - - 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, ')'); - }); - - vm->bind_func(type, "map", 2, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - PyVar f = args[1]; - PyVar new_array_obj = vm->new_user_object(); - Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj); - new_array.init(self.n_cols, self.n_rows); - for(int i = 0; i < new_array.numel; i++) { - new_array.data[i] = vm->call(f, self.data[i]); - } - return new_array_obj; - }); - - vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - PyVar new_array_obj = vm->new_user_object(); - Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj); - new_array.init(self.n_cols, self.n_rows); - for(int i = 0; i < new_array.numel; i++) { - new_array.data[i] = self.data[i]; - } - return new_array_obj; - }); - - vm->bind_func(type, "fill_", 2, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - for(int i = 0; i < self.numel; i++) { - self.data[i] = args[1]; - } - return vm->None; - }); - - vm->bind_func(type, "apply_", 2, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - PyVar f = args[1]; - for(int i = 0; i < self.numel; i++) { - self.data[i] = vm->call(f, self.data[i]); - } - return vm->None; - }); - - vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - if(is_type(args[1], VM::tp_list)) { - const List& list = PK_OBJ_GET(List, args[1]); - if(list.size() != self.numel) { - vm->ValueError("list size must be equal to the number of elements in the array2d"); - } - for(int i = 0; i < self.numel; i++) { - self.data[i] = list[i]; - } - return vm->None; - } - Array2d& other = CAST(Array2d&, args[1]); - // if self and other have different sizes, re-initialize self - if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) { - delete self.data; - self.init(other.n_cols, other.n_rows); - } - for(int i = 0; i < self.numel; i++) { - self.data[i] = other.data[i]; - } - return vm->None; - }); - - 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); - if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False; - for(int i = 0; i < self.numel; i++) { - if(vm->py_ne(self.data[i], other.data[i])) return vm->False; - } - return vm->True; - }); - - vm->bind(type, "count_neighbors(self, value, neighborhood='Moore') -> array2d[int]", [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - PyVar new_array_obj = vm->new_user_object(); - Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj); - new_array.init(self.n_cols, self.n_rows); - PyVar value = args[1]; - const Str& neighborhood = CAST(Str&, args[2]); - if(neighborhood == "Moore") { - for(int j = 0; j < new_array.n_rows; j++) { - for(int i = 0; i < new_array.n_cols; i++) { - int count = 0; - count += self.is_valid(i - 1, j - 1) && vm->py_eq(self._get(i - 1, j - 1), value); - count += self.is_valid(i, j - 1) && vm->py_eq(self._get(i, j - 1), value); - count += self.is_valid(i + 1, j - 1) && vm->py_eq(self._get(i + 1, j - 1), value); - count += self.is_valid(i - 1, j) && vm->py_eq(self._get(i - 1, j), value); - count += self.is_valid(i + 1, j) && vm->py_eq(self._get(i + 1, j), value); - count += self.is_valid(i - 1, j + 1) && vm->py_eq(self._get(i - 1, j + 1), value); - count += self.is_valid(i, j + 1) && vm->py_eq(self._get(i, j + 1), value); - count += self.is_valid(i + 1, j + 1) && vm->py_eq(self._get(i + 1, j + 1), value); - new_array._set(i, j, VAR(count)); - } - } - } else if(neighborhood == "von Neumann") { - for(int j = 0; j < new_array.n_rows; j++) { - for(int i = 0; i < new_array.n_cols; i++) { - int count = 0; - count += self.is_valid(i, j - 1) && vm->py_eq(self._get(i, j - 1), value); - count += self.is_valid(i - 1, j) && vm->py_eq(self._get(i - 1, j), value); - count += self.is_valid(i + 1, j) && vm->py_eq(self._get(i + 1, j), value); - count += self.is_valid(i, j + 1) && vm->py_eq(self._get(i, j + 1), value); - new_array._set(i, j, VAR(count)); - } - } - } else { - vm->ValueError("neighborhood must be 'Moore' or 'von Neumann'"); - } - return new_array_obj; - }); - - vm->bind_func(type, "count", 2, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - PyVar value = args[1]; - int count = 0; - for(int i = 0; i < self.numel; i++) - count += vm->py_eq(self.data[i], value); - return VAR(count); - }); - - vm->bind_func(type, "find_bounding_rect", 2, [](VM* vm, ArgsView args) { - Array2d& self = PK_OBJ_GET(Array2d, args[0]); - PyVar value = args[1]; - int left = self.n_cols; - int top = self.n_rows; - int right = 0; - int bottom = 0; - for(int j = 0; j < self.n_rows; j++) { - for(int i = 0; i < self.n_cols; i++) { - if(vm->py_eq(self._get(i, j), value)) { - left = (std::min)(left, i); - top = (std::min)(top, j); - right = (std::max)(right, i); - bottom = (std::max)(bottom, j); - } - } - } - int width = right - left + 1; - int height = bottom - top + 1; - if(width <= 0 || height <= 0) return vm->None; - Tuple t(4); - t[0] = VAR(left); - t[1] = VAR(top); - t[2] = VAR(width); - t[3] = VAR(height); - return VAR(std::move(t)); - }); - } - - void _gc_mark(VM* vm) const { - for(int i = 0; i < numel; i++) - vm->obj_gc_mark(data[i]); - } - - ~Array2d() { delete[] data; } -}; - -struct Array2dIter { - PK_ALWAYS_PASS_BY_POINTER(Array2dIter) - - PyVar ref; - Array2d* a; - int i; - - Array2dIter(PyVar ref, Array2d* a) : ref(ref), a(a), i(0) {} - - void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); } - - 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); - vm->s_data.emplace(VM::tp_int, res.rem); - vm->s_data.emplace(VM::tp_int, res.quot); - vm->s_data.push(self.a->data[self.i++]); - return 3; - }); - } -}; - -void add_module_array2d(VM* vm) { - PyObject* mod = vm->new_module("array2d"); - - vm->register_user_class(mod, "array2d", VM::tp_object, true); - vm->register_user_class(mod, "_array2d_iter"); - - Type array2d_iter_t = vm->_tp_user(); - vm->bind__iter__(array2d_iter_t, [](VM* vm, PyVar _0) { - return vm->new_user_object(_0, &_0.obj_get()); - }); -} - -} // namespace pkpy diff --git a/src/modules/base64.cpp b/src/modules/base64.cpp deleted file mode 100644 index 0be841c8..00000000 --- a/src/modules/base64.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "pocketpy/modules/base64.hpp" -#include "pocketpy/interpreter/bindings.hpp" - -namespace pkpy { - -// https://github.com/zhicheng/base64/blob/master/base64.c - -const char BASE64_PAD = '='; -const char BASE64DE_FIRST = '+'; -const char BASE64DE_LAST = 'z'; - -// clang-format off -/* BASE 64 encode table */ -const char base64en[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/', -}; - -/* ASCII order for BASE 64 decode, 255 in unused character */ -const unsigned char base64de[] = { - /* nul, soh, stx, etx, eot, enq, ack, bel, */ - 255, 255, 255, 255, 255, 255, 255, 255, - - /* bs, ht, nl, vt, np, cr, so, si, */ - 255, 255, 255, 255, 255, 255, 255, 255, - - /* dle, dc1, dc2, dc3, dc4, nak, syn, etb, */ - 255, 255, 255, 255, 255, 255, 255, 255, - - /* can, em, sub, esc, fs, gs, rs, us, */ - 255, 255, 255, 255, 255, 255, 255, 255, - - /* sp, '!', '"', '#', '$', '%', '&', ''', */ - 255, 255, 255, 255, 255, 255, 255, 255, - - /* '(', ')', '*', '+', ',', '-', '.', '/', */ - 255, 255, 255, 62, 255, 255, 255, 63, - - /* '0', '1', '2', '3', '4', '5', '6', '7', */ - 52, 53, 54, 55, 56, 57, 58, 59, - - /* '8', '9', ':', ';', '<', '=', '>', '?', */ - 60, 61, 255, 255, 255, 255, 255, 255, - - /* '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', */ - 255, 0, 1, 2, 3, 4, 5, 6, - - /* 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', */ - 7, 8, 9, 10, 11, 12, 13, 14, - - /* 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', */ - 15, 16, 17, 18, 19, 20, 21, 22, - - /* 'X', 'Y', 'Z', '[', '\', ']', '^', '_', */ - 23, 24, 25, 255, 255, 255, 255, 255, - - /* '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', */ - 255, 26, 27, 28, 29, 30, 31, 32, - - /* 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', */ - 33, 34, 35, 36, 37, 38, 39, 40, - - /* 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', */ - 41, 42, 43, 44, 45, 46, 47, 48, - - /* 'x', 'y', 'z', '{', '|', '}', '~', del, */ - 49, 50, 51, 255, 255, 255, 255, 255 -}; -// clang-format on - -static unsigned int base64_encode(const unsigned char* in, unsigned int inlen, char* out) { - int s; - unsigned int i; - unsigned int j; - unsigned char c; - unsigned char l; - - s = 0; - l = 0; - for(i = j = 0; i < inlen; i++) { - c = in[i]; - - switch(s) { - case 0: - s = 1; - out[j++] = base64en[(c >> 2) & 0x3F]; - break; - case 1: - s = 2; - out[j++] = base64en[((l & 0x3) << 4) | ((c >> 4) & 0xF)]; - break; - case 2: - s = 0; - out[j++] = base64en[((l & 0xF) << 2) | ((c >> 6) & 0x3)]; - out[j++] = base64en[c & 0x3F]; - break; - } - l = c; - } - - switch(s) { - case 1: - out[j++] = base64en[(l & 0x3) << 4]; - out[j++] = BASE64_PAD; - out[j++] = BASE64_PAD; - break; - case 2: - out[j++] = base64en[(l & 0xF) << 2]; - out[j++] = BASE64_PAD; - break; - } - - out[j] = 0; - - return j; -} - -static unsigned int base64_decode(const char* in, unsigned int inlen, unsigned char* out) { - unsigned int i; - unsigned int j; - unsigned char c; - - if(inlen & 0x3) { return 0; } - - for(i = j = 0; i < inlen; i++) { - if(in[i] == BASE64_PAD) { break; } - if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { return 0; } - - c = base64de[(unsigned char)in[i]]; - if(c == 255) { return 0; } - - switch(i & 0x3) { - case 0: out[j] = (c << 2) & 0xFF; break; - case 1: - out[j++] |= (c >> 4) & 0x3; - out[j] = (c & 0xF) << 4; - break; - case 2: - out[j++] |= (c >> 2) & 0xF; - out[j] = (c & 0x3) << 6; - break; - case 3: out[j++] |= c; break; - } - } - - return j; -} - -void add_module_base64(VM* vm) { - PyObject* mod = vm->new_module("base64"); - - // b64encode - vm->bind_func(mod, "b64encode", 1, [](VM* vm, ArgsView args) { - Bytes& b = CAST(Bytes&, args[0]); - unsigned char* p = (unsigned char*)std::malloc(b.size() * 2); - int size = base64_encode((const unsigned char*)b.data(), b.size(), (char*)p); - return VAR(Bytes(p, size)); - }); - - // b64decode - vm->bind_func(mod, "b64decode", 1, [](VM* vm, ArgsView args) { - Bytes& b = CAST(Bytes&, args[0]); - unsigned char* p = (unsigned char*)std::malloc(b.size()); - int size = base64_decode((const char*)b.data(), b.size(), p); - return VAR(Bytes(p, size)); - }); -} - -} // namespace pkpy diff --git a/src/modules/csv.cpp b/src/modules/csv.cpp deleted file mode 100644 index ebcc9a91..00000000 --- a/src/modules/csv.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "pocketpy/modules/csv.hpp" -#include "pocketpy/interpreter/bindings.hpp" - -namespace pkpy { - -void add_module_csv(VM* vm) { - 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]); - List ret; - for(int i = 0; i < csvfile.size(); i++) { - std::string_view line = CAST(Str&, csvfile[i]).sv(); - if(i == 0) { - // Skip utf8 BOM if there is any. - if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3); - } - List row; - int j; - bool in_quote = false; - std::string buffer; - __NEXT_LINE: - j = 0; - while(j < line.size()) { - switch(line[j]) { - case '"': - if(in_quote) { - if(j + 1 < line.size() && line[j + 1] == '"') { - buffer += '"'; - j++; - } else { - in_quote = false; - } - } else { - in_quote = true; - } - break; - case ',': - if(in_quote) { - buffer += line[j]; - } else { - row.push_back(VAR(buffer)); - buffer.clear(); - } - break; - case '\r': break; // ignore - default: buffer += line[j]; break; - } - j++; - } - if(in_quote) { - if(i == csvfile.size() - 1) { - vm->ValueError("unterminated quote"); - } else { - buffer += '\n'; - i++; - line = CAST(Str&, csvfile[i]).sv(); - goto __NEXT_LINE; - } - } - row.push_back(VAR(buffer)); - ret.push_back(VAR(std::move(row))); - } - return VAR(std::move(ret)); - }); - - vm->bind(mod, "DictReader(csvfile: list[str]) -> list[dict]", [](VM* vm, ArgsView args) { - PyVar csv_reader = vm->_modules["csv"]->attr()["reader"]; - PyVar ret_obj = vm->call(csv_reader, args[0]); - const List& ret = CAST(List&, ret_obj); - if(ret.size() == 0) { vm->ValueError("empty csvfile"); } - const List& header = CAST(List&, ret[0]); - List new_ret; - for(int i = 1; i < ret.size(); i++) { - const List& row = CAST(List&, ret[i]); - if(row.size() != header.size()) { vm->ValueError("row.size() != header.size()"); } - Dict row_dict; - for(int j = 0; j < header.size(); j++) { - row_dict.set(vm, header[j], row[j]); - } - new_ret.push_back(VAR(std::move(row_dict))); - } - return VAR(std::move(new_ret)); - }); -} - -} // namespace pkpy diff --git a/src/modules/dataclasses.cpp b/src/modules/dataclasses.cpp deleted file mode 100644 index 3d46bd10..00000000 --- a/src/modules/dataclasses.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "pocketpy/modules/dataclasses.hpp" -#include "pocketpy/interpreter/bindings.hpp" - -namespace pkpy { - -static void patch__init__(VM* vm, Type cls) { - vm->bind(vm->_t(cls), "__init__(self, *args, **kwargs)", [](VM* vm, ArgsView _view) { - PyVar self = _view[0]; - const Tuple& args = CAST(Tuple&, _view[1]); - const Dict& kwargs_ = CAST(Dict&, _view[2]); - NameDict kwargs; - kwargs_.apply([&](PyVar k, PyVar v) { - kwargs.set(CAST(Str&, k), v); - }); - - Type cls = vm->_tp(self); - const PyTypeInfo* cls_info = &vm->_all_types[cls]; - NameDict& cls_d = cls_info->obj->attr(); - const auto& fields = cls_info->annotated_fields; - - int i = 0; // index into args - for(StrName field: fields) { - if(kwargs.contains(field)) { - self->attr().set(field, kwargs[field]); - kwargs.del(field); - } else { - if(i < args.size()) { - self->attr().set(field, args[i]); - ++i; - } else if(cls_d.contains(field)) { // has default value - self->attr().set(field, cls_d[field]); - } else { - vm->TypeError(_S(cls_info->name, " missing required argument ", field.escape())); - } - } - } - if(args.size() > i) { - vm->TypeError( - _S(cls_info->name, " takes ", fields.size(), " positional arguments but ", args.size(), " were given")); - } - if(kwargs.size() > 0) { - StrName unexpected_key = kwargs.items()[0].first; - vm->TypeError(_S(cls_info->name, " got an unexpected keyword argument ", unexpected_key.escape())); - } - return vm->None; - }); -} - -static void patch__repr__(VM* vm, Type cls) { - vm->bind__repr__(cls, [](VM* vm, PyVar _0) -> Str { - const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)]; - const auto& fields = cls_info->annotated_fields; - const NameDict& obj_d = _0->attr(); - SStream ss; - ss << cls_info->name << "("; - bool first = true; - for(StrName field: fields) { - if(first) - first = false; - else - ss << ", "; - ss << field << "=" << vm->py_repr(obj_d[field]); - } - ss << ")"; - return ss.str(); - }); -} - -static void patch__eq__(VM* vm, Type cls) { - vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) { - if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented; - const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)]; - const auto& fields = cls_info->annotated_fields; - for(StrName field: fields) { - PyVar lhs = _0->attr()[field]; - PyVar rhs = _1->attr()[field]; - if(vm->py_ne(lhs, rhs)) return vm->False; - } - return vm->True; - }); -} - -void add_module_dataclasses(VM* vm) { - PyObject* mod = vm->new_module("dataclasses"); - - vm->bind_func(mod, "dataclass", 1, [](VM* vm, ArgsView args) { - vm->check_type(args[0], VM::tp_type); - Type cls = PK_OBJ_GET(Type, args[0]); - NameDict& cls_d = args[0]->attr(); - - if(!cls_d.contains(__init__)) patch__init__(vm, cls); - if(!cls_d.contains(__repr__)) patch__repr__(vm, cls); - if(!cls_d.contains(__eq__)) patch__eq__(vm, cls); - - const auto& fields = vm->_all_types[cls].annotated_fields; - bool has_default = false; - for(StrName field: fields) { - if(cls_d.contains(field)) { - has_default = true; - } else { - if(has_default) { - vm->TypeError(_S("non-default argument ", field.escape(), " follows default argument")); - } - } - } - return args[0]; - }); - - vm->bind_func(mod, "asdict", 1, [](VM* vm, ArgsView args) { - const auto& fields = vm->_tp_info(args[0])->annotated_fields; - const NameDict& obj_d = args[0]->attr(); - Dict d; - for(StrName field: fields) { - d.set(vm, VAR(field.sv()), obj_d[field]); - } - return VAR(std::move(d)); - }); -} - -} // namespace pkpy diff --git a/src/modules/easing.cpp b/src/modules/easing.cpp deleted file mode 100644 index ebd8e12d..00000000 --- a/src/modules/easing.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "pocketpy/modules/easing.hpp" -#include "pocketpy/interpreter/bindings.hpp" - -#include - -namespace pkpy { -// https://easings.net/ - -const double kPi = 3.1415926545; - -static double easeLinear(double x) { return x; } - -static double easeInSine(double x) { return 1.0 - std::cos(x * kPi / 2); } - -static double easeOutSine(double x) { return std::sin(x * kPi / 2); } - -static double easeInOutSine(double x) { return -(std::cos(kPi * x) - 1) / 2; } - -static double easeInQuad(double x) { return x * x; } - -static double easeOutQuad(double x) { return 1 - std::pow(1 - x, 2); } - -static double easeInOutQuad(double x) { - if(x < 0.5) { - return 2 * x * x; - } else { - return 1 - std::pow(-2 * x + 2, 2) / 2; - } -} - -static double easeInCubic(double x) { return x * x * x; } - -static double easeOutCubic(double x) { return 1 - std::pow(1 - x, 3); } - -static double easeInOutCubic(double x) { - if(x < 0.5) { - return 4 * x * x * x; - } else { - return 1 - std::pow(-2 * x + 2, 3) / 2; - } -} - -static double easeInQuart(double x) { return std::pow(x, 4); } - -static double easeOutQuart(double x) { return 1 - std::pow(1 - x, 4); } - -static double easeInOutQuart(double x) { - if(x < 0.5) { - return 8 * std::pow(x, 4); - } else { - return 1 - std::pow(-2 * x + 2, 4) / 2; - } -} - -static double easeInQuint(double x) { return std::pow(x, 5); } - -static double easeOutQuint(double x) { return 1 - std::pow(1 - x, 5); } - -static double easeInOutQuint(double x) { - if(x < 0.5) { - return 16 * std::pow(x, 5); - } else { - return 1 - std::pow(-2 * x + 2, 5) / 2; - } -} - -static double easeInExpo(double x) { return x == 0 ? 0 : std::pow(2, 10 * x - 10); } - -static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - std::pow(2, -10 * x); } - -static double easeInOutExpo(double x) { - if(x == 0) { - return 0; - } else if(x == 1) { - return 1; - } else if(x < 0.5) { - return std::pow(2, 20 * x - 10) / 2; - } else { - return (2 - std::pow(2, -20 * x + 10)) / 2; - } -} - -static double easeInCirc(double x) { return 1 - std::sqrt(1 - std::pow(x, 2)); } - -static double easeOutCirc(double x) { return std::sqrt(1 - std::pow(x - 1, 2)); } - -static double easeInOutCirc(double x) { - if(x < 0.5) { - return (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2; - } else { - return (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2; - } -} - -static double easeInBack(double x) { - const double c1 = 1.70158; - const double c3 = c1 + 1; - return c3 * x * x * x - c1 * x * x; -} - -static double easeOutBack(double x) { - const double c1 = 1.70158; - const double c3 = c1 + 1; - return 1 + c3 * std::pow(x - 1, 3) + c1 * std::pow(x - 1, 2); -} - -static double easeInOutBack(double x) { - const double c1 = 1.70158; - const double c2 = c1 * 1.525; - if(x < 0.5) { - return (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2; - } else { - return (std::pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2; - } -} - -static double easeInElastic(double x) { - const double c4 = (2 * kPi) / 3; - if(x == 0) { - return 0; - } else if(x == 1) { - return 1; - } else { - return -std::pow(2, 10 * x - 10) * std::sin((x * 10 - 10.75) * c4); - } -} - -static double easeOutElastic(double x) { - const double c4 = (2 * kPi) / 3; - if(x == 0) { - return 0; - } else if(x == 1) { - return 1; - } else { - return std::pow(2, -10 * x) * std::sin((x * 10 - 0.75) * c4) + 1; - } -} - -static double easeInOutElastic(double x) { - const double c5 = (2 * kPi) / 4.5; - if(x == 0) { - return 0; - } else if(x == 1) { - return 1; - } else if(x < 0.5) { - return -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2; - } else { - return (std::pow(2, -20 * x + 10) * std::sin((20 * x - 11.125) * c5)) / 2 + 1; - } -} - -static double easeOutBounce(double x) { - const double n1 = 7.5625; - const double d1 = 2.75; - if(x < 1 / d1) { - return n1 * x * x; - } else if(x < 2 / d1) { - x -= 1.5 / d1; - return n1 * x * x + 0.75; - } else if(x < 2.5 / d1) { - x -= 2.25 / d1; - return n1 * x * x + 0.9375; - } else { - x -= 2.625 / d1; - return n1 * x * x + 0.984375; - } -} - -static double easeInBounce(double x) { return 1 - easeOutBounce(1 - x); } - -static double easeInOutBounce(double x) { - return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2; -} - -void add_module_easing(VM* vm) { - PyObject* mod = vm->new_module("easing"); - -#define EASE(name) \ - vm->bind_func(mod, #name, 1, [](VM* vm, ArgsView args) { \ - f64 t = CAST(f64, args[0]); \ - return VAR(ease##name(t)); \ - }); - - EASE(Linear) - EASE(InSine) - EASE(OutSine) - EASE(InOutSine) - EASE(InQuad) - EASE(OutQuad) - EASE(InOutQuad) - EASE(InCubic) - EASE(OutCubic) - EASE(InOutCubic) - EASE(InQuart) - EASE(OutQuart) - EASE(InOutQuart) - EASE(InQuint) - EASE(OutQuint) - EASE(InOutQuint) - EASE(InExpo) - EASE(OutExpo) - EASE(InOutExpo) - EASE(InCirc) - EASE(OutCirc) - EASE(InOutCirc) - EASE(InBack) - EASE(OutBack) - EASE(InOutBack) - EASE(InElastic) - EASE(OutElastic) - EASE(InOutElastic) - EASE(InBounce) - EASE(OutBounce) - EASE(InOutBounce) - -#undef EASE -} -} // namespace pkpy diff --git a/src/modules/io.cpp b/src/modules/io.cpp deleted file mode 100644 index d047bf4b..00000000 --- a/src/modules/io.cpp +++ /dev/null @@ -1,247 +0,0 @@ -#include "pocketpy/modules/io.hpp" -#include "pocketpy/interpreter/bindings.hpp" - -#if PK_ENABLE_OS -#include -#include -#endif - -namespace pkpy { - -#if PK_ENABLE_OS - -struct FileIO { - FILE* fp; - bool is_text; - - FileIO(VM* vm, const Str& file, const Str& mode); - void close(); - static void _register(VM* vm, PyObject* mod, PyObject* type); -}; - -static FILE* io_fopen(const char* name, const char* mode) { -#if _MSC_VER - FILE* fp; - errno_t err = fopen_s(&fp, name, mode); - if(err != 0) return nullptr; - return fp; -#else - return fopen(name, mode); -#endif -} - -static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp) { -#if _MSC_VER - return fread_s(buffer, std::numeric_limits::max(), size, count, fp); -#else - return fread(buffer, size, count, fp); -#endif -} - -unsigned char* _default_import_handler(const char* name, int* out_size) { - bool exists = std::filesystem::exists(std::filesystem::path(name)); - if(!exists) return nullptr; - FILE* fp = io_fopen(name, "rb"); - if(!fp) return nullptr; - fseek(fp, 0, SEEK_END); - int buffer_size = ftell(fp); - unsigned char* buffer = new unsigned char[buffer_size]; - fseek(fp, 0, SEEK_SET); - size_t sz = io_fread(buffer, 1, buffer_size, fp); - (void)sz; // suppress warning - fclose(fp); - *out_size = buffer_size; - return buffer; -}; - -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, py_cast(vm, args[1]), py_cast(vm, args[2])); - }); - - vm->bind(type, "read(self, size=-1)", [](VM* vm, ArgsView args) { - FileIO& io = PK_OBJ_GET(FileIO, args[0]); - i64 size = CAST(i64, args[1]); - i64 buffer_size; - if(size < 0) { - long current = ftell(io.fp); - fseek(io.fp, 0, SEEK_END); - buffer_size = ftell(io.fp); - fseek(io.fp, current, SEEK_SET); - } else { - buffer_size = size; - } - unsigned char* buffer = (unsigned char*)std::malloc(buffer_size); - i64 actual_size = io_fread(buffer, 1, buffer_size, io.fp); - assert(actual_size <= buffer_size); - // in text mode, CR may be dropped, which may cause `actual_size < buffer_size` - Bytes b(buffer, actual_size); - if(io.is_text) { return VAR(std::string_view((char*)b.data(), b.size())); } - return VAR(std::move(b)); - }); - - vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args) { - FileIO& io = PK_OBJ_GET(FileIO, args[0]); - if(io.is_text) { - Str& s = CAST(Str&, args[1]); - fwrite(s.c_str(), 1, s.length(), io.fp); - } else { - Bytes& buffer = CAST(Bytes&, args[1]); - fwrite(buffer.data(), 1, buffer.size(), io.fp); - } - return vm->None; - }); - - vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) { - FileIO& io = PK_OBJ_GET(FileIO, args[0]); - long pos = ftell(io.fp); - if(pos == -1) vm->IOError(strerror(errno)); - return VAR(pos); - }); - - vm->bind_func(type, "seek", 3, [](VM* vm, ArgsView args) { - FileIO& io = PK_OBJ_GET(FileIO, args[0]); - long offset = CAST(long, args[1]); - int whence = CAST(int, args[2]); - int ret = fseek(io.fp, offset, whence); - if(ret != 0) vm->IOError(strerror(errno)); - return vm->None; - }); - - vm->bind_func(type, "close", 1, [](VM* vm, ArgsView args) { - FileIO& io = PK_OBJ_GET(FileIO, args[0]); - io.close(); - return vm->None; - }); - - vm->bind_func(type, __exit__, 1, [](VM* vm, ArgsView args) { - FileIO& io = PK_OBJ_GET(FileIO, args[0]); - io.close(); - return vm->None; - }); - - vm->bind_func(type, __enter__, 1, PK_LAMBDA(args[0])); -} - -FileIO::FileIO(VM* vm, const Str& file, const Str& mode) { - this->is_text = mode.sv().find("b") == std::string::npos; - fp = io_fopen(file.c_str(), mode.c_str()); - if(!fp) vm->IOError(strerror(errno)); -} - -void FileIO::close() { - if(fp == nullptr) return; - fclose(fp); - fp = nullptr; -} - -void add_module_io(VM* vm) { - PyObject* mod = vm->new_module("io"); - vm->register_user_class(mod, "FileIO"); - - mod->attr().set("SEEK_SET", VAR(SEEK_SET)); - mod->attr().set("SEEK_CUR", VAR(SEEK_CUR)); - mod->attr().set("SEEK_END", VAR(SEEK_END)); - - vm->bind(vm->builtins, "open(path, mode='r')", [](VM* vm, ArgsView args) { - return vm->call(vm->_modules["io"]->attr("FileIO"), args[0], args[1]); - }); -} - -void add_module_os(VM* vm) { - PyObject* mod = vm->new_module("os"); - PyObject* path_obj = vm->new_object(VM::tp_object).get(); - mod->attr().set("path", path_obj); - - // Working directory is shared by all VMs!! - vm->bind_func(mod, "getcwd", 0, [](VM* vm, ArgsView args) { - return VAR(std::filesystem::current_path().string()); - }); - - vm->bind_func(mod, "chdir", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - std::filesystem::current_path(path); - return vm->None; - }); - - vm->bind_func(mod, "listdir", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - std::filesystem::directory_iterator di; - try { - di = std::filesystem::directory_iterator(path); - } catch(std::filesystem::filesystem_error&) { vm->IOError(path.string()); } - List ret; - for(auto& p: di) - ret.push_back(VAR(p.path().filename().string())); - return VAR(std::move(ret)); - }); - - vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - bool ok = std::filesystem::remove(path); - if(!ok) vm->IOError("operation failed"); - return vm->None; - }); - - vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - bool ok = std::filesystem::create_directory(path); - if(!ok) vm->IOError("operation failed"); - return vm->None; - }); - - vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - bool ok = std::filesystem::remove(path); - if(!ok) vm->IOError("operation failed"); - return vm->None; - }); - - vm->bind_func(path_obj, "join", -1, [](VM* vm, ArgsView args) { - std::filesystem::path path; - for(int i = 0; i < args.size(); i++) { - path /= CAST(Str&, args[i]).sv(); - } - return VAR(path.string()); - }); - - vm->bind_func(path_obj, "exists", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - bool exists = std::filesystem::exists(path); - return VAR(exists); - }); - - vm->bind_func(path_obj, "basename", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - return VAR(path.filename().string()); - }); - - vm->bind_func(path_obj, "isdir", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - bool isdir = std::filesystem::is_directory(path); - return VAR(isdir); - }); - - vm->bind_func(path_obj, "isfile", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - bool isfile = std::filesystem::is_regular_file(path); - return VAR(isfile); - }); - - vm->bind_func(path_obj, "abspath", 1, [](VM* vm, ArgsView args) { - std::filesystem::path path(CAST(Str&, args[0]).sv()); - return VAR(std::filesystem::absolute(path).string()); - }); -} -#else - -void add_module_io(VM* vm) {} - -void add_module_os(VM* vm) {} - -unsigned char* _default_import_handler(const char* name, int* out_size) { return nullptr; } - -#endif - -} // namespace pkpy diff --git a/src/modules/linalg.cpp b/src/modules/linalg.cpp deleted file mode 100644 index 531c1894..00000000 --- a/src/modules/linalg.cpp +++ /dev/null @@ -1,717 +0,0 @@ -#include "pocketpy/modules/linalg.hpp" -#include "pocketpy/interpreter/bindings.hpp" - -namespace pkpy { - -#define BIND_VEC_VEC_OP(D, name, op) \ - 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(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); \ - }); - -#define BIND_VEC_FUNCTION_0(T, name) \ - vm->bind_func(type, #name, 1, [](VM* vm, ArgsView args) { \ - T self = _CAST(T, args[0]); \ - return VAR(self.name()); \ - }); - -#define BIND_VEC_FUNCTION_1(T, name) \ - vm->bind_func(type, #name, 2, [](VM* vm, ArgsView args) { \ - T self = _CAST(T, args[0]); \ - T other = CAST(T, args[1]); \ - return VAR(self.name(other)); \ - }); - -#define BIND_VEC_MUL_OP(D) \ - 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); \ - return VAR(self * other); \ - } \ - f64 other = CAST(f64, _1); \ - return VAR(self * other); \ - }); \ - vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args) { \ - Vec##D self = _CAST(Vec##D, args[0]); \ - f64 other = CAST(f64, args[1]); \ - return VAR(self * other); \ - }); \ - 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__(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"); \ - return VAR(self[i]); \ - }); - -#define BIND_SSO_VEC_COMMON(D) \ - 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); \ - return VAR(self == other); \ - }); \ - vm->bind_func(type, "__getnewargs__", 1, [](VM* vm, ArgsView args) { \ - Vec##D self = _CAST(Vec##D, args[0]); \ - Tuple t(D); \ - for(int i = 0; i < D; i++) \ - t[i] = VAR(self[i]); \ - return VAR(std::move(t)); \ - }); - -// https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector2.cs#L289 -static Vec2 - SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime) { - // Based on Game Programming Gems 4 Chapter 1.10 - smoothTime = (std::max)(0.0001F, smoothTime); - float omega = 2.0F / smoothTime; - - float x = omega * deltaTime; - float exp = 1.0F / (1.0F + x + 0.48F * x * x + 0.235F * x * x * x); - - float change_x = current.x - target.x; - float change_y = current.y - target.y; - Vec2 originalTo = target; - - // Clamp maximum speed - float maxChange = maxSpeed * smoothTime; - - float maxChangeSq = maxChange * maxChange; - float sqDist = change_x * change_x + change_y * change_y; - if(sqDist > maxChangeSq) { - float mag = std::sqrt(sqDist); - change_x = change_x / mag * maxChange; - change_y = change_y / mag * maxChange; - } - - target.x = current.x - change_x; - target.y = current.y - change_y; - - float temp_x = (currentVelocity.x + omega * change_x) * deltaTime; - float temp_y = (currentVelocity.y + omega * change_y) * deltaTime; - - currentVelocity.x = (currentVelocity.x - omega * temp_x) * exp; - currentVelocity.y = (currentVelocity.y - omega * temp_y) * exp; - - float output_x = target.x + (change_x + temp_x) * exp; - float output_y = target.y + (change_y + temp_y) * exp; - - // Prevent overshooting - float origMinusCurrent_x = originalTo.x - current.x; - float origMinusCurrent_y = originalTo.y - current.y; - float outMinusOrig_x = output_x - originalTo.x; - float outMinusOrig_y = output_y - originalTo.y; - - if(origMinusCurrent_x * outMinusOrig_x + origMinusCurrent_y * outMinusOrig_y > 0) { - output_x = originalTo.x; - output_y = originalTo.y; - - currentVelocity.x = (output_x - originalTo.x) / deltaTime; - currentVelocity.y = (output_y - originalTo.y) / deltaTime; - } - return Vec2(output_x, output_y); -} - -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)); - - vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args) { - float x = CAST_F(args[1]); - float y = CAST_F(args[2]); - return vm->new_object(PK_OBJ_GET(Type, args[0]), x, y); - }); - - // @staticmethod - vm->bind( - type, - "smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2", - [](VM* vm, ArgsView args) { - Vec2 current = CAST(Vec2, args[0]); - Vec2 target = CAST(Vec2, args[1]); - Vec2 current_velocity_ = CAST(Vec2, args[2]); - float smooth_time = CAST_F(args[3]); - float max_speed = CAST_F(args[4]); - float delta_time = CAST_F(args[5]); - Vec2 ret = SmoothDamp(current, target, current_velocity_, smooth_time, max_speed, delta_time); - return VAR(Tuple(VAR(ret), VAR(current_velocity_))); - }, - {}, - BindType_STATICMETHOD); - - // @staticmethod - vm->bind( - type, - "angle(__from: vec2, __to: vec2) -> float", - [](VM* vm, ArgsView args) { - Vec2 __from = CAST(Vec2, args[0]); - Vec2 __to = CAST(Vec2, args[1]); - float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x); - const float PI = 3.1415926535897932384f; - if(val > PI) val -= 2 * PI; - if(val < -PI) val += 2 * PI; - return VAR(val); - }, - {}, - BindType_STATICMETHOD); - - vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str { - Vec2 self = _CAST(Vec2, obj); - SStream ss; - ss.setprecision(3); - ss << "vec2(" << self.x << ", " << self.y << ")"; - return ss.str(); - }); - - vm->bind_func(type, "rotate", 2, [](VM* vm, ArgsView args) { - Vec2 self = _CAST(Vec2, args[0]); - float radian = CAST(f64, args[1]); - return vm->new_user_object(self.rotate(radian)); - }); - - PY_READONLY_FIELD(Vec2, "x", x) - PY_READONLY_FIELD(Vec2, "y", y) - - BIND_VEC_VEC_OP(2, __add__, +) - BIND_VEC_VEC_OP(2, __sub__, -) - BIND_VEC_MUL_OP(2) - BIND_VEC_FLOAT_OP(2, __truediv__, /) - BIND_VEC_FUNCTION_1(Vec2, dot) - BIND_VEC_FUNCTION_1(Vec2, cross) - BIND_VEC_FUNCTION_0(Vec2, length) - BIND_VEC_FUNCTION_0(Vec2, length_squared) - BIND_VEC_FUNCTION_0(Vec2, normalize) - BIND_VEC_GETITEM(2) - BIND_SSO_VEC_COMMON(2) -} - -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)); - - vm->bind_func(type, __new__, 4, [](VM* vm, ArgsView args) { - float x = CAST_F(args[1]); - float y = CAST_F(args[2]); - float z = CAST_F(args[3]); - return vm->new_object(PK_OBJ_GET(Type, args[0]), x, y, z); - }); - - vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str { - Vec3 self = _CAST(Vec3, obj); - SStream ss; - ss.setprecision(3); - ss << "vec3(" << self.x << ", " << self.y << ", " << self.z << ")"; - return ss.str(); - }); - - PY_READONLY_FIELD(Vec3, "x", x) - PY_READONLY_FIELD(Vec3, "y", y) - PY_READONLY_FIELD(Vec3, "z", z) - - BIND_VEC_VEC_OP(3, __add__, +) - BIND_VEC_VEC_OP(3, __sub__, -) - BIND_VEC_MUL_OP(3) - BIND_VEC_FUNCTION_1(Vec3, dot) - BIND_VEC_FUNCTION_1(Vec3, cross) - BIND_VEC_FUNCTION_0(Vec3, length) - BIND_VEC_FUNCTION_0(Vec3, length_squared) - BIND_VEC_FUNCTION_0(Vec3, normalize) - BIND_VEC_GETITEM(3) - BIND_SSO_VEC_COMMON(3) -} - -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)); - type->attr().set("ONE", vm->new_user_object(1, 1, 1, 1)); - - vm->bind_func(type, __new__, 5, [](VM* vm, ArgsView args) { - float x = CAST_F(args[1]); - float y = CAST_F(args[2]); - float z = CAST_F(args[3]); - float w = CAST_F(args[4]); - return vm->new_object(PK_OBJ_GET(Type, args[0]), x, y, z, w); - }); - - vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str { - Vec4 self = _CAST(Vec4&, obj); - SStream ss; - ss.setprecision(3); - ss << "vec4(" << self.x << ", " << self.y << ", " << self.z << ", " << self.w << ")"; - return ss.str(); - }); - - PY_FIELD(Vec4, "x", x) - PY_FIELD(Vec4, "y", y) - PY_FIELD(Vec4, "z", z) - PY_FIELD(Vec4, "w", w) - - BIND_VEC_VEC_OP(4, __add__, +) - BIND_VEC_VEC_OP(4, __sub__, -) - BIND_VEC_MUL_OP(4) - BIND_VEC_FUNCTION_1(Vec4&, dot) - BIND_VEC_FUNCTION_1(Vec4&, copy_) - BIND_VEC_FUNCTION_0(Vec4&, length) - BIND_VEC_FUNCTION_0(Vec4&, length_squared) - BIND_VEC_FUNCTION_0(Vec4&, normalize) - BIND_VEC_FUNCTION_0(Vec4&, normalize_) - BIND_VEC_GETITEM(4) -} - -#undef BIND_VEC_VEC_OP -#undef BIND_VEC_MUL_OP -#undef BIND_VEC_FUNCTION_0 -#undef BIND_VEC_FUNCTION_1 -#undef BIND_VEC_GETITEM - -void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) { - PY_STRUCT_LIKE(Mat3x3) - - vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) { - if(args.size() == 1 + 0) return vm->new_object(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros()); - if(args.size() == 1 + 1) { - const List& list = CAST(List&, args[1]); - if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats"); - Mat3x3 mat; - for(int i = 0; i < 9; i++) - mat.v[i] = CAST_F(list[i]); - return vm->new_object(PK_OBJ_GET(Type, args[0]), mat); - } - if(args.size() == 1 + 9) { - Mat3x3 mat; - for(int i = 0; i < 9; i++) - mat.v[i] = CAST_F(args[1 + i]); - return vm->new_object(PK_OBJ_GET(Type, args[0]), mat); - } - vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size() - 1)); - return vm->None; - }); - - vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - const Mat3x3& other = CAST(Mat3x3&, args[1]); - self = other; - return vm->None; - }); - - vm->bind__repr__(type->as(), [](VM* vm, PyVar obj) -> Str { - const Mat3x3& self = _CAST(Mat3x3&, obj); - SStream ss; - ss.setprecision(3); - ss << "mat3x3([" << self._11 << ", " << self._12 << ", " << self._13 << ",\n"; - ss << " " << self._21 << ", " << self._22 << ", " << self._23 << ",\n"; - ss << " " << self._31 << ", " << self._32 << ", " << self._33 << "])"; - return ss.str(); - }); - - 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) { vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers"); } - i64 i = CAST(i64, t[0]); - i64 j = CAST(i64, t[1]); - if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); } - return VAR(self.m[i][j]); - }); - - 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) { vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers"); } - i64 i = CAST(i64, t[0]); - i64 j = CAST(i64, t[1]); - if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); } - self.m[i][j] = CAST_F(value); - }); - - vm->bind_field(type, "_11", &Mat3x3::_11); - vm->bind_field(type, "_12", &Mat3x3::_12); - vm->bind_field(type, "_13", &Mat3x3::_13); - vm->bind_field(type, "_21", &Mat3x3::_21); - vm->bind_field(type, "_22", &Mat3x3::_22); - vm->bind_field(type, "_23", &Mat3x3::_23); - vm->bind_field(type, "_31", &Mat3x3::_31); - vm->bind_field(type, "_32", &Mat3x3::_32); - vm->bind_field(type, "_33", &Mat3x3::_33); - - 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__(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__(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_func(type, "__rmul__", 2, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - f64 other = CAST_F(args[1]); - return vm->new_user_object(self * other); - }); - - 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__(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); - return vm->new_user_object(self.matmul(other)); - } - if(vm->is_user_type(_1)) { - const Vec3 other = _CAST(Vec3, _1); - return vm->new_user_object(self.matmul(other)); - } - return vm->NotImplemented; - }); - - vm->bind(type, "matmul(self, other: mat3x3, out: mat3x3 = None)", [](VM* vm, ArgsView args) { - const Mat3x3& self = _CAST(Mat3x3&, args[0]); - const Mat3x3& other = CAST(Mat3x3&, args[1]); - if(is_none(args[2])) { - return vm->new_user_object(self.matmul(other)); - } else { - Mat3x3& out = CAST(Mat3x3&, args[2]); - out = self.matmul(other); - return vm->None; - } - }); - - vm->bind_func(type, "determinant", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - return VAR(self.determinant()); - }); - - vm->bind_func(type, "transpose", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - return vm->new_user_object(self.transpose()); - }); - - 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"); - return vm->new_user_object(ret); - }); - - vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - Mat3x3 ret; - if(!self.inverse(ret)) vm->ValueError("matrix is not invertible"); - return vm->new_user_object(ret); - }); - - vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - Mat3x3 ret; - if(!self.inverse(ret)) vm->ValueError("matrix is not invertible"); - self = ret; - return vm->None; - }); - - vm->bind_func(type, "transpose_", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - self = self.transpose(); - return vm->None; - }); - - // @staticmethod - vm->bind_func( - type, - "zeros", - 0, - [](VM* vm, ArgsView args) { - return vm->new_user_object(Mat3x3::zeros()); - }, - {}, - BindType_STATICMETHOD); - - // @staticmethod - vm->bind_func( - type, - "ones", - 0, - [](VM* vm, ArgsView args) { - return vm->new_user_object(Mat3x3::ones()); - }, - {}, - BindType_STATICMETHOD); - - // @staticmethod - vm->bind_func( - type, - "identity", - 0, - [](VM* vm, ArgsView args) { - return vm->new_user_object(Mat3x3::identity()); - }, - {}, - BindType_STATICMETHOD); - - /*************** affine transformations ***************/ - // @staticmethod - vm->bind( - type, - "trs(t: vec2, r: float, s: vec2)", - [](VM* vm, ArgsView args) { - Vec2 t = CAST(Vec2, args[0]); - f64 r = CAST_F(args[1]); - Vec2 s = CAST(Vec2, args[2]); - return vm->new_user_object(Mat3x3::trs(t, r, s)); - }, - {}, - BindType_STATICMETHOD); - - vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - Vec2 t = CAST(Vec2, args[1]); - f64 r = CAST_F(args[2]); - Vec2 s = CAST(Vec2, args[3]); - self = Mat3x3::trs(t, r, s); - return vm->None; - }); - - vm->bind(type, "copy_t_(self, t: vec2)", [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - Vec2 t = CAST(Vec2, args[1]); - self = Mat3x3::trs(t, self._r(), self._s()); - return vm->None; - }); - - vm->bind(type, "copy_r_(self, r: float)", [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - f64 r = CAST_F(args[1]); - self = Mat3x3::trs(self._t(), r, self._s()); - return vm->None; - }); - - vm->bind(type, "copy_s_(self, s: vec2)", [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - Vec2 s = CAST(Vec2, args[1]); - self = Mat3x3::trs(self._t(), self._r(), s); - return vm->None; - }); - - vm->bind_func(type, "is_affine", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - return VAR(self.is_affine()); - }); - - vm->bind_func(type, "_t", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - return vm->new_user_object(self._t()); - }); - - vm->bind_func(type, "_r", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - return VAR(self._r()); - }); - - vm->bind_func(type, "_s", 1, [](VM* vm, ArgsView args) { - Mat3x3& self = _CAST(Mat3x3&, args[0]); - return vm->new_user_object(self._s()); - }); - - vm->bind_func(type, "transform_point", 2, [](VM* vm, ArgsView args) { - const Mat3x3& self = _CAST(Mat3x3&, args[0]); - Vec2 v = CAST(Vec2, args[1]); - Vec2 res(self._11 * v.x + self._12 * v.y + self._13, self._21 * v.x + self._22 * v.y + self._23); - return vm->new_user_object(res); - }); - - vm->bind_func(type, "inverse_transform_point", 2, [](VM* vm, ArgsView args) { - const Mat3x3& self = _CAST(Mat3x3&, args[0]); - Vec2 v = CAST(Vec2, args[1]); - Mat3x3 inv; - if(!self.inverse(inv)) vm->ValueError("matrix is not invertible"); - Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23); - return vm->new_user_object(res); - }); - - vm->bind_func(type, "transform_vector", 2, [](VM* vm, ArgsView args) { - const Mat3x3& self = _CAST(Mat3x3&, args[0]); - Vec2 v = CAST(Vec2, args[1]); - Vec2 res(self._11 * v.x + self._12 * v.y, self._21 * v.x + self._22 * v.y); - return vm->new_user_object(res); - }); - - vm->bind_func(type, "inverse_transform_vector", 2, [](VM* vm, ArgsView args) { - const Mat3x3& self = _CAST(Mat3x3&, args[0]); - Vec2 v = CAST(Vec2, args[1]); - Mat3x3 inv; - if(!self.inverse(inv)) vm->ValueError("matrix is not invertible"); - Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y); - return vm->new_user_object(res); - }); -} - -void add_module_linalg(VM* vm) { - PyObject* linalg = vm->new_module("linalg"); - - vm->register_user_class(linalg, "vec2", VM::tp_object); - vm->register_user_class(linalg, "vec3", VM::tp_object); - vm->register_user_class(linalg, "vec4", VM::tp_object, true); - vm->register_user_class(linalg, "mat3x3", VM::tp_object, true); - - PyVar float_p = vm->_modules["c"]->attr("float_p"); - linalg->attr().set("vec4_p", float_p); - linalg->attr().set("mat3x3_p", float_p); -} - -/////////////// mat3x3 /////////////// -Mat3x3::Mat3x3() {} - -Mat3x3::Mat3x3(float _11, float _12, float _13, float _21, float _22, float _23, float _31, float _32, float _33) : - _11(_11), _12(_12), _13(_13), _21(_21), _22(_22), _23(_23), _31(_31), _32(_32), _33(_33) {} - -Mat3x3 Mat3x3::zeros() { return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0); } - -Mat3x3 Mat3x3::ones() { return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1); } - -Mat3x3 Mat3x3::identity() { return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); } - -Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const { - Mat3x3 ret; - for(int i = 0; i < 9; ++i) - ret.v[i] = v[i] + other.v[i]; - return ret; -} - -Mat3x3 Mat3x3::operator- (const Mat3x3& other) const { - Mat3x3 ret; - for(int i = 0; i < 9; ++i) - ret.v[i] = v[i] - other.v[i]; - return ret; -} - -Mat3x3 Mat3x3::operator* (float scalar) const { - Mat3x3 ret; - for(int i = 0; i < 9; ++i) - ret.v[i] = v[i] * scalar; - return ret; -} - -Mat3x3 Mat3x3::operator/ (float scalar) const { - Mat3x3 ret; - for(int i = 0; i < 9; ++i) - ret.v[i] = v[i] / scalar; - return ret; -} - -bool Mat3x3::operator== (const Mat3x3& other) const { - for(int i = 0; i < 9; ++i) { - if(!isclose(v[i], other.v[i])) return false; - } - return true; -} - -bool Mat3x3::operator!= (const Mat3x3& other) const { - for(int i = 0; i < 9; ++i) { - if(!isclose(v[i], other.v[i])) return true; - } - return false; -} - -Mat3x3 Mat3x3::matmul(const Mat3x3& other) const { - Mat3x3 out; - out._11 = _11 * other._11 + _12 * other._21 + _13 * other._31; - out._12 = _11 * other._12 + _12 * other._22 + _13 * other._32; - out._13 = _11 * other._13 + _12 * other._23 + _13 * other._33; - out._21 = _21 * other._11 + _22 * other._21 + _23 * other._31; - out._22 = _21 * other._12 + _22 * other._22 + _23 * other._32; - out._23 = _21 * other._13 + _22 * other._23 + _23 * other._33; - out._31 = _31 * other._11 + _32 * other._21 + _33 * other._31; - out._32 = _31 * other._12 + _32 * other._22 + _33 * other._32; - out._33 = _31 * other._13 + _32 * other._23 + _33 * other._33; - return out; -} - -Vec3 Mat3x3::matmul(const Vec3& other) const { - Vec3 out; - out.x = _11 * other.x + _12 * other.y + _13 * other.z; - out.y = _21 * other.x + _22 * other.y + _23 * other.z; - out.z = _31 * other.x + _32 * other.y + _33 * other.z; - return out; -} - -float Mat3x3::determinant() const { - return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32 - _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31; -} - -Mat3x3 Mat3x3::transpose() const { - Mat3x3 ret; - ret._11 = _11; - ret._12 = _21; - ret._13 = _31; - ret._21 = _12; - ret._22 = _22; - ret._23 = _32; - ret._31 = _13; - ret._32 = _23; - ret._33 = _33; - return ret; -} - -bool Mat3x3::inverse(Mat3x3& out) const { - float det = determinant(); - if(isclose(det, 0)) return false; - float inv_det = 1.0f / det; - out._11 = (_22 * _33 - _23 * _32) * inv_det; - out._12 = (_13 * _32 - _12 * _33) * inv_det; - out._13 = (_12 * _23 - _13 * _22) * inv_det; - out._21 = (_23 * _31 - _21 * _33) * inv_det; - out._22 = (_11 * _33 - _13 * _31) * inv_det; - out._23 = (_13 * _21 - _11 * _23) * inv_det; - out._31 = (_21 * _32 - _22 * _31) * inv_det; - out._32 = (_12 * _31 - _11 * _32) * inv_det; - out._33 = (_11 * _22 - _12 * _21) * inv_det; - return true; -} - -Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s) { - float cr = cosf(radian); - float sr = sinf(radian); - return Mat3x3(s.x * cr, -s.y * sr, t.x, s.x * sr, s.y * cr, t.y, 0.0f, 0.0f, 1.0f); -} - -bool Mat3x3::is_affine() const { - float det = _11 * _22 - _12 * _21; - if(isclose(det, 0)) return false; - return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f; -} - -Vec2 Mat3x3::_t() const { return Vec2(_13, _23); } - -float Mat3x3::_r() const { return atan2f(_21, _11); } - -Vec2 Mat3x3::_s() const { return Vec2(sqrtf(_11 * _11 + _21 * _21), sqrtf(_12 * _12 + _22 * _22)); } - -} // namespace pkpy diff --git a/src/modules/modules.cpp b/src/modules/modules.cpp deleted file mode 100644 index b5f5d682..00000000 --- a/src/modules/modules.cpp +++ /dev/null @@ -1,355 +0,0 @@ -#include "pocketpy/modules/modules.hpp" -#include "pocketpy/interpreter/bindings.hpp" -#include "pocketpy/common/export.h" - -#include "pocketpy/common/_generated.h" - -#include -#include - -namespace pkpy { - -struct PyStructTime { - int tm_year; - int tm_mon; - int tm_mday; - int tm_hour; - int tm_min; - int tm_sec; - int tm_wday; - int tm_yday; - int tm_isdst; - - PyStructTime(std::time_t t) { - std::tm* tm = std::localtime(&t); - tm_year = tm->tm_year + 1900; - tm_mon = tm->tm_mon + 1; - tm_mday = tm->tm_mday; - tm_hour = tm->tm_hour; - tm_min = tm->tm_min; - tm_sec = tm->tm_sec; - tm_wday = (tm->tm_wday + 6) % 7; - tm_yday = tm->tm_yday + 1; - tm_isdst = tm->tm_isdst; - } - - 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); - PY_READONLY_FIELD(PyStructTime, "tm_hour", tm_hour); - PY_READONLY_FIELD(PyStructTime, "tm_min", tm_min); - PY_READONLY_FIELD(PyStructTime, "tm_sec", tm_sec); - PY_READONLY_FIELD(PyStructTime, "tm_wday", tm_wday); - PY_READONLY_FIELD(PyStructTime, "tm_yday", tm_yday); - PY_READONLY_FIELD(PyStructTime, "tm_isdst", tm_isdst); - } -}; - -void add_module_time(VM* vm) { - PyObject* mod = vm->new_module("time"); - vm->register_user_class(mod, "struct_time"); - - vm->bind_func(mod, "time", 0, [](VM* vm, ArgsView args) { - auto now = std::chrono::system_clock::now(); - return VAR(std::chrono::duration_cast(now.time_since_epoch()).count() / 1000.0); - }); - - vm->bind_func(mod, "sleep", 1, [](VM* vm, ArgsView args) { - f64 seconds = CAST_F(args[0]); - auto begin = std::chrono::system_clock::now(); - while(true) { - auto now = std::chrono::system_clock::now(); - f64 elapsed = std::chrono::duration_cast(now - begin).count() / 1000.0; - if(elapsed >= seconds) break; - } - return vm->None; - }); - - vm->bind_func(mod, "localtime", 0, [](VM* vm, ArgsView args) { - auto now = std::chrono::system_clock::now(); - std::time_t t = std::chrono::system_clock::to_time_t(now); - return vm->new_user_object(t); - }); -} - -void add_module_sys(VM* vm) { - PyObject* mod = vm->new_module("sys"); - vm->setattr(mod, "version", VAR(PK_VERSION)); - vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM])); - - PyObject* stdout_ = vm->new_object(vm->tp_object).get(); - PyObject* stderr_ = vm->new_object(vm->tp_object).get(); - vm->setattr(mod, "stdout", stdout_); - vm->setattr(mod, "stderr", stderr_); - - vm->bind_func(stdout_, "write", 1, [](VM* vm, ArgsView args) { - Str& s = CAST(Str&, args[0]); - vm->stdout_write(s); - return vm->None; - }); - - vm->bind_func(stderr_, "write", 1, [](VM* vm, ArgsView args) { - Str& s = CAST(Str&, args[0]); - vm->stderr_write(s); - return vm->None; - }); -} - -void add_module_json(VM* vm) { - 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)) { - const Bytes& b = PK_OBJ_GET(Bytes, args[0]); - sv = std::string_view((char*)b.data(), b.size()); - } else { - sv = CAST(Str&, args[0]).sv(); - } - CodeObject* code = vm->compile(sv, "", JSON_MODE); - PyVar retval = vm->_exec(code, vm->callstack.top()._module); - CodeObject__delete(code); - return retval; - }); - - vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) { - return VAR(vm->py_json(args[0])); - }); -} - -// https://docs.python.org/3.5/library/math.html -void add_module_math(VM* vm) { - 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())); - mod->attr().set("nan", VAR(std::numeric_limits::quiet_NaN())); - - vm->bind_func(mod, "ceil", 1, PK_LAMBDA(VAR((i64)std::ceil(CAST_F(args[0]))))); - vm->bind_func(mod, "fabs", 1, PK_LAMBDA(VAR(std::fabs(CAST_F(args[0]))))); - vm->bind_func(mod, "floor", 1, PK_LAMBDA(VAR((i64)std::floor(CAST_F(args[0]))))); - vm->bind_func(mod, "fsum", 1, [](VM* vm, ArgsView args) { - List& list = CAST(List&, args[0]); - double sum = 0; - double c = 0; - for(PyVar arg: list) { - double x = CAST_F(arg); - double y = x - c; - double t = sum + y; - c = (t - sum) - y; - sum = t; - } - return VAR(sum); - }); - vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) { - i64 a = CAST(i64, args[0]); - i64 b = CAST(i64, args[1]); - if(a < 0) a = -a; - if(b < 0) b = -b; - while(b != 0) { - i64 t = b; - b = a % b; - a = t; - } - return VAR(a); - }); - - vm->bind_func(mod, "isfinite", 1, PK_LAMBDA(VAR(std::isfinite(CAST_F(args[0]))))); - vm->bind_func(mod, "isinf", 1, PK_LAMBDA(VAR(std::isinf(CAST_F(args[0]))))); - vm->bind_func(mod, "isnan", 1, PK_LAMBDA(VAR(std::isnan(CAST_F(args[0]))))); - - vm->bind_func(mod, "isclose", 2, [](VM* vm, ArgsView args) { - f64 a = CAST_F(args[0]); - f64 b = CAST_F(args[1]); - return VAR(std::fabs(a - b) < 1e-9); - }); - - vm->bind_func(mod, "exp", 1, PK_LAMBDA(VAR(std::exp(CAST_F(args[0]))))); - - vm->bind(mod, "log(x, base=2.718281828459045)", [](VM* vm, ArgsView args) { - f64 x = CAST_F(args[0]); - f64 base = CAST_F(args[1]); - return VAR(std::log(x) / std::log(base)); - }); - - vm->bind_func(mod, "log2", 1, PK_LAMBDA(VAR(std::log2(CAST_F(args[0]))))); - vm->bind_func(mod, "log10", 1, PK_LAMBDA(VAR(std::log10(CAST_F(args[0]))))); - - vm->bind_func(mod, "pow", 2, PK_LAMBDA(VAR(std::pow(CAST_F(args[0]), CAST_F(args[1]))))); - vm->bind_func(mod, "sqrt", 1, PK_LAMBDA(VAR(std::sqrt(CAST_F(args[0]))))); - - vm->bind_func(mod, "acos", 1, PK_LAMBDA(VAR(std::acos(CAST_F(args[0]))))); - vm->bind_func(mod, "asin", 1, PK_LAMBDA(VAR(std::asin(CAST_F(args[0]))))); - vm->bind_func(mod, "atan", 1, PK_LAMBDA(VAR(std::atan(CAST_F(args[0]))))); - vm->bind_func(mod, "atan2", 2, PK_LAMBDA(VAR(std::atan2(CAST_F(args[0]), CAST_F(args[1]))))); - - vm->bind_func(mod, "cos", 1, PK_LAMBDA(VAR(std::cos(CAST_F(args[0]))))); - vm->bind_func(mod, "sin", 1, PK_LAMBDA(VAR(std::sin(CAST_F(args[0]))))); - vm->bind_func(mod, "tan", 1, PK_LAMBDA(VAR(std::tan(CAST_F(args[0]))))); - - vm->bind_func(mod, "degrees", 1, PK_LAMBDA(VAR(CAST_F(args[0]) * 180 / 3.1415926535897932384))); - vm->bind_func(mod, "radians", 1, PK_LAMBDA(VAR(CAST_F(args[0]) * 3.1415926535897932384 / 180))); - - vm->bind_func(mod, "modf", 1, [](VM* vm, ArgsView args) { - f64 i; - f64 f = std::modf(CAST_F(args[0]), &i); - return VAR(Tuple(VAR(f), VAR(i))); - }); - - vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) { - i64 n = CAST(i64, args[0]); - if(n < 0) vm->ValueError("factorial() not defined for negative values"); - i64 r = 1; - for(i64 i = 2; i <= n; i++) - r *= i; - return VAR(r); - }); -} - -void add_module_traceback(VM* vm) { - 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 = vm->__last_exception->as(); - vm->stdout_write(e.summary()); - return vm->None; - }); - - vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) { - if(vm->__last_exception == nullptr) vm->ValueError("no exception"); - Exception& e = vm->__last_exception->as(); - return VAR(e.summary()); - }); -} - -void add_module_dis(VM* vm) { - PyObject* mod = vm->new_module("dis"); - - vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) { - CodeObject* code; - bool need_delete = false; - PyVar obj = args[0]; - if(is_type(obj, vm->tp_str)) { - const Str& source = CAST(Str, obj); - code = vm->compile(source, "", EXEC_MODE); - need_delete = true; - } - PyVar f = obj; - if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func; - code = CAST(Function&, f).decl->code; - vm->stdout_write(vm->disassemble(code)); - if(need_delete) CodeObject__delete(code); - return vm->None; - }); -} - -void add_module_gc(VM* vm) { - PyObject* mod = vm->new_module("gc"); - vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(pk_ManagedHeap__collect(&vm->heap)))); -} - -void add_module_enum(VM* vm) { - PyObject* mod = vm->new_module("enum"); - CodeObject* code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE); - vm->_exec(code, mod); - CodeObject__delete(code); - PyVar Enum = mod->attr("Enum"); - vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) { - new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice - NameDict& attr = new_ti->obj->attr(); - for(auto [k, v]: attr.items()) { - // wrap every attribute - std::string_view k_sv = k.sv(); - if(k_sv.empty() || k_sv[0] == '_') continue; - attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v)); - } - }; -} - -void add_module___builtins(VM* vm) { - PyObject* mod = vm->new_module("__builtins"); - - vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args) { - return vm->py_next(args[0]); - }); - - vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) { - PyVar self = args[0]; - if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict"); - if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled"); - self->_attr = new NameDict(); - return vm->None; - }); -} - -/************************************************/ -#if PK_ENABLE_PROFILER -struct LineProfilerW; - -struct _LpGuard { - PK_ALWAYS_PASS_BY_POINTER(_LpGuard) - LineProfilerW* lp; - VM* vm; - _LpGuard(LineProfilerW* lp, VM* vm); - ~_LpGuard(); -}; - -// line_profiler wrapper -struct LineProfilerW { - LineProfiler profiler; - - 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); - }); - - vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args) { - LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]); - vm->check_type(args[1], VM::tp_function); - auto decl = PK_OBJ_GET(Function, args[1]).decl.get(); - self.profiler.functions.push_back(decl); - return vm->None; - }); - - vm->bind(type, "runcall(self, func, *args)", [](VM* vm, ArgsView view) { - LineProfilerW& self = PK_OBJ_GET(LineProfilerW, view[0]); - PyVar func = view[1]; - const Tuple& args = CAST(Tuple&, view[2]); - vm->s_data.push(func); - vm->s_data.push(PY_NULL); - for(PyVar arg: args) - vm->s_data.push(arg); - _LpGuard guard(&self, vm); - PyVar ret = vm->vectorcall(args.size()); - return ret; - }); - - vm->bind(type, "print_stats(self)", [](VM* vm, ArgsView args) { - LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]); - vm->stdout_write(self.profiler.stats()); - return vm->None; - }); - } -}; - -_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) { - if(vm->_profiler) { vm->ValueError("only one profiler can be enabled at a time"); } - vm->_profiler = &lp->profiler; - lp->profiler.begin(); -} - -_LpGuard::~_LpGuard() { - vm->_profiler = nullptr; - lp->profiler.end(); -} - -void add_module_line_profiler(VM* vm) { - PyObject* mod = vm->new_module("line_profiler"); - vm->register_user_class(mod, "LineProfiler"); -} -#else -void add_module_line_profiler(VM* vm) { (void)vm; } -#endif - -} // namespace pkpy diff --git a/src/modules/random.cpp b/src/modules/random.cpp deleted file mode 100644 index 02ac9bfc..00000000 --- a/src/modules/random.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include "pocketpy/modules/random.hpp" -#include "pocketpy/interpreter/bindings.hpp" - -#include - -/* https://github.com/clibs/mt19937ar - -Copyright (c) 2011 Mutsuo Saito, Makoto Matsumoto, Hiroshima -University and The University of Tokyo. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of the Hiroshima University nor the names of - its contributors may be used to endorse or promote products - derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -struct mt19937 { - const static int N = 624; - const static int M = 397; - const uint32_t MATRIX_A = 0x9908b0dfUL; /* constant vector a */ - const uint32_t UPPER_MASK = 0x80000000UL; /* most significant w-r bits */ - const uint32_t LOWER_MASK = 0x7fffffffUL; /* least significant r bits */ - - uint32_t mt[N]; /* the array for the state vector */ - int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */ - - /* initializes mt[N] with a seed */ - void seed(uint32_t s) { - mt[0] = s & 0xffffffffUL; - for(mti = 1; mti < N; mti++) { - mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti); - /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ - /* In the previous versions, MSBs of the seed affect */ - /* only MSBs of the array mt[]. */ - /* 2002/01/09 modified by Makoto Matsumoto */ - mt[mti] &= 0xffffffffUL; - /* for >32 bit machines */ - } - } - - /* generates a random number on [0,0xffffffff]-interval */ - uint32_t next_uint32(void) { - uint32_t y; - static uint32_t mag01[2] = {0x0UL, MATRIX_A}; - /* mag01[x] = x * MATRIX_A for x=0,1 */ - - if(mti >= N) { /* generate N words at one time */ - int kk; - - if(mti == N + 1) /* if init_genrand() has not been called, */ - seed(5489UL); /* a default initial seed is used */ - - for(kk = 0; kk < N - M; kk++) { - y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); - mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL]; - } - for(; kk < N - 1; kk++) { - y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); - mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; - } - y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); - mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL]; - - mti = 0; - } - - y = mt[mti++]; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - return y; - } - - uint64_t next_uint64(void) { return (uint64_t(next_uint32()) << 32) | next_uint32(); } - - /* generates a random number on [0,1)-real-interval */ - float random(void) { return next_uint32() * (1.0 / 4294967296.0); /* divided by 2^32 */ } - - /* generates a random number on [a, b]-interval */ - int64_t randint(int64_t a, int64_t b) { - uint64_t delta = b - a + 1; - if(delta < 0x80000000UL) { - return a + next_uint32() % (uint32_t)delta; - } else { - return a + next_uint64() % delta; - } - } - - float uniform(float a, float b) { return a + random() * (b - a); } -}; - -namespace pkpy { - -struct Random { - mt19937 gen; - - Random() { - auto count = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - gen.seed((uint32_t)count); - } - - 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); - }); - - vm->bind_func(type, "seed", 2, [](VM* vm, ArgsView args) { - Random& self = PK_OBJ_GET(Random, args[0]); - self.gen.seed(CAST(i64, args[1])); - return vm->None; - }); - - vm->bind_func(type, "randint", 3, [](VM* vm, ArgsView args) { - Random& self = PK_OBJ_GET(Random, args[0]); - i64 a = CAST(i64, args[1]); - i64 b = CAST(i64, args[2]); - if(a > b) vm->ValueError("randint(a, b): a must be less than or equal to b"); - return VAR(self.gen.randint(a, b)); - }); - - vm->bind_func(type, "random", 1, [](VM* vm, ArgsView args) { - Random& self = PK_OBJ_GET(Random, args[0]); - return VAR(self.gen.random()); - }); - - vm->bind_func(type, "uniform", 3, [](VM* vm, ArgsView args) { - Random& self = PK_OBJ_GET(Random, args[0]); - f64 a = CAST(f64, args[1]); - f64 b = CAST(f64, args[2]); - if(a > b) std::swap(a, b); - return VAR(self.gen.uniform(a, b)); - }); - - vm->bind_func(type, "shuffle", 2, [](VM* vm, ArgsView args) { - Random& self = PK_OBJ_GET(Random, args[0]); - List& L = CAST(List&, args[1]); - for(int i = L.size() - 1; i > 0; i--) { - int j = self.gen.randint(0, i); - std::swap(L[i], L[j]); - } - return vm->None; - }); - - vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) { - Random& self = PK_OBJ_GET(Random, args[0]); - ArgsView view = vm->cast_array_view(args[1]); - if(view.empty()) vm->IndexError("cannot choose from an empty sequence"); - int index = self.gen.randint(0, view.size() - 1); - return view[index]; - }); - - vm->bind(type, "choices(self, population, weights=None, k=1)", [](VM* vm, ArgsView args) { - Random& self = PK_OBJ_GET(Random, args[0]); - ArgsView view = vm->cast_array_view(args[1]); - PyVar* data = view.begin(); - int size = view.size(); - if(size == 0) vm->IndexError("cannot choose from an empty sequence"); - array cum_weights(size); - if(is_none(args[2])) { - for(int i = 0; i < size; i++) - cum_weights[i] = i + 1; - } else { - ArgsView weights = vm->cast_array_view(args[2]); - if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size)); - cum_weights[0] = CAST(f64, weights[0]); - for(int i = 1; i < size; i++) { - cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]); - } - } - if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero"); - int k = CAST(int, args[3]); - List result(k); - for(int i = 0; i < k; i++) { - f64 key = self.gen.uniform(0.0, cum_weights[size - 1]); - int index; - c11__lower_bound(f64, cum_weights.begin(), cum_weights.size(), key, c11__less, &index); - assert(index != cum_weights.size()); - result[i] = data[index]; - } - return VAR(std::move(result)); - }); - } -}; - -void add_module_random(VM* vm) { - 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")); - mod->attr().set("random", vm->getattr(instance, "random")); - mod->attr().set("uniform", vm->getattr(instance, "uniform")); - mod->attr().set("randint", vm->getattr(instance, "randint")); - mod->attr().set("shuffle", vm->getattr(instance, "shuffle")); - mod->attr().set("choice", vm->getattr(instance, "choice")); - mod->attr().set("choices", vm->getattr(instance, "choices")); -} - -} // namespace pkpy diff --git a/src/objects/base.c b/src/objects/base.c index a528d960..0e9745d5 100644 --- a/src/objects/base.c +++ b/src/objects/base.c @@ -1,8 +1,6 @@ #include "pocketpy/objects/base.h" -struct pkpy_G pkpy_g; - -PyVar pkpy_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0}; -PyVar pkpy_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0}; -PyVar pkpy_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0}; +PyVar PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0}; +PyVar PY_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0}; +PyVar PY_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0}; diff --git a/src/objects/namedict.c b/src/objects/namedict.c index 2d083cfa..f66ef7ab 100644 --- a/src/objects/namedict.c +++ b/src/objects/namedict.c @@ -3,6 +3,6 @@ #define SMALLMAP_T__SOURCE #define K uint16_t #define V PyVar -#define NAME pkpy_NameDict +#define NAME pk_NameDict #include "pocketpy/xmacros/smallmap.h" #undef SMALLMAP_T__SOURCE diff --git a/src/objects/public.cpp b/src/objects/public.cpp deleted file mode 100644 index 982d45c4..00000000 --- a/src/objects/public.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "pocketpy/objects/base.h" -#include "pocketpy/interpreter/vm.hpp" - -extern "C" { - -bool py_eq(const PyVar* a, const PyVar* b){ - auto vm = (pkpy::VM*)pkpy_g.vm; - return vm->py_eq(*a, *b); -} - -bool py_le(const PyVar* a, const PyVar* b){ - auto vm = (pkpy::VM*)pkpy_g.vm; - return vm->py_le(*a, *b); -} - -int64_t py_hash(const PyVar* a){ - auto vm = (pkpy::VM*)pkpy_g.vm; - return vm->py_hash(*a); -} - -} diff --git a/src/objects/tuplelist.cpp b/src/objects/tuplelist.cpp deleted file mode 100644 index 5e00bad5..00000000 --- a/src/objects/tuplelist.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "pocketpy/objects/tuplelist.hpp" - -namespace pkpy { - -Tuple::Tuple(int n) { - if(n <= INLINED_SIZE) { - this->_args = _inlined; - } else { - this->_args = (PyVar*)std::malloc(n * sizeof(PyVar)); - } - this->_size = n; -} - -Tuple::Tuple(Tuple&& other) noexcept { - _size = other._size; - if(other.is_inlined()) { - _args = _inlined; - for(int i = 0; i < _size; i++) - _args[i] = other._args[i]; - } else { - _args = other._args; - other._args = other._inlined; - other._size = 0; - } -} - -Tuple::Tuple(PyVar _0, PyVar _1) : Tuple(2) { - _args[0] = _0; - _args[1] = _1; -} - -Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2) : Tuple(3) { - _args[0] = _0; - _args[1] = _1; - _args[2] = _2; -} - -Tuple::~Tuple() { - if(!is_inlined()) std::free(_args); -} - -List ArgsView::to_list() const { - List ret(size()); - for(int i = 0; i < size(); i++) - ret[i] = _begin[i]; - return ret; -} - -Tuple ArgsView::to_tuple() const { - Tuple ret(size()); - for(int i = 0; i < size(); i++) - ret[i] = _begin[i]; - return ret; -} - -} // namespace pkpy diff --git a/src/public.c b/src/pocketpy.c similarity index 67% rename from src/public.c rename to src/pocketpy.c index 7eb684cf..f87bef30 100644 --- a/src/public.c +++ b/src/pocketpy.c @@ -1,9 +1,22 @@ -#include "pocketpy/objects/public.h" +#include "pocketpy/pocketpy.h" #include "pocketpy/objects/object.h" #include "pocketpy/interpreter/vm.h" +pk_VM* pk_vm; +static pk_VM pk_default_vm; + void py_initialize(){ - // initialize the global VM + Pools_initialize(); + pk_StrName__initialize(); + pk_vm = &pk_default_vm; + pk_VM__ctor(&pk_default_vm); +} + +void py_finalize(){ + pk_VM__dtor(&pk_default_vm); + pk_vm = NULL; + pk_StrName__finalize(); + Pools_finalize(); } void py_newint(PyVar* self, int64_t val){ diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp deleted file mode 100644 index c763e374..00000000 --- a/src/pocketpy.cpp +++ /dev/null @@ -1,1767 +0,0 @@ -#include "pocketpy/pocketpy.hpp" - -#include "pocketpy/common/_generated.h" - -#include "pocketpy/common/refcount.h" -#include "pocketpy/modules/array2d.hpp" -#include "pocketpy/modules/base64.hpp" -#include "pocketpy/modules/csv.hpp" -#include "pocketpy/modules/dataclasses.hpp" -#include "pocketpy/modules/easing.hpp" -#include "pocketpy/modules/io.hpp" -#include "pocketpy/modules/linalg.hpp" -#include "pocketpy/modules/random.hpp" -#include "pocketpy/modules/modules.hpp" -#include "pocketpy/objects/base.h" -#include "pocketpy/objects/codeobject.h" - -#include -#include - -namespace pkpy { - -#ifdef PK_USE_CJSON -void add_module_cjson(VM* vm); -#endif - -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); - if(is_int(_1)) { - i64 index = _1._i64; - index = vm->normalized_index(index, self.size()); - return self[index]; - } - if(is_type(_1, vm->tp_slice)) { - const Slice& s = _CAST(Slice&, _1); - int start, stop, step; - vm->parse_int_slice(s, self.size(), start, stop, step); - List new_list; - PK_SLICE_LOOP(i, start, stop, step) new_list.push_back(self[i]); - - if constexpr(std::is_same_v) - return VAR(std::move(new_list)); - else - return VAR(new_list.to_tuple()); - } - vm->TypeError("indices must be integers or slices"); -} - -void __init_builtins(VM* _vm) { -#define BIND_NUM_ARITH_OPT(name, op) \ - _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) { \ - 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; \ - }); - - BIND_NUM_ARITH_OPT(__add__, +) - BIND_NUM_ARITH_OPT(__sub__, -) - BIND_NUM_ARITH_OPT(__mul__, *) - -#undef BIND_NUM_ARITH_OPT - -#define BIND_NUM_LOGICAL_OPT(name, op) \ - _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) { \ - 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; \ - }); - - BIND_NUM_LOGICAL_OPT(__eq__, ==) - BIND_NUM_LOGICAL_OPT(__lt__, <) - BIND_NUM_LOGICAL_OPT(__le__, <=) - BIND_NUM_LOGICAL_OPT(__gt__, >) - BIND_NUM_LOGICAL_OPT(__ge__, >=) - -#undef BIND_NUM_ARITH_OPT -#undef BIND_NUM_LOGICAL_OPT - - // builtin functions - _vm->bind_func(_vm->builtins, "breakpoint", 0, [](VM* vm, ArgsView args) { -#if PK_ENABLE_PROFILER - vm->_next_breakpoint = NextBreakpoint(vm->callstack.size(), vm->callstack.top().curr_lineno(), false); -#endif - return vm->None; - }); - - _vm->bind_func(_vm->builtins, "super", -1, [](VM* vm, ArgsView args)->PyVar { - PyObject* class_arg = nullptr; - PyVar self_arg = nullptr; - if(args.size() == 2) { - 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 = frame->_callable->as()._class; - if(frame->_locals.size() > 0) self_arg = frame->_locals[0]; - } - if(class_arg == nullptr || self_arg == nullptr) { - vm->TypeError("super(): unable to determine the class context, use super(class, self) instead"); - } - } else { - vm->TypeError("super() takes 0 or 2 arguments"); - } - vm->check_type(class_arg, vm->tp_type); - 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); - vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape()); - } - return vm->new_object(vm->tp_super, self_arg, vm->_all_types[type].base); - }); - - _vm->bind_func(_vm->builtins, "staticmethod", 1, [](VM* vm, ArgsView args)->PyVar { - PyVar func = args[0]; - vm->check_type(func, vm->tp_function); - return vm->new_object(vm->tp_staticmethod, args[0]); - }); - - _vm->bind_func(_vm->builtins, "classmethod", 1, [](VM* vm, ArgsView args)->PyVar { - PyVar func = args[0]; - vm->check_type(func, vm->tp_function); - return vm->new_object(vm->tp_classmethod, args[0]); - }); - - _vm->bind_func(_vm->builtins, "isinstance", 2, [](VM* vm, ArgsView args) { - if(is_type(args[1], vm->tp_tuple)) { - Tuple& types = _CAST(Tuple&, args[1]); - for(PyVar type: types) { - vm->check_type(type, vm->tp_type); - if(vm->isinstance(args[0], type->as())) return vm->True; - } - return vm->False; - } - vm->check_type(args[1], vm->tp_type); - Type type = PK_OBJ_GET(Type, args[1]); - return VAR(vm->isinstance(args[0], type)); - }); - - _vm->bind_func(_vm->builtins, "issubclass", 2, [](VM* vm, ArgsView args) { - vm->check_type(args[0], vm->tp_type); - vm->check_type(args[1], vm->tp_type); - return VAR(vm->issubclass(PK_OBJ_GET(Type, args[0]), PK_OBJ_GET(Type, args[1]))); - }); - - _vm->bind_func(_vm->builtins, "globals", 0, [](VM* vm, ArgsView args) { - PyObject* mod = vm->callstack.top()._module; - return VAR(MappingProxy(mod)); - }); - - _vm->bind(_vm->builtins, "round(x, ndigits=None)", [](VM* vm, ArgsView args) { - if(is_int(args[0])) return args[0]; - f64 x = CAST(f64, args[0]); - f64 offset = x >= 0 ? 0.5 : -0.5; - if(is_none(args[1])) return VAR((i64)(x + offset)); - int ndigits = CAST(int, args[1]); - if(ndigits < 0) vm->ValueError("ndigits should be non-negative"); - // ndigits > 0 - return VAR((i64)(x * std::pow(10, ndigits) + offset) / std::pow(10, ndigits)); - }); - - _vm->bind_func(_vm->builtins, "abs", 1, [](VM* vm, ArgsView args) { - if(is_int(args[0])) return VAR(std::abs(_CAST(i64, args[0]))); - if(is_float(args[0])) return VAR(std::abs(_CAST(f64, args[0]))); - vm->TypeError("bad operand type for abs()"); - return vm->None; - }); - - _vm->bind(_vm->builtins, "max(*args, key=None)", [](VM* vm, ArgsView args) { - return vm->__minmax_reduce(&VM::py_gt, args[0], args[1]); - }); - - _vm->bind(_vm->builtins, "min(*args, key=None)", [](VM* vm, ArgsView args) { - return vm->__minmax_reduce(&VM::py_lt, args[0], args[1]); - }); - - _vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) { - PyVar obj = args[0]; - if(is_tagged(obj)) return vm->None; - return VAR(reinterpret_cast(obj.get())); - }); - - _vm->bind_func(_vm->builtins, "callable", 1, [](VM* vm, ArgsView args) { - return VAR(vm->py_callable(args[0])); - }); - - _vm->bind_func(_vm->builtins, "__import__", 1, [](VM* vm, ArgsView args) -> PyVar { - const Str& name = CAST(Str&, args[0]); - return vm->py_import(name); - }); - - _vm->bind_func(_vm->builtins, "divmod", 2, [](VM* vm, ArgsView args) { - if(is_int(args[0])) { - i64 lhs = _CAST(i64, args[0]); - i64 rhs = CAST(i64, args[1]); - if(rhs == 0) vm->ZeroDivisionError(); - auto res = std::div(lhs, rhs); - return VAR(Tuple(VAR(res.quot), VAR(res.rem))); - } else { - return vm->call_method(args[0], __divmod__, args[1]); - } - }); - - // we use `_0`, `_1` and `_2` here to disable keyword arguments (but with default values) - _vm->bind(_vm->builtins, "eval(_0, _1=None, _2=None)", [](VM* vm, ArgsView args) { - return vm->py_eval(CAST(Str&, args[0]), args[1], args[2]); - }); - - _vm->bind(_vm->builtins, "exec(_0, _1=None, _2=None)", [](VM* vm, ArgsView args) { - vm->py_exec(CAST(Str&, args[0]), args[1], args[2]); - return vm->None; - }); - - _vm->bind(_vm->builtins, "compile(source: str, filename: str, mode: str) -> str", [](VM* vm, ArgsView args) { - const Str& source = CAST(Str&, args[0]); - const Str& filename = CAST(Str&, args[1]); - const Str& mode = CAST(Str&, args[2]); - if(mode == "exec") { - return VAR(vm->precompile(source, filename, EXEC_MODE)); - } else if(mode == "eval") { - return VAR(vm->precompile(source, filename, EVAL_MODE)); - } else if(mode == "single") { - return VAR(vm->precompile(source, filename, CELL_MODE)); - } else { - vm->ValueError("compile() mode must be 'exec', 'eval' or 'single'"); - return vm->None; - } - }); - - _vm->bind(_vm->builtins, "exit(code=0)", [](VM* vm, ArgsView args) { - std::exit(CAST(int, args[0])); - return vm->None; - }); - - _vm->bind_func(_vm->builtins, "repr", 1, [](VM* vm, ArgsView args) { - return VAR(vm->py_repr(args[0])); - }); - - _vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args) { - const PyTypeInfo* ti = vm->_tp_info(args[0]); - if(ti->m__len__) return VAR(ti->m__len__(vm, args[0])); - return vm->call_method(args[0], __len__); - }); - - _vm->bind_func(_vm->builtins, "hash", 1, [](VM* vm, ArgsView args) { - i64 value = vm->py_hash(args[0]); - return VAR(value); - }); - - _vm->bind_func(_vm->builtins, "chr", 1, [](VM* vm, ArgsView args) { - i64 i = CAST(i64, args[0]); - if(i < 0 || i >= 128) vm->ValueError("chr() arg not in [0, 128)"); - return VAR(std::string(1, (char)i)); - }); - - _vm->bind_func(_vm->builtins, "ord", 1, [](VM* vm, ArgsView args) { - const Str& s = CAST(Str&, args[0]); - if(s.length() != 1) vm->TypeError("ord() expected an ASCII character"); - return VAR((i64)(s[0])); - }); - - _vm->bind_func(_vm->builtins, "hasattr", 2, [](VM* vm, ArgsView args) { - return VAR(vm->getattr(args[0], CAST(Str&, args[1]), false) != nullptr); - }); - - _vm->bind_func(_vm->builtins, "setattr", 3, [](VM* vm, ArgsView args) { - vm->setattr(args[0], CAST(Str&, args[1]), args[2]); - return vm->None; - }); - - _vm->bind_func(_vm->builtins, "getattr", -1, [](VM* vm, ArgsView args) { - if(args.size() != 2 && args.size() != 3) vm->TypeError("getattr() takes 2 or 3 arguments"); - StrName name = CAST(Str&, args[1]); - PyVar val = vm->getattr(args[0], name, false); - if(val == nullptr) { - if(args.size() == 2) vm->AttributeError(args[0], name); - return args[2]; - } - return val; - }); - - _vm->bind_func(_vm->builtins, "delattr", 2, [](VM* vm, ArgsView args) { - vm->delattr(args[0], CAST(Str&, args[1])); - return vm->None; - }); - - _vm->bind_func(_vm->builtins, "hex", 1, [](VM* vm, ArgsView args) { - SStream ss; - i64 val = CAST(i64, args[0]); - if(val == 0) { - ss << "0x0"; - return VAR(ss.str()); - } - if(val < 0) { - ss << "-"; - val = -val; - } - ss << "0x"; - bool non_zero = true; - for(int i = 56; i >= 0; i -= 8) { - unsigned char cpnt = (val >> i) & 0xff; - ss.write_hex(cpnt, non_zero); - if(cpnt != 0) non_zero = false; - } - return VAR(ss.str()); - }); - - _vm->bind_func(_vm->builtins, "iter", 1, [](VM* vm, ArgsView args) { - return vm->py_iter(args[0]); - }); - - _vm->bind_func(_vm->builtins, "next", 1, [](VM* vm, ArgsView args) { - PyVar retval = vm->py_next(args[0]); - if(retval == vm->StopIteration) vm->_error(vm->call(vm->StopIteration)); - return retval; - }); - - _vm->bind_func(_vm->builtins, "bin", 1, [](VM* vm, ArgsView args) { - SStream ss; - i64 x = CAST(i64, args[0]); - if(x < 0) { - ss << "-"; - x = -x; - } - ss << "0b"; - std::string bits; - while(x) { - bits += (x & 1) ? '1' : '0'; - x >>= 1; - } - std::reverse(bits.begin(), bits.end()); - if(bits.empty()) bits = "0"; - ss << bits; - return VAR(ss.str()); - }); - - _vm->bind_func(_vm->builtins, "dir", 1, [](VM* vm, ArgsView args) { - vector names; - if(!is_tagged(args[0]) && args[0]->is_attr_valid()) { - auto keys = args[0]->attr().keys(); - names.extend(keys.begin(), keys.end()); - } - const NameDict& t_attr = vm->_t(args[0])->attr(); - auto keys = t_attr.keys(); - names.extend(keys.begin(), keys.end()); - std::sort(names.begin(), names.end()); - List ret; - for(int i = 0; i < names.size(); i++) { - // remove duplicates - if(i > 0 && names[i] == names[i - 1]) continue; - ret.push_back(VAR(names[i].sv())); - } - return VAR(std::move(ret)); - }); - - // tp_object - _vm->bind__repr__(VM::tp_object, [](VM* vm, PyVar obj) -> Str { - assert(!is_tagged(obj)); - SStream ss; - ss << "<" << _type_name(vm, vm->_tp(obj)) << " object at "; - ss.write_ptr(obj.get()); - ss << ">"; - return ss.str(); - }); - - _vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) { - if(!_0.is_ptr) vm->TypeError("cannot compare tagged object: _0"); - if(!_1.is_ptr) vm->TypeError("cannot compare tagged object: _1"); - return _0._obj == _1._obj ? vm->True : vm->False; - }); - - _vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) ->PyVar { - vm->check_type(args[0], vm->tp_type); - Type t = PK_OBJ_GET(Type, args[0]); - return vm->new_object(t); - }); - - // tp_type - _vm->bind_func(VM::tp_type, __new__, 2, PK_LAMBDA(vm->_t(args[1]))); - - // tp_range - _vm->bind_func(VM::tp_range, __new__, -1, [](VM* vm, ArgsView args) { - args._begin += 1; // skip cls - Range r; - switch(args.size()) { - case 1: r.stop = CAST(i64, args[0]); break; - case 2: - r.start = CAST(i64, args[0]); - r.stop = CAST(i64, args[1]); - break; - case 3: - r.start = CAST(i64, args[0]); - r.stop = CAST(i64, args[1]); - r.step = CAST(i64, args[2]); - break; - default: vm->TypeError("expected 1-3 arguments, got " + std::to_string(args.size())); - } - if(r.step == 0) vm->ValueError("range() arg 3 must not be zero"); - return VAR(r); - }); - - _vm->bind__iter__(VM::tp_range, [](VM* vm, PyVar _0) { - const Range& r = PK_OBJ_GET(Range, _0); - if(r.step > 0) { - return vm->new_user_object(r); - } else { - return vm->new_user_object(r); - } - }); - - // tp_nonetype - _vm->bind__repr__(_vm->_tp(_vm->None), [](VM* vm, PyVar _0) -> Str { - return "None"; - }); - - // tp_float / tp_float - _vm->bind__truediv__(VM::tp_float, [](VM* vm, PyVar _0, PyVar _1) { - f64 value = CAST_F(_1); - return VAR(_CAST(f64, _0) / value); - }); - _vm->bind__truediv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) { - f64 value = CAST_F(_1); - return VAR(_CAST(i64, _0) / value); - }); - - auto py_number_pow = [](VM* vm, PyVar _0, PyVar _1) { - 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)); - } - i64 ret = 1; - while(rhs) { - if(rhs & 1) ret *= lhs; - lhs *= lhs; - rhs >>= 1; - } - return VAR(ret); - } else { - return VAR((f64)std::pow(CAST_F(_0), CAST_F(_1))); - } - }; - - _vm->bind__pow__(VM::tp_int, py_number_pow); - _vm->bind__pow__(VM::tp_float, py_number_pow); - - _vm->bind_func(VM::tp_int, __new__, -1, [](VM* vm, ArgsView args) { - if(args.size() == 1 + 0) return VAR(0); - // 1 arg - if(args.size() == 1 + 1) { - switch(vm->_tp(args[1])) { - case VM::tp_float: return VAR((i64)_CAST(f64, args[1])); - case VM::tp_int: return args[1]; - case VM::tp_bool: return VAR(args[1].extra ? 1 : 0); - case VM::tp_str: break; - default: vm->TypeError("invalid arguments for int()"); - } - } - // 2+ args -> error - if(args.size() > 1 + 2) vm->TypeError("int() takes at most 2 arguments"); - // 1 or 2 args with str - int base = 10; - if(args.size() == 1 + 2) base = CAST(i64, args[2]); - const Str& s = CAST(Str&, args[1]); - std::string_view sv = s.sv(); - bool negative = false; - if(!sv.empty() && (sv[0] == '+' || sv[0] == '-')) { - negative = sv[0] == '-'; - sv.remove_prefix(1); - } - i64 val; - if(parse_uint(sv, &val, base) != IntParsingResult::Success) { - vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape())); - } - if(negative) val = -val; - return VAR(val); - }); - - _vm->bind__floordiv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) { - i64 rhs = CAST(i64, _1); - if(rhs == 0) vm->ZeroDivisionError(); - return VAR(_CAST(i64, _0) / rhs); - }); - - _vm->bind__mod__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) { - i64 rhs = CAST(i64, _1); - if(rhs == 0) vm->ZeroDivisionError(); - return VAR(_CAST(i64, _0) % rhs); - }); - - _vm->bind_func(VM::tp_int, "bit_length", 1, [](VM* vm, ArgsView args) { - i64 x = _CAST(i64, args[0]); - if(x < 0) x = -x; - int bits = 0; - while(x) { - x >>= 1; - bits++; - } - return VAR(bits); - }); - - _vm->bind__repr__(VM::tp_int, [](VM* vm, PyVar obj) -> Str { - return std::to_string(_CAST(i64, obj)); - }); - _vm->bind__neg__(VM::tp_int, [](VM* vm, PyVar obj) { - return VAR(-_CAST(i64, obj)); - }); - _vm->bind__hash__(VM::tp_int, [](VM* vm, PyVar obj) { - return _CAST(i64, obj); - }); - _vm->bind__invert__(VM::tp_int, [](VM* vm, PyVar obj) { - return VAR(~_CAST(i64, obj)); - }); - -#define INT_BITWISE_OP(name, op) \ - _vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \ - return VAR(_CAST(i64, lhs) op CAST(i64, rhs)); \ - }); - - INT_BITWISE_OP(__lshift__, <<) - INT_BITWISE_OP(__rshift__, >>) - INT_BITWISE_OP(__and__, &) - INT_BITWISE_OP(__or__, |) - INT_BITWISE_OP(__xor__, ^) - -#undef INT_BITWISE_OP - - _vm->bind_func(VM::tp_float, __new__, -1, [](VM* vm, ArgsView args) { - if(args.size() == 1 + 0) return VAR(0.0); - if(args.size() > 1 + 1) vm->TypeError("float() takes at most 1 argument"); - // 1 arg - switch(vm->_tp(args[1])) { - case VM::tp_int: return VAR((f64)CAST(i64, args[1])); - case VM::tp_float: return args[1]; - case VM::tp_bool: return VAR(args[1].extra ? 1.0 : 0.0); - case VM::tp_str: break; - default: vm->TypeError("invalid arguments for float()"); - } - // str to float - const Str& s = PK_OBJ_GET(Str, args[1]); - if(s == "inf") return VAR(INFINITY); - if(s == "-inf") return VAR(-INFINITY); - - double float_out; - char* p_end; - try { - float_out = std::strtod(s.c_str(), &p_end); - if(p_end != s.end()) throw 1; - } catch(...) { vm->ValueError("invalid literal for float(): " + s.escape()); } - return VAR(float_out); - }); - - _vm->bind__hash__(VM::tp_float, [](VM* vm, PyVar _0) { - f64 val = _CAST(f64, _0); - return (i64)std::hash()(val); - }); - - _vm->bind__neg__(VM::tp_float, [](VM* vm, PyVar _0) { - return VAR(-_CAST(f64, _0)); - }); - - _vm->bind__repr__(VM::tp_float, [](VM* vm, PyVar _0) -> Str { - f64 val = _CAST(f64, _0); - SStream ss; - ss << val; - return ss.str(); - }); - - // tp_str - _vm->bind_func(VM::tp_str, __new__, -1, [](VM* vm, ArgsView args) { - if(args.size() == 1) return VAR(Str()); - if(args.size() > 2) vm->TypeError("str() takes at most 1 argument"); - return VAR(vm->py_str(args[1])); - }); - - _vm->bind__hash__(VM::tp_str, [](VM* vm, PyVar _0) { - return (i64)_CAST(Str&, _0).hash(); - }); - - _vm->bind__add__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) { - return VAR(_CAST(Str&, _0) + CAST(Str&, _1)); - }); - _vm->bind__len__(VM::tp_str, [](VM* vm, PyVar _0) { - return (i64)_CAST(Str&, _0).u8_length(); - }); - _vm->bind__mul__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) { - const Str& self = _CAST(Str&, _0); - i64 n = CAST(i64, _1); - SStream ss; - for(i64 i = 0; i < n; i++) - ss << self.sv(); - return VAR(ss.str()); - }); - _vm->bind_func(VM::tp_str, "__rmul__", 2, [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - i64 n = CAST(i64, args[1]); - SStream ss; - for(i64 i = 0; i < n; i++) - ss << self.sv(); - return VAR(ss.str()); - }); - _vm->bind__contains__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) { - const Str& self = _CAST(Str&, _0); - return VAR(self.index(CAST(Str&, _1)) != -1); - }); - - _vm->bind_func(VM::tp_str, __str__, 1, [](VM* vm, ArgsView args) { - return args[0]; - }); - _vm->bind__iter__(VM::tp_str, [](VM* vm, PyVar _0) { - return vm->new_user_object(_0); - }); - _vm->bind__repr__(VM::tp_str, [](VM* vm, PyVar _0) -> Str { - const Str& self = _CAST(Str&, _0); - return self.escape(); - }); - -#define BIND_CMP_STR(name, op) \ - _vm->bind##name(VM::tp_str, [](VM* vm, PyVar lhs, PyVar rhs) { \ - if(!is_type(rhs, vm->tp_str)) return vm->NotImplemented; \ - return VAR(_CAST(Str&, lhs) op _CAST(Str&, rhs)); \ - }); - - BIND_CMP_STR(__eq__, ==) - BIND_CMP_STR(__lt__, <) - BIND_CMP_STR(__le__, <=) - BIND_CMP_STR(__gt__, >) - BIND_CMP_STR(__ge__, >=) -#undef BIND_CMP_STR - - _vm->bind__getitem__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) { - const Str& self = PK_OBJ_GET(Str, _0); - if(is_type(_1, vm->tp_slice)) { - const Slice& s = _CAST(Slice&, _1); - int start, stop, step; - vm->parse_int_slice(s, self.u8_length(), start, stop, step); - return VAR(self.u8_slice(start, stop, step)); - } - i64 i = CAST(i64, _1); - i = vm->normalized_index(i, self.u8_length()); - return VAR(self.u8_getitem(i)); - }); - - _vm->bind(_vm->_t(VM::tp_str), "replace(self, old, new)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& old = CAST(Str&, args[1]); - if(old.empty()) vm->ValueError("empty substring"); - const Str& new_ = CAST(Str&, args[2]); - return VAR(self.replace(old, new_)); - }); - - _vm->bind(_vm->_t(VM::tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& sep = CAST(Str&, args[1]); - if(sep.empty()) vm->ValueError("empty separator"); - vector parts; - if(sep.size == 1) { - parts = self.split(sep[0]); - } else { - parts = self.split(sep); - } - List ret(parts.size()); - for(int i = 0; i < parts.size(); i++) - ret[i] = VAR(Str(parts[i])); - return VAR(std::move(ret)); - }); - - _vm->bind(_vm->_t(VM::tp_str), "splitlines(self)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - vector parts = self.split('\n'); - List ret(parts.size()); - for(int i = 0; i < parts.size(); i++) - ret[i] = VAR(Str(parts[i])); - return VAR(std::move(ret)); - }); - - _vm->bind(_vm->_t(VM::tp_str), "count(self, s: str)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& s = CAST(Str&, args[1]); - return VAR(self.count(s)); - }); - - _vm->bind(_vm->_t(VM::tp_str), "index(self, value, __start=0)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& value = CAST(Str&, args[1]); - int start = CAST(int, args[2]); - if(start < 0) vm->ValueError("argument 'start' can't be negative"); - int index = self.index(value, start); - if(index < 0) vm->ValueError("substring not found"); - return VAR(index); - }); - - _vm->bind(_vm->_t(VM::tp_str), "find(self, value, __start=0)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& value = CAST(Str&, args[1]); - int start = CAST(int, args[2]); - if(start < 0) vm->ValueError("argument 'start' can't be negative"); - return VAR(self.index(value, start)); - }); - - _vm->bind_func(VM::tp_str, "startswith", 2, [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& prefix = CAST(Str&, args[1]); - return VAR(self.index(prefix) == 0); - }); - - _vm->bind_func(VM::tp_str, "endswith", 2, [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - const Str& suffix = CAST(Str&, args[1]); - int offset = self.length() - suffix.length(); - if(offset < 0) return vm->False; - bool ok = memcmp(self.c_str() + offset, suffix.c_str(), suffix.length()) == 0; - return VAR(ok); - }); - - _vm->bind_func(VM::tp_str, "encode", 1, [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - Bytes retval(self.length()); - std::memcpy(retval.data(), self.c_str(), self.length()); - return VAR(std::move(retval)); - }); - - _vm->bind_func(VM::tp_str, "join", 2, [](VM* vm, ArgsView args) { - auto _lock = vm->gc_scope_lock(); - const Str& self = _CAST(Str&, args[0]); - SStream ss; - PyVar it = vm->py_iter(args[1]); // strong ref - const PyTypeInfo* info = vm->_tp_info(args[1]); - PyVar obj = vm->_py_next(info, it); - while(obj != vm->StopIteration) { - if(!ss.empty()) ss << self; - ss << CAST(Str&, obj); - obj = vm->_py_next(info, it); - } - return VAR(ss.str()); - }); - - _vm->bind_func(VM::tp_str, "lower", 1, [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - return VAR(self.lower()); - }); - - _vm->bind_func(VM::tp_str, "upper", 1, [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - return VAR(self.upper()); - }); - - _vm->bind(_vm->_t(VM::tp_str), "strip(self, chars=None)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - if(is_none(args[1])) { - return VAR(self.strip()); - } else { - const Str& chars = CAST(Str&, args[1]); - return VAR(self.strip(true, true, chars)); - } - }); - - _vm->bind(_vm->_t(VM::tp_str), "lstrip(self, chars=None)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - if(is_none(args[1])) { - return VAR(self.lstrip()); - } else { - const Str& chars = CAST(Str&, args[1]); - return VAR(self.strip(true, false, chars)); - } - }); - - _vm->bind(_vm->_t(VM::tp_str), "rstrip(self, chars=None)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - if(is_none(args[1])) { - return VAR(self.rstrip()); - } else { - const Str& chars = CAST(Str&, args[1]); - return VAR(self.strip(false, true, chars)); - } - }); - - // zfill - _vm->bind(_vm->_t(VM::tp_str), "zfill(self, width)", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - int width = CAST(int, args[1]); - int delta = width - self.u8_length(); - if(delta <= 0) return args[0]; - SStream ss; - for(int i = 0; i < delta; i++) - ss << '0'; - ss << self; - return VAR(ss.str()); - }); - - // ljust - _vm->bind(_vm->_t(VM::tp_str), "ljust(self, width, fillchar=' ')", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - int width = CAST(int, args[1]); - int delta = width - self.u8_length(); - if(delta <= 0) return args[0]; - const Str& fillchar = CAST(Str&, args[2]); - if(fillchar.u8_length() != 1) vm->TypeError("The fill character must be exactly one character long"); - SStream ss; - ss << self; - for(int i = 0; i < delta; i++) - ss << fillchar; - return VAR(ss.str()); - }); - - // rjust - _vm->bind(_vm->_t(VM::tp_str), "rjust(self, width, fillchar=' ')", [](VM* vm, ArgsView args) { - const Str& self = _CAST(Str&, args[0]); - int width = CAST(int, args[1]); - int delta = width - self.u8_length(); - if(delta <= 0) return args[0]; - const Str& fillchar = CAST(Str&, args[2]); - if(fillchar.u8_length() != 1) vm->TypeError("The fill character must be exactly one character long"); - SStream ss; - for(int i = 0; i < delta; i++) - ss << fillchar; - ss << self; - return VAR(ss.str()); - }); - - // tp_list / tp_tuple - _vm->bind(_vm->_t(VM::tp_list), "sort(self, key=None, reverse=False)", [](VM* vm, ArgsView args) { - List& self = _CAST(List&, args[0]); - PyVar key = args[1]; - if(is_none(key)) { - std::stable_sort(self.begin(), self.end(), [vm](PyVar a, PyVar b) { - return vm->py_lt(a, b); - }); - } else { - std::stable_sort(self.begin(), self.end(), [vm, key](PyVar a, PyVar b) { - return vm->py_lt(vm->call(key, a), vm->call(key, b)); - }); - } - bool reverse = CAST(bool, args[2]); - if(reverse) { std::reverse(self.begin(), self.end()); } - return vm->None; - }); - - _vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str { - if(vm->_repr_recursion_set.contains(_0.get())) return "[...]"; - List& iterable = _CAST(List&, _0); - SStream ss; - ss << '['; - vm->_repr_recursion_set.push_back(_0.get()); - for(int i = 0; i < iterable.size(); i++) { - ss << vm->py_repr(iterable[i]); - if(i != iterable.size() - 1) ss << ", "; - } - vm->_repr_recursion_set.pop_back(); - ss << ']'; - return ss.str(); - }); - - _vm->bind__repr__(VM::tp_tuple, [](VM* vm, PyVar _0) -> Str { - Tuple& iterable = _CAST(Tuple&, _0); - SStream ss; - ss << '('; - if(iterable.size() == 1) { - ss << vm->py_repr(iterable[0]); - ss << ','; - } else { - for(int i = 0; i < iterable.size(); i++) { - ss << vm->py_repr(iterable[i]); - if(i != iterable.size() - 1) ss << ", "; - } - } - ss << ')'; - return ss.str(); - }); - - _vm->bind_func(VM::tp_list, __new__, -1, [](VM* vm, ArgsView args) { - if(args.size() == 1 + 0) return VAR(List()); - if(args.size() == 1 + 1) return VAR(vm->py_list(args[1])); - vm->TypeError("list() takes 0 or 1 arguments"); - return vm->None; - }); - - _vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { - List& self = _CAST(List&, _0); - for(PyVar i: self) - if(vm->py_eq(i, _1)) return vm->True; - return vm->False; - }); - - _vm->bind_func(VM::tp_list, "count", 2, [](VM* vm, ArgsView args) { - List& self = _CAST(List&, args[0]); - int count = 0; - for(PyVar i: self) - if(vm->py_eq(i, args[1])) count++; - return VAR(count); - }); - - _vm->bind__eq__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { - List& a = _CAST(List&, _0); - if(!is_type(_1, vm->tp_list)) return vm->NotImplemented; - List& b = _CAST(List&, _1); - if(a.size() != b.size()) return vm->False; - for(int i = 0; i < a.size(); i++) { - if(!vm->py_eq(a[i], b[i])) return vm->False; - } - return vm->True; - }); - - _vm->bind(_vm->_t(VM::tp_list), "index(self, value, __start=0)", [](VM* vm, ArgsView args) { - List& self = _CAST(List&, args[0]); - PyVar obj = args[1]; - int start = CAST(int, args[2]); - for(int i = start; i < self.size(); i++) { - if(vm->py_eq(self[i], obj)) return VAR(i); - } - vm->ValueError(vm->py_repr(obj) + " is not in list"); - return vm->None; - }); - - _vm->bind_func(VM::tp_list, "remove", 2, [](VM* vm, ArgsView args) { - List& self = _CAST(List&, args[0]); - PyVar obj = args[1]; - for(PyVar* it = self.begin(); it != self.end(); it++) { - if(vm->py_eq(*it, obj)) { - self.erase(it); - return vm->None; - } - } - vm->ValueError(vm->py_repr(obj) + " is not in list"); - return vm->None; - }); - - _vm->bind_func(VM::tp_list, "pop", -1, [](VM* vm, ArgsView args) { - List& self = _CAST(List&, args[0]); - if(args.size() == 1 + 0) { - if(self.empty()) vm->IndexError("pop from empty list"); - PyVar retval = self.back(); - self.pop_back(); - return retval; - } - if(args.size() == 1 + 1) { - i64 index = CAST(i64, args[1]); - index = vm->normalized_index(index, self.size()); - PyVar ret = self[index]; - self.erase(self.begin() + index); - return ret; - } - vm->TypeError("pop() takes at most 1 argument"); - return vm->None; - }); - - _vm->bind_func(VM::tp_list, "append", 2, [](VM* vm, ArgsView args) { - List& self = _CAST(List&, args[0]); - self.push_back(args[1]); - return vm->None; - }); - - _vm->bind_func(VM::tp_list, "extend", 2, [](VM* vm, ArgsView args) { - auto _lock = vm->gc_scope_lock(); - List& self = _CAST(List&, args[0]); - PyVar it = vm->py_iter(args[1]); // strong ref - const PyTypeInfo* info = vm->_tp_info(args[1]); - PyVar obj = vm->_py_next(info, it); - while(obj != vm->StopIteration) { - self.push_back(obj); - obj = vm->_py_next(info, it); - } - return vm->None; - }); - - _vm->bind_func(VM::tp_list, "reverse", 1, [](VM* vm, ArgsView args) { - List& self = _CAST(List&, args[0]); - std::reverse(self.begin(), self.end()); - return vm->None; - }); - - _vm->bind__mul__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { - const List& self = _CAST(List&, _0); - if(!is_int(_1)) return vm->NotImplemented; - int n = _CAST(int, _1); - List result; - result.reserve(self.size() * n); - for(int i = 0; i < n; i++) - result.extend(self.begin(), self.end()); - return VAR(std::move(result)); - }); - _vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) { - const List& self = _CAST(List&, args[0]); - if(!is_int(args[1])) return vm->NotImplemented; - int n = _CAST(int, args[1]); - List result; - result.reserve(self.size() * n); - for(int i = 0; i < n; i++) - result.extend(self.begin(), self.end()); - return VAR(std::move(result)); - }); - - _vm->bind_func(VM::tp_list, "insert", 3, [](VM* vm, ArgsView args) { - List& self = _CAST(List&, args[0]); - int index = CAST(int, args[1]); - if(index < 0) index += self.size(); - if(index < 0) index = 0; - if(index > self.size()) index = self.size(); - self.insert(self.begin() + index, args[2]); - return vm->None; - }); - - _vm->bind_func(VM::tp_list, "clear", 1, [](VM* vm, ArgsView args) { - _CAST(List&, args[0]).clear(); - return vm->None; - }); - - _vm->bind_func(VM::tp_list, "copy", 1, [](VM* vm, ArgsView args) { - const List& self = _CAST(List&, args[0]); - return VAR(List(explicit_copy_t(), self)); - }); - -#define BIND_RICH_CMP(name, op, _t, _T) \ - _vm->bind__##name##__(_vm->_t, [](VM* vm, PyVar lhs, PyVar rhs) { \ - if(!is_type(rhs, vm->_t)) return vm->NotImplemented; \ - auto& a = _CAST(_T&, lhs); \ - auto& b = _CAST(_T&, rhs); \ - for(int i = 0; i < a.size() && i < b.size(); i++) { \ - if(vm->py_eq(a[i], b[i])) continue; \ - return VAR(vm->py_##name(a[i], b[i])); \ - } \ - return VAR(a.size() op b.size()); \ - }); - - BIND_RICH_CMP(lt, <, tp_list, List) - BIND_RICH_CMP(le, <=, tp_list, List) - BIND_RICH_CMP(gt, >, tp_list, List) - BIND_RICH_CMP(ge, >=, tp_list, List) - - BIND_RICH_CMP(lt, <, tp_tuple, Tuple) - BIND_RICH_CMP(le, <=, tp_tuple, Tuple) - BIND_RICH_CMP(gt, >, tp_tuple, Tuple) - BIND_RICH_CMP(ge, >=, tp_tuple, Tuple) - -#undef BIND_RICH_CMP - - _vm->bind__add__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { - const List& self = _CAST(List&, _0); - const List& other = CAST(List&, _1); - List new_list(explicit_copy_t(), self); - new_list.extend(other.begin(), other.end()); - return VAR(std::move(new_list)); - }); - - _vm->bind__len__(VM::tp_list, [](VM* vm, PyVar _0) { - return (i64)_CAST(List&, _0).size(); - }); - _vm->bind__iter__(VM::tp_list, [](VM* vm, PyVar _0) { - List& self = _CAST(List&, _0); - return vm->new_user_object(_0.get(), self.begin(), self.end()); - }); - - _vm->bind__getitem__(VM::tp_list, PyArrayGetItem); - _vm->bind__setitem__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1, PyVar _2) { - List& self = _CAST(List&, _0); - i64 i = CAST(i64, _1); - i = vm->normalized_index(i, self.size()); - self[i] = _2; - }); - _vm->bind__delitem__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { - List& self = _CAST(List&, _0); - i64 i = CAST(i64, _1); - i = vm->normalized_index(i, self.size()); - self.erase(self.begin() + i); - }); - - _vm->bind_func(VM::tp_tuple, __new__, -1, [](VM* vm, ArgsView args) { - if(args.size() == 1 + 0) return VAR(Tuple(0)); - if(args.size() == 1 + 1) { - List list = vm->py_list(args[1]); - return VAR(list.to_tuple()); - } - vm->TypeError("tuple() takes at most 1 argument"); - return vm->None; - }); - - _vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) { - Tuple& self = _CAST(Tuple&, obj); - for(PyVar i: self) - if(vm->py_eq(i, item)) return vm->True; - return vm->False; - }); - - _vm->bind_func(VM::tp_tuple, "count", 2, [](VM* vm, ArgsView args) { - Tuple& self = _CAST(Tuple&, args[0]); - int count = 0; - for(PyVar i: self) - if(vm->py_eq(i, args[1])) count++; - return VAR(count); - }); - - _vm->bind__eq__(VM::tp_tuple, [](VM* vm, PyVar _0, PyVar _1) { - const Tuple& self = _CAST(Tuple&, _0); - if(!is_type(_1, vm->tp_tuple)) return vm->NotImplemented; - const Tuple& other = _CAST(Tuple&, _1); - if(self.size() != other.size()) return vm->False; - for(int i = 0; i < self.size(); i++) { - if(!vm->py_eq(self[i], other[i])) return vm->False; - } - return vm->True; - }); - - _vm->bind__hash__(VM::tp_tuple, [](VM* vm, PyVar _0) { - i64 x = 1000003; - for(PyVar item: _CAST(Tuple&, _0)) { - i64 y = vm->py_hash(item); - // recommended by Github Copilot - x = x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2)); - } - return x; - }); - - _vm->bind__iter__(VM::tp_tuple, [](VM* vm, PyVar _0) { - Tuple& self = _CAST(Tuple&, _0); - return vm->new_user_object(_0.get(), self.begin(), self.end()); - }); - - _vm->bind__getitem__(VM::tp_tuple, PyArrayGetItem); - _vm->bind__len__(VM::tp_tuple, [](VM* vm, PyVar obj) { - return (i64)_CAST(Tuple&, obj).size(); - }); - - // tp_bool - _vm->bind_func(VM::tp_bool, __new__, 2, PK_LAMBDA(VAR(vm->py_bool(args[1])))); - _vm->bind__hash__(VM::tp_bool, [](VM* vm, PyVar _0) { - return (i64)_CAST(bool, _0); - }); - _vm->bind__repr__(VM::tp_bool, [](VM* vm, PyVar _0) -> Str { - bool val = _CAST(bool, _0); - return val ? "True" : "False"; - }); - - _vm->bind__and__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { - return VAR(_CAST(bool, _0) && CAST(bool, _1)); - }); - _vm->bind__or__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { - return VAR(_CAST(bool, _0) || CAST(bool, _1)); - }); - _vm->bind__xor__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { - return VAR(_CAST(bool, _0) != CAST(bool, _1)); - }); - _vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { - if(is_type(_1, vm->tp_bool)) return VAR(_0.extra == _1.extra); - if(is_int(_1)) return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1)); - return vm->NotImplemented; - }); - - // tp_ellipsis / tp_NotImplementedType - _vm->bind__repr__(_vm->_tp(_vm->Ellipsis), [](VM* vm, PyVar _0) -> Str { - return "..."; - }); - _vm->bind__repr__(_vm->_tp(_vm->NotImplemented), [](VM* vm, PyVar _0) -> Str { - return "NotImplemented"; - }); - - // tp_bytes - _vm->bind_func(VM::tp_bytes, __new__, 2, [](VM* vm, ArgsView args) { - List& list = CAST(List&, args[1]); - Bytes retval(list.size()); - for(int i = 0; i < list.size(); i++) { - i64 b = CAST(i64, list[i]); - if(b < 0 || b > 255) vm->ValueError("byte must be in range[0, 256)"); - retval[i] = (char)b; - } - return VAR(std::move(retval)); - }); - - _vm->bind__getitem__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) { - const Bytes& self = PK_OBJ_GET(Bytes, _0); - if(is_type(_1, vm->tp_slice)) { - const Slice& s = _CAST(Slice&, _1); - int start, stop, step; - vm->parse_int_slice(s, self.size(), start, stop, step); - int guess_max_size = abs(stop - start) / abs(step) + 1; - if(guess_max_size > self.size()) guess_max_size = self.size(); - unsigned char* buffer = (unsigned char*)std::malloc(guess_max_size); - int j = 0; // actual size - PK_SLICE_LOOP(i, start, stop, step) buffer[j++] = self[i]; - return VAR(Bytes(buffer, j)); - } - i64 i = CAST(i64, _1); - i = vm->normalized_index(i, self.size()); - return VAR(self[i]); - }); - - _vm->bind__add__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) { - const Bytes& a = _CAST(Bytes&, _0); - const Bytes& b = CAST(Bytes&, _1); - Bytes retval(a.size() + b.size()); - std::memcpy(retval.data(), a.data(), a.size()); - std::memcpy(retval.data() + a.size(), b.data(), b.size()); - return VAR(std::move(retval)); - }); - - _vm->bind__hash__(VM::tp_bytes, [](VM* vm, PyVar _0) { - const Bytes& self = _CAST(Bytes&, _0); - std::string_view view((char*)self.data(), self.size()); - return (i64)std::hash()(view); - }); - - _vm->bind__repr__(VM::tp_bytes, [](VM* vm, PyVar _0) -> Str { - const Bytes& self = _CAST(Bytes&, _0); - SStream ss; - ss << "b'"; - for(int i = 0; i < self.size(); i++) { - ss << "\\x"; - ss.write_hex((unsigned char)self[i]); - } - ss << "'"; - return ss.str(); - }); - _vm->bind__len__(VM::tp_bytes, [](VM* vm, PyVar _0) { - return (i64)_CAST(Bytes&, _0).size(); - }); - - _vm->bind_func(VM::tp_bytes, "decode", 1, [](VM* vm, ArgsView args) { - const Bytes& self = _CAST(Bytes&, args[0]); - return VAR(Str(std::string_view((char*)self.data(), self.size()))); - }); - - _vm->bind__eq__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) { - if(!is_type(_1, vm->tp_bytes)) return vm->NotImplemented; - const Bytes& lhs = _CAST(Bytes&, _0); - const Bytes& rhs = _CAST(Bytes&, _1); - if(lhs.size() != rhs.size()) return vm->False; - return VAR(memcmp(lhs.data(), rhs.data(), lhs.size()) == 0); - }); - - // tp_slice - _vm->bind_func(VM::tp_slice, __new__, 4, [](VM* vm, ArgsView args) { - return VAR(Slice(args[1], args[2], args[3])); - }); - - _vm->bind__eq__(VM::tp_slice, [](VM* vm, PyVar _0, PyVar _1) { - const Slice& self = _CAST(Slice&, _0); - if(!is_type(_1, vm->tp_slice)) return vm->NotImplemented; - const Slice& other = _CAST(Slice&, _1); - if(vm->py_ne(self.start, other.start)) return vm->False; - if(vm->py_ne(self.stop, other.stop)) return vm->False; - if(vm->py_ne(self.step, other.step)) return vm->False; - return vm->True; - }); - - _vm->bind__repr__(VM::tp_slice, [](VM* vm, PyVar _0) -> Str { - const Slice& self = _CAST(Slice&, _0); - SStream ss; - ss << "slice("; - ss << vm->py_repr(self.start) << ", "; - ss << vm->py_repr(self.stop) << ", "; - ss << vm->py_repr(self.step) << ")"; - return ss.str(); - }); - - // tp_mappingproxy - _vm->bind_func(VM::tp_mappingproxy, "keys", 1, [](VM* vm, ArgsView args) { - MappingProxy& self = _CAST(MappingProxy&, args[0]); - List keys; - for(StrName name: self.attr().keys()) - keys.push_back(VAR(name.sv())); - return VAR(std::move(keys)); - }); - - _vm->bind_func(VM::tp_mappingproxy, "values", 1, [](VM* vm, ArgsView args) { - MappingProxy& self = _CAST(MappingProxy&, args[0]); - List values; - for(auto [k, v]: self.attr().items()) - values.push_back(v); - return VAR(std::move(values)); - }); - - _vm->bind_func(VM::tp_mappingproxy, "items", 1, [](VM* vm, ArgsView args) { - MappingProxy& self = _CAST(MappingProxy&, args[0]); - List items; - for(auto [k, v]: self.attr().items()) { - PyVar t = VAR(Tuple(VAR(k.sv()), v)); - items.push_back(std::move(t)); - } - return VAR(std::move(items)); - }); - - _vm->bind__len__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) { - return (i64)_CAST(MappingProxy&, _0).attr().size(); - }); - - _vm->bind__eq__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) { - const MappingProxy& a = _CAST(MappingProxy&, _0); - if(!is_type(_1, VM::tp_mappingproxy)) return vm->NotImplemented; - const MappingProxy& b = _CAST(MappingProxy&, _1); - return VAR(a.obj == b.obj); - }); - - _vm->bind__getitem__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) { - MappingProxy& self = _CAST(MappingProxy&, _0); - StrName key = CAST(Str&, _1); - PyVar ret = self.attr().try_get_likely_found(key); - if(ret == nullptr) vm->KeyError(_1); - return ret; - }); - - _vm->bind(_vm->_t(VM::tp_mappingproxy), "get(self, key, default=None)", [](VM* vm, ArgsView args) { - MappingProxy& self = _CAST(MappingProxy&, args[0]); - StrName key = CAST(Str&, args[1]); - PyVar ret = self.attr().try_get(key); - if(ret == nullptr) return args[2]; - return ret; - }); - - _vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str { - if(vm->_repr_recursion_set.contains(_0.get())) return "{...}"; - MappingProxy& self = _CAST(MappingProxy&, _0); - SStream ss; - ss << "mappingproxy({"; - bool first = true; - vm->_repr_recursion_set.push_back(_0.get()); - for(auto [k, v]: self.attr().items()) { - if(!first) ss << ", "; - first = false; - ss << k.escape() << ": "; - ss << vm->py_repr(v); - } - vm->_repr_recursion_set.pop_back(); - ss << "})"; - return ss.str(); - }); - - _vm->bind__contains__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) { - MappingProxy& self = _CAST(MappingProxy&, _0); - return VAR(self.attr().contains(CAST(Str&, _1))); - }); - - // tp_dict - _vm->bind_func(VM::tp_dict, __new__, -1, [](VM* vm, ArgsView args)->PyVar { - Type cls_t = PK_OBJ_GET(Type, args[0]); - return vm->new_object(cls_t); - }); - - _vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) { - if(args.size() == 1 + 0) return vm->None; - if(args.size() == 1 + 1) { - auto _lock = vm->gc_scope_lock(); - Dict& self = PK_OBJ_GET(Dict, args[0]); - if(is_type(args[1], vm->tp_dict)) { - Dict& other = CAST(Dict&, args[1]); - self.update(vm, other); - return vm->None; - } - if(is_type(args[1], vm->tp_list)) { - List& list = PK_OBJ_GET(List, args[1]); - for(PyVar item: list) { - Tuple& t = CAST(Tuple&, item); - if(t.size() != 2) { - vm->ValueError("dict() takes a list of tuples (key, value)"); - return vm->None; - } - self.set(vm, t[0], t[1]); - } - return vm->None; - } - vm->TypeError("dict() takes a dictionary or a list of tuples"); - } - vm->TypeError("dict() takes at most 1 argument"); - }); - - _vm->bind__len__(VM::tp_dict, [](VM* vm, PyVar _0) { - return (i64)PK_OBJ_GET(Dict, _0).size(); - }); - - _vm->bind__getitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) { - Dict& self = PK_OBJ_GET(Dict, _0); - PyVar ret = self.try_get(vm, _1); - if(ret == nullptr) { - // try __missing__ - PyVar self; - PyVar f_missing = vm->get_unbound_method(_0, __missing__, &self, false); - if(f_missing != nullptr) { return vm->call_method(self, f_missing, _1); } - vm->KeyError(_1); - } - return ret; - }); - - _vm->bind__setitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1, PyVar _2) { - Dict& self = _CAST(Dict&, _0); - self.set(vm, _1, _2); - }); - - _vm->bind__delitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) { - Dict& self = _CAST(Dict&, _0); - bool ok = self.del(vm, _1); - if(!ok) vm->KeyError(_1); - }); - - _vm->bind_func(VM::tp_dict, "pop", -1, [](VM* vm, ArgsView args) { - if(args.size() != 2 && args.size() != 3) { - vm->TypeError("pop() expected 1 or 2 arguments"); - return vm->None; - } - Dict& self = _CAST(Dict&, args[0]); - PyVar value = self.try_get(vm, args[1]); - if(value == nullptr) { - if(args.size() == 2) vm->KeyError(args[1]); - if(args.size() == 3) { return args[2]; } - } - self.del(vm, args[1]); - return value; - }); - - _vm->bind__contains__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) { - Dict& self = _CAST(Dict&, _0); - return VAR(self.contains(vm, _1)); - }); - - _vm->bind__iter__(VM::tp_dict, [](VM* vm, PyVar _0) { - const Dict& self = _CAST(Dict&, _0); - return vm->py_iter(VAR(self.keys())); - }); - - _vm->bind_func(VM::tp_dict, "get", -1, [](VM* vm, ArgsView args) { - Dict& self = _CAST(Dict&, args[0]); - if(args.size() == 1 + 1) { - PyVar ret = self.try_get(vm, args[1]); - if(ret != nullptr) return ret; - return vm->None; - } else if(args.size() == 1 + 2) { - PyVar ret = self.try_get(vm, args[1]); - if(ret != nullptr) return ret; - return args[2]; - } - vm->TypeError("get() takes at most 2 arguments"); - return vm->None; - }); - - _vm->bind_func(VM::tp_dict, "keys", 1, [](VM* vm, ArgsView args) { - const Dict& self = _CAST(Dict&, args[0]); - return VAR(self.keys()); - }); - - _vm->bind_func(VM::tp_dict, "values", 1, [](VM* vm, ArgsView args) { - const Dict& self = _CAST(Dict&, args[0]); - return VAR(self.values()); - }); - - _vm->bind_func(VM::tp_dict, "items", 1, [](VM* vm, ArgsView args) { - return vm->new_user_object(args[0]); - }); - - _vm->bind_func(VM::tp_dict, "update", 2, [](VM* vm, ArgsView args) { - Dict& self = _CAST(Dict&, args[0]); - const Dict& other = CAST(Dict&, args[1]); - self.update(vm, other); - return vm->None; - }); - - _vm->bind_func(VM::tp_dict, "copy", 1, [](VM* vm, ArgsView args) { - const Dict& self = _CAST(Dict&, args[0]); - return VAR(self); - }); - - _vm->bind_func(VM::tp_dict, "clear", 1, [](VM* vm, ArgsView args) { - Dict& self = _CAST(Dict&, args[0]); - self.clear(); - return vm->None; - }); - - _vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str { - if(vm->_repr_recursion_set.contains(_0.get())) return "{...}"; - Dict& self = _CAST(Dict&, _0); - SStream ss; - ss << "{"; - bool first = true; - vm->_repr_recursion_set.push_back(_0.get()); - self.apply([&](PyVar k, PyVar v) { - if(!first) ss << ", "; - first = false; - ss << vm->py_repr(k) << ": " << vm->py_repr(v); - }); - vm->_repr_recursion_set.pop_back(); - ss << "}"; - return ss.str(); - }); - - _vm->bind__eq__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) { - Dict& self = _CAST(Dict&, _0); - if(!vm->isinstance(_1, vm->tp_dict)) return vm->NotImplemented; - Dict& other = _CAST(Dict&, _1); - if(self.size() != other.size()) return vm->False; - pkpy_DictIter it = self.iter(); - PyVar key, val; - while(pkpy_DictIter__next(&it, (PyVar*)(&key), (PyVar*)(&val))) { - PyVar other_val = other.try_get(vm, key); - if(other_val == nullptr) return vm->False; - if(!vm->py_eq(val, other_val)) return vm->False; - } - return vm->True; - }); - - _vm->bind__repr__(VM::tp_module, [](VM* vm, PyVar _0) -> Str { - const Str& path = CAST(Str&, _0->attr(__path__)); - return _S(""); - }); - - // tp_property - _vm->bind_func(VM::tp_property, __new__, -1, [](VM* vm, ArgsView args) { - if(args.size() == 1 + 1) { - return VAR(Property(args[1], vm->None)); - } else if(args.size() == 1 + 2) { - return VAR(Property(args[1], args[2])); - } - vm->TypeError("property() takes at most 2 arguments"); - return vm->None; - }); - - _vm->bind_property(_vm->_t(VM::tp_function), "__doc__", [](VM* vm, ArgsView args) { - Function& func = _CAST(Function&, args[0]); - if(!func.decl->docstring) return vm->None; - return VAR(func.decl->docstring); - }); - - _vm->bind_property(_vm->_t(VM::tp_native_func), "__doc__", [](VM* vm, ArgsView args) { - NativeFunc& func = _CAST(NativeFunc&, args[0]); - if(func.decl == nullptr) return vm->None; - if(!func.decl->docstring) return vm->None; - return VAR(func.decl->docstring); - }); - - // tp_exception - _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); - PyObject* e_obj = vm->new_object(cls, cls_name.index).get(); - e_obj->_attr = new NameDict(); - e_obj->as().self = e_obj; - return e_obj; - }); - - _vm->bind(_vm->_t(VM::tp_exception), "__init__(self, msg=...)", [](VM* vm, ArgsView args) { - Exception& self = _CAST(Exception&, args[0]); - if(args[1].type != tp_ellipsis) { - const char* msg = CAST(Str&, args[1]).c_str(); - pkpy_Str__dtor(&self.msg); - pkpy_Str__ctor(&self.msg, msg); - } - return vm->None; - }); - - _vm->bind__repr__(VM::tp_exception, [](VM* vm, PyVar _0) -> Str { - Exception& self = _CAST(Exception&, _0); - const char* msg_s = pkpy_Str__data(&self.msg); - return _S(_type_name(vm, _0.type), '(', Str(msg_s).escape(), ')'); - }); - - _vm->bind__str__(VM::tp_exception, [](VM* vm, PyVar _0) -> Str { - Exception& self = _CAST(Exception&, _0); - return pkpy_Str__copy(&self.msg); - }); - - _vm->register_user_class(_vm->builtins, "_range_iter"); - _vm->register_user_class(_vm->builtins, "_range_iter_r"); - _vm->register_user_class(_vm->builtins, "_array_iter"); - _vm->register_user_class(_vm->builtins, "_string_iter"); - _vm->register_user_class(_vm->builtins, "generator"); - _vm->register_user_class(_vm->builtins, "_dict_items_iter"); -} - -void VM::__post_init_builtin_types() { - __init_builtins(this); - - bind_func(tp_module, __new__, -1, PK_ACTION(vm->NotImplementedError())); - - _all_types[tp_module].m__getattr__ = [](VM* vm, PyVar obj, StrName name) -> PyVar { - const Str& path = CAST(Str&, obj->attr(__path__)); - PyObject* retval = vm->py_import(_S(path, ".", name.sv()), false); - if(retval) return retval; - return nullptr; - }; - - bind_func(tp_property, "setter", 2, [](VM* vm, ArgsView args) { - Property& self = _CAST(Property&, args[0]); - // The setter's name is not necessary to be the same as the property's name - // However, for cpython compatibility, we recommend to use the same name - self.setter = args[1]; - return args[0]; - }); - - // type - bind__getitem__(tp_type, [](VM* vm, PyVar self, PyVar _) { - return self; // for generics - }); - - bind__repr__(tp_type, [](VM* vm, PyVar self) -> Str { - SStream ss; - const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, self)]; - ss << ""; - return ss.str(); - }); - - bind_property(_t(tp_object), "__class__", PK_LAMBDA(vm->_t(args[0]))); - bind_property(_t(tp_type), "__base__", [](VM* vm, ArgsView args) { - const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; - return info.base ? vm->_all_types[info.base].obj : vm->None; - }); - bind_property(_t(tp_type), "__name__", [](VM* vm, ArgsView args) { - 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) -> PyVar { - const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; - if(info.mod == nullptr) return vm->None; - return info.mod; - }); - bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args) { - return CAST(BoundMethod&, args[0]).self; - }); - bind_property(_t(tp_bound_method), "__func__", [](VM* vm, ArgsView args) { - return CAST(BoundMethod&, args[0]).func; - }); - - bind__eq__(tp_bound_method, [](VM* vm, PyVar lhs, PyVar rhs) { - if(!is_type(rhs, vm->tp_bound_method)) return vm->NotImplemented; - const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs); - const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs); - return VAR(PyVar__IS_OP(&_0.self, &_1.self) && PyVar__IS_OP(&_0.func, &_1.func)); - }); - - bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args) { - return CAST(Slice&, args[0]).start; - }); - bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args) { - return CAST(Slice&, args[0]).stop; - }); - bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args) { - return CAST(Slice&, args[0]).step; - }); - - 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].get())); - }); - - bind(builtins, "print(*args, sep=' ', end='\\n')", [](VM* vm, ArgsView args) { - const Tuple& _0 = CAST(Tuple&, args[0]); - const Str& _1 = CAST(Str&, args[1]); - const Str& _2 = CAST(Str&, args[2]); - SStream ss; - for(int i = 0; i < _0.size(); i++) { - ss << vm->py_str(_0[i]); - if(i != _0.size() - 1) ss << _1; - } - ss << _2; - vm->stdout_write(ss.str()); - return vm->None; - }); - - add_module___builtins(vm); - add_module_sys(this); - add_module_traceback(this); - add_module_time(this); - add_module_json(this); - add_module_math(this); - add_module_dis(this); - add_module_c(this); - add_module_gc(this); - add_module_random(this); - add_module_base64(this); - - _lazy_modules.insert("this", kPythonLibs_this); - _lazy_modules.insert("functools", kPythonLibs_functools); - _lazy_modules.insert("heapq", kPythonLibs_heapq); - _lazy_modules.insert("bisect", kPythonLibs_bisect); - _lazy_modules.insert("pickle", kPythonLibs_pickle); - _lazy_modules.insert("_long", kPythonLibs__long); - _lazy_modules.insert("colorsys", kPythonLibs_colorsys); - _lazy_modules.insert("typing", kPythonLibs_typing); - _lazy_modules.insert("datetime", kPythonLibs_datetime); - _lazy_modules.insert("cmath", kPythonLibs_cmath); - _lazy_modules.insert("itertools", kPythonLibs_itertools); - _lazy_modules.insert("operator", kPythonLibs_operator); - _lazy_modules.insert("collections", kPythonLibs_collections); - - try { - // initialize dummy func_decl for exec/eval - CodeObject* code = compile("def _(): pass", "", EXEC_MODE); - __dynamic_func_decl = c11__getitem(FuncDecl_, &code->func_decls, 0); - PK_INCREF(__dynamic_func_decl); - CodeObject__delete(code); - // initialize builtins - code = compile(kPythonLibs_builtins, "", EXEC_MODE); - this->_exec(code, this->builtins); - CodeObject__delete(code); - code = compile(kPythonLibs__set, "", EXEC_MODE); - this->_exec(code, this->builtins); - CodeObject__delete(code); - } catch(TopLevelException e) { - std::cerr << e.summary() << std::endl; - std::cerr << "failed to load builtins module!!" << std::endl; - exit(1); - } - - if(enable_os) { - add_module_io(this); - add_module_os(this); - _import_handler = &_default_import_handler; - } - - add_module_csv(this); - add_module_dataclasses(this); - add_module_linalg(this); - add_module_easing(this); - add_module_array2d(this); - add_module_line_profiler(this); - add_module_enum(this); - -#ifdef PK_USE_CJSON - add_module_cjson(this); -#endif -} - -CodeObject* VM::compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope) { - Compiler compiler(this, source, filename, mode, unknown_global_scope); - CodeObject* code; - Error* err = compiler.compile(&code); - if(err) __compile_error(err); - return code; -} - -void VM::__compile_error(Error* err){ - assert(err != nullptr); - if(err->type == std::string_view("NeedMoreLines")){ - bool arg = (bool)err->userdata; - PK_DECREF(err->src); - std::free(err); - throw NeedMoreLines(arg); - } - __last_exception = vm->call( - vm->builtins->attr(err->type), - VAR((const char*)err->msg) - ).get(); - Exception& e = __last_exception->as(); - e.stpush(err->src, err->lineno, err->cursor, ""); - PK_DECREF(err->src); - std::free(err); - _error(__last_exception); -} - -Str VM::precompile(std::string_view source, const Str& filename, CompileMode mode) { - Compiler compiler(this, source, filename, mode, false); - Str out; - Error* err = compiler.lexer.precompile(&out); - if(err) __compile_error(err); - return out; -} - -} // namespace pkpy diff --git a/src/pocketpy_c.cpp b/src/pocketpy_c.cpp deleted file mode 100644 index 8df1fa80..00000000 --- a/src/pocketpy_c.cpp +++ /dev/null @@ -1,575 +0,0 @@ -#include "pocketpy/objects/codeobject.h" -#ifndef PK_NO_EXPORT_C_API - -#include "pocketpy/pocketpy.hpp" -#include "pocketpy/pocketpy_c.h" - -#include - -namespace pkpy{ - -#define PK_ASSERT_N_EXTRA_ELEMENTS(n) \ - int __ex_count = count_extra_elements(vm, n); \ - if(__ex_count < n) { \ - Str msg = _S("expected at least ", n, " elements, got ", __ex_count); \ - pkpy_error(vm_handle, "StackError", pkpy_string(msg.c_str())); \ - return false; \ - } - -#define PK_ASSERT_NO_ERROR() \ - if(vm->__c.error != nullptr) return false; - -static int count_extra_elements(VM* vm, int n) { - if(vm->callstack.empty()) { return vm->s_data.size(); } - assert(!vm->__c.s_view.empty()); - return vm->s_data._sp - vm->__c.s_view.back().end(); -} - -static PyVar stack_item(VM* vm, int index) { - PyVar* begin; - PyVar* end = vm->s_data.end(); - if(vm->callstack.empty()) { - begin = vm->s_data.begin(); - } else { - assert(!vm->__c.s_view.empty()); - begin = vm->__c.s_view.back().begin(); - } - int size = end - begin; - if(index < 0) index += size; - assert(index >= 0 && index < size); - return begin[index]; -} - -#define PK_PROTECTED(__B) \ - try { \ - __B \ - } catch(TopLevelException e) { \ - vm->__c.error = (PyObject*)e.ptr->self; \ - return false; \ - } catch(const std::exception& re) { \ - PyObject* e_t = vm->_t(vm->tp_exception); \ - vm->__c.error = vm->call(e_t, VAR(re.what())).get(); \ - return false; \ - } - -pkpy_vm* pkpy_new_vm(bool enable_os) { return (pkpy_vm*)new VM(enable_os); } - -void pkpy_delete_vm(pkpy_vm* vm) { return delete (VM*)vm; } - -bool pkpy_exec(pkpy_vm* vm_handle, const char* source) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar res; - PK_PROTECTED( - CodeObject* code = vm->compile(source, "main.py", EXEC_MODE); - res = vm->_exec(code, vm->_main); - CodeObject__delete(code); - ) - return res != nullptr; -} - -bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar res; - PyObject* mod; - PK_PROTECTED( - if(module == nullptr){ mod = vm->_main; - }else{ - mod = vm->_modules[module].get(); // may raise - } - CodeObject* code = vm->compile(source, filename, (CompileMode)mode); - res = vm->_exec(code, mod); - CodeObject__delete(code); // TODO: _exec may raise, so code may leak - ) - return res != nullptr; -} - -void pkpy_set_main_argv(pkpy_vm* vm_handle, int argc, char** argv) { - VM* vm = (VM*)vm_handle; - vm->set_main_argv(argc, argv); -} - -bool pkpy_dup(pkpy_vm* vm_handle, int n) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, n); - vm->s_data.push(item); - ) - return true; -} - -bool pkpy_pop(pkpy_vm* vm_handle, int n) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(n) - vm->s_data.shrink(n); - return true; -} - -bool pkpy_pop_top(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(1) - vm->s_data.pop(); - return true; -} - -bool pkpy_dup_top(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(1) - vm->s_data.push(vm->s_data.top()); - return true; -} - -bool pkpy_rot_two(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(2) - std::swap(vm->s_data.top(), vm->s_data.second()); - return true; -} - -int pkpy_stack_size(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - if(vm->callstack.empty()) { return vm->s_data.size(); } - if(vm->__c.s_view.empty()) exit(127); - return vm->s_data._sp - vm->__c.s_view.back().begin(); -} - -// int -bool pkpy_push_int(pkpy_vm* vm_handle, int value) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar res; - PK_PROTECTED( - // int may overflow so we should protect it - res = py_var(vm, value); - ) - vm->s_data.push(res); - return true; -} - -bool pkpy_is_int(pkpy_vm* vm_handle, int i) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - return is_int(stack_item(vm, i)); - ) -} - -bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - *out = py_cast(vm, item); - ) - return true; -} - -// float -bool pkpy_push_float(pkpy_vm* vm_handle, double value) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar res = py_var(vm, value); - vm->s_data.push(res); - return true; -} - -bool pkpy_is_float(pkpy_vm* vm_handle, int i) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - return is_float(item); - ) -} - -bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - *out = py_cast(vm, item); - ) - return true; -} - -// bool -bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - vm->s_data.push(value ? vm->True : vm->False); - return true; -} - -bool pkpy_is_bool(pkpy_vm* vm_handle, int i) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - return is_type(item, vm->tp_bool); - ) -} - -bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - *out = py_cast(vm, item); - ) - return true; -} - -// string -bool pkpy_push_string(pkpy_vm* vm_handle, pkpy_CString value) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar res = py_var(vm, value); - vm->s_data.push(res); - return true; -} - -bool pkpy_is_string(pkpy_vm* vm_handle, int i) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - return is_type(item, vm->tp_str); - ) -} - -bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - const Str& s = py_cast(vm, item); - *out = s.c_str(); - ) - return true; -} - -// void_p -bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar res = py_var(vm, value); - vm->s_data.push(res); - return true; -} - -bool pkpy_is_voidp(pkpy_vm* vm_handle, int i) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - return vm->is_user_type(item); - ) -} - -bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - VoidP& vp = py_cast(vm, item); - *out = vp.ptr; - ) - return true; -} - -// none -bool pkpy_push_none(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - vm->s_data.push(vm->None); - return true; -} - -bool pkpy_is_none(pkpy_vm* vm_handle, int i) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar item = stack_item(vm, i); - return is_none(item); - ) -} - -// null -bool pkpy_push_null(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - vm->s_data.push(PY_NULL); - return true; -} - -struct TempViewPopper { - VM* vm; - bool used; - - TempViewPopper(VM* vm) : vm(vm), used(false) {} - - void restore() noexcept { - if(used) return; - vm->__c.s_view.pop_back(); - used = true; - } - - ~TempViewPopper() { restore(); } -}; - -// function -static PyVar c_function_wrapper(VM* vm, ArgsView args) { - pkpy_CFunction f = lambda_get_userdata(args.begin()); - PyVar* curr_sp = vm->s_data._sp; - - vm->__c.s_view.push_back(args); - TempViewPopper _tvp(vm); - int retc = f((pkpy_vm*)vm); // may raise, _tvp will handle this via RAII - _tvp.restore(); - - // propagate_if_errored - if(vm->__c.error != nullptr) { - PyObject* e_obj = vm->__c.error; - vm->__c.error = nullptr; - vm->_error(e_obj); - return nullptr; - } - assert(retc == vm->s_data._sp - curr_sp); - if(retc == 0) return vm->None; - if(retc == 1) return vm->s_data.popx(); - ArgsView ret_view(curr_sp, vm->s_data._sp); - return py_var(vm, ret_view.to_tuple()); -} - -bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar f_obj; - PK_PROTECTED( - f_obj = vm->bind(nullptr, sig, c_function_wrapper, f); - ) - vm->s_data.push(f_obj); - return true; -} - -// special push -bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyObject* module = vm->new_module(name); - vm->s_data.emplace(module); - ) - return true; -} - -// some opt -bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(1) - PyVar o = vm->s_data.top(); - o = vm->getattr(o, StrName(name), false); - if(o == nullptr) return false; - vm->s_data.top() = o; - return true; -} - -bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(2) - PyVar a = vm->s_data.top(); - PyVar val = vm->s_data.second(); - PK_PROTECTED( - vm->setattr(a, StrName(name), val); - ) - vm->s_data.shrink(2); - return true; -} - -// get global will also get bulitins -bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar o = vm->_main->attr().try_get(StrName(name)); - if(o == nullptr) { - o = vm->builtins->attr().try_get(StrName(name)); - if(o == nullptr) return false; - } - vm->s_data.push(o); - return true; -} - -bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(1) - vm->_main->attr().set(StrName(name), vm->s_data.popx()); - return true; -} - -bool pkpy_eval(pkpy_vm* vm_handle, const char* source) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - CodeObject* code = vm->compile(source, "", EVAL_MODE); - PyVar ret = vm->_exec(code, vm->_main); - vm->s_data.push(ret); - CodeObject__delete(code); - ) - return true; -} - -bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(1) - auto _lock = vm->gc_scope_lock(); - PK_PROTECTED( - PyVar _0 = vm->py_iter(vm->s_data.popx()); - for(int i=0; ipy_next(_0); - if(_1 == vm->StopIteration) vm->ValueError("not enough values to unpack"); - vm->s_data.push(_1); - } - if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack"); - ) - return true; -} - -bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(1) - PyVar o = vm->s_data.top(); - PyVar self; - PK_PROTECTED( - o = vm->get_unbound_method(o, StrName(name), &self); - ) - vm->s_data.pop(); - vm->s_data.push(o); - vm->s_data.push(self); - return true; -} - -bool pkpy_py_repr(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(1) - PyVar item = vm->s_data.top(); - PK_PROTECTED( - item = VAR(vm->py_repr(item)); - ) - vm->s_data.top() = item; - return true; -} - -bool pkpy_py_str(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(1) - PyVar item = vm->s_data.top(); - PK_PROTECTED( - item = VAR(vm->py_str(item)); - ) - vm->s_data.top() = item; - return true; -} - -bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_PROTECTED( - PyVar module = vm->py_import(name); - vm->s_data.push(module); - ) - return true; -} - -/* Error Handling */ -bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PyVar e_t = vm->_main->attr().try_get_likely_found(name); - if(e_t == nullptr) { - e_t = vm->builtins->attr().try_get_likely_found(name); - if(e_t == nullptr) { - e_t = vm->_t(vm->tp_exception); - std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'" - << std::endl; - } - } - vm->__c.error = vm->call(e_t, VAR(message)).get(); - return false; -} - -bool pkpy_check_error(pkpy_vm* vm_handle) { - VM* vm = (VM*)vm_handle; - return vm->__c.error != nullptr; -} - -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 = vm->__c.error->as(); - if(message != nullptr) - *message = strdup(e.summary().c_str()); - else - std::cout << e.summary() << std::endl; - vm->__c.error = nullptr; - if(vm->callstack.empty()) { - vm->s_data.clear(); - } else { - if(vm->__c.s_view.empty()) exit(127); - vm->s_data.reset(vm->__c.s_view.back().end()); - } - return true; -} - -bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) { - VM* vm = (VM*)vm_handle; - PK_ASSERT_NO_ERROR() - PK_ASSERT_N_EXTRA_ELEMENTS(argc + 2) - PyVar res; - PK_PROTECTED( - res = vm->vectorcall(argc); - ) - vm->s_data.push(res); - return true; -} - -/*****************************************************************/ -void pkpy_free(void* p) { std::free(p); } - -pkpy_CName pkpy_name(const char* name) { return StrName(name).index; } - -pkpy_CString pkpy_name_to_string(pkpy_CName name) { return StrName(name).c_str(); } - -void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler) { - VM* vm = (VM*)vm_handle; - vm->_stdout = handler; -} - -void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler) { - VM* vm = (VM*)vm_handle; - vm->_import_handler = handler; -} - -void* pkpy_new_repl(pkpy_vm* vm_handle) { return new REPL((VM*)vm_handle); } - -bool pkpy_repl_input(void* r, const char* line) { return ((REPL*)r)->input(line); } - -void pkpy_delete_repl(void* repl) { delete (REPL*)repl; } - -#endif // PK_NO_EXPORT_C_API - -} // namespace pkpy \ No newline at end of file diff --git a/src2/main.c b/src2/main.c new file mode 100644 index 00000000..c4f0e3c7 --- /dev/null +++ b/src2/main.c @@ -0,0 +1,42 @@ +#include +#include +#include "pocketpy.h" + +char* read_file(const char* path) { + FILE* file = fopen(path, "r"); + if(file == NULL) { + printf("Error: file not found\n"); + return NULL; + } + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char* buffer = malloc(size + 1); + fread(buffer, 1, size, file); + buffer[size] = 0; + return buffer; +} + +int main(int argc, char** argv) { +#if _WIN32 + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); +#endif + + if(argc != 2) goto __HELP; + char* source = read_file(argv[1]); + py_initialize(); + + py_Error* err = py_exec_simple(source); + if(err){ + py_Error__print(err); + py_Error__delete(err); + } + + py_finalize(); + free(source); + +__HELP: + printf("Usage: pocketpy [filename]\n"); + return 0; +} diff --git a/src2/pocketpy_c.c b/src2/pocketpy_c.c deleted file mode 100644 index ce17fb43..00000000 --- a/src2/pocketpy_c.c +++ /dev/null @@ -1,265 +0,0 @@ - -#include "pocketpy/pocketpy_c.h" - -#ifdef _WIN32 -#pragma warning(disable: 4700) -#endif - -pkpy_vm* pkpy_new_vm(bool enable_os) { - pkpy_vm* returnValue; - return returnValue; -} - -void pkpy_delete_vm(pkpy_vm* vm) { - -} - -bool pkpy_exec(pkpy_vm* vm, const char* source) { - bool returnValue; - return returnValue; -} - -bool pkpy_exec_2(pkpy_vm* vm, const char* source, const char* filename, int mode, const char* module) { - bool returnValue; - return returnValue; -} - -void pkpy_set_main_argv(pkpy_vm* vm, int argc, char** argv){ - -} - -bool pkpy_dup(pkpy_vm* vm, int i) { - bool returnValue; - return returnValue; -} - -bool pkpy_pop(pkpy_vm* vm, int n) { - bool returnValue; - return returnValue; -} - -bool pkpy_pop_top(pkpy_vm* vm) { - bool returnValue; - return returnValue; -} - -bool pkpy_dup_top(pkpy_vm* vm) { - bool returnValue; - return returnValue; -} - -bool pkpy_rot_two(pkpy_vm* vm) { - bool returnValue; - return returnValue; -} - -int pkpy_stack_size(pkpy_vm* vm) { - int returnValue; - return returnValue; -} - -bool pkpy_push_int(pkpy_vm* vm, int val) { - bool returnValue; - return returnValue; -} - -bool pkpy_is_int(pkpy_vm* vm, int i) { - bool returnValue; - return returnValue; -} - -bool pkpy_to_int(pkpy_vm* vm, int i, int* out) { - bool returnValue; - return returnValue; -} - -bool pkpy_push_float(pkpy_vm* vm, double val) { - bool returnValue; - return returnValue; -} - -bool pkpy_is_float(pkpy_vm* vm, int i) { - bool returnValue; - return returnValue; -} - -bool pkpy_to_float(pkpy_vm* vm, int i, double* out) { - bool returnValue; - return returnValue; -} - -bool pkpy_push_bool(pkpy_vm* vm, bool val) { - bool returnValue; - return returnValue; -} - -bool pkpy_is_bool(pkpy_vm* vm, int i) { - bool returnValue; - return returnValue; -} - -bool pkpy_to_bool(pkpy_vm* vm, int i, bool* out) { - bool returnValue; - return returnValue; -} - -bool pkpy_push_string(pkpy_vm* vm, pkpy_CString val) { - bool returnValue; - return returnValue; -} - -bool pkpy_is_string(pkpy_vm* vm, int i) { - bool returnValue; - return returnValue; -} - -bool pkpy_to_string(pkpy_vm* vm, int i, pkpy_CString* out) { - bool returnValue; - return returnValue; -} - -bool pkpy_push_voidp(pkpy_vm* vm, void* val) { - bool returnValue; - return returnValue; -} - -bool pkpy_is_voidp(pkpy_vm* vm, int i) { - bool returnValue; - return returnValue; -} - -bool pkpy_to_voidp(pkpy_vm* vm, int i, void** out) { - bool returnValue; - return returnValue; -} - -bool pkpy_push_none(pkpy_vm* vm) { - bool returnValue; - return returnValue; -} - -bool pkpy_is_none(pkpy_vm* vm, int i) { - bool returnValue; - return returnValue; -} - -bool pkpy_push_null(pkpy_vm* vm) { - bool returnValue; - return returnValue; -} - -bool pkpy_push_function(pkpy_vm* vm, const char* sig, pkpy_CFunction val) { - bool returnValue; - return returnValue; -} - -bool pkpy_push_module(pkpy_vm* vm, const char* name) { - bool returnValue; - return returnValue; -} - -bool pkpy_getattr(pkpy_vm* vm, pkpy_CName name) { - bool returnValue; - return returnValue; -} - -bool pkpy_setattr(pkpy_vm* vm, pkpy_CName name) { - bool returnValue; - return returnValue; -} - -bool pkpy_getglobal(pkpy_vm* vm, pkpy_CName name) { - bool returnValue; - return returnValue; -} - -bool pkpy_setglobal(pkpy_vm* vm, pkpy_CName name) { - bool returnValue; - return returnValue; -} - -bool pkpy_eval(pkpy_vm* vm, const char* source) { - bool returnValue; - return returnValue; -} - -bool pkpy_unpack_sequence(pkpy_vm* vm, int size) { - bool returnValue; - return returnValue; -} - -bool pkpy_get_unbound_method(pkpy_vm* vm, pkpy_CName name) { - bool returnValue; - return returnValue; -} - -bool pkpy_py_repr(pkpy_vm* vm) { - bool returnValue; - return returnValue; -} - -bool pkpy_py_str(pkpy_vm* vm) { - bool returnValue; - return returnValue; -} - -bool pkpy_py_import(pkpy_vm* vm, pkpy_CString name) { - bool returnValue; - return returnValue; -} - -bool pkpy_error(pkpy_vm* vm, const char* name, pkpy_CString msg) { - bool returnValue; - return returnValue; -} - -bool pkpy_check_error(pkpy_vm* vm) { - bool returnValue; - return returnValue; -} - -bool pkpy_clear_error(pkpy_vm* vm, char** message) { - bool returnValue; - return returnValue; -} - -bool pkpy_vectorcall(pkpy_vm* vm, int argc) { - bool returnValue; - return returnValue; -} - -void pkpy_free(void* p) { - -} - -pkpy_CName pkpy_name(const char* s) { - pkpy_CName returnValue; - return returnValue; -} - -pkpy_CString pkpy_name_to_string(pkpy_CName name) { - pkpy_CString returnValue; - return returnValue; -} - -void pkpy_set_output_handler(pkpy_vm* vm, pkpy_COutputHandler handler) { - -} - -void pkpy_set_import_handler(pkpy_vm* vm, pkpy_CImportHandler handler) { - -} - -void* pkpy_new_repl(pkpy_vm* vm) { - void* returnValue; - return returnValue; -} - -bool pkpy_repl_input(void* r, const char* line) { - bool returnValue; - return returnValue; -} - -void pkpy_delete_repl(void* repl) { - -}