diff --git a/.github/workflows/numpy.yml b/.github/workflows/numpy.yml deleted file mode 100644 index 659be77f..00000000 --- a/.github/workflows/numpy.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: numpy Build and Test - -on: - push: - paths-ignore: - - 'docs/**' - - 'web/**' - - '**.md' - pull_request: - paths-ignore: - - 'docs/**' - - 'web/**' - - '**.md' - -jobs: - build_linux: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up GCC - run: | - sudo apt-get update - sudo apt-get install -y gcc g++ - - - name: Set up CMake - uses: jwlawson/actions-setup-cmake@v1.10 - - - name: Test - run: | - cd 3rd/numpy/tests - cmake -B build - cmake --build build --config Release --parallel - ./build/numpy_bindings - - build_mac: - runs-on: macos-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Clang - run: | - brew install llvm - echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.zshrc - source ~/.zshrc - - - name: Set up CMake - uses: jwlawson/actions-setup-cmake@v1.10 - - - name: Test - run: | - cd 3rd/numpy/tests - cmake -B build -DENABLE_TEST=ON - cmake --build build --config Release --parallel - ./build/numpy_bindings - - build_windows: - runs-on: windows-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up MSVC - uses: ilammy/msvc-dev-cmd@v1 - - - name: Set up CMake - uses: jwlawson/actions-setup-cmake@v1.10 - - - name: Test - run: | - cd 3rd\numpy\tests - cmake -B build - cmake --build build --config Release --parallel - build\Release\numpy_bindings.exe diff --git a/3rd/numpy/tests/CMakeLists.txt b/3rd/numpy/CMakeLists.txt similarity index 51% rename from 3rd/numpy/tests/CMakeLists.txt rename to 3rd/numpy/CMakeLists.txt index 0f66b7fc..a966c3c1 100644 --- a/3rd/numpy/tests/CMakeLists.txt +++ b/3rd/numpy/CMakeLists.txt @@ -1,17 +1,13 @@ cmake_minimum_required(VERSION 3.10) -project(numpy_bindings) +project(numpy) # Set C++ standard set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -# Add pocketpy as a subdirectory -add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../.." "${CMAKE_CURRENT_BINARY_DIR}/pocketpy") # Include pybind11 and numpy -include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") -include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include") +include_directories("${CMAKE_CURRENT_LIST_DIR}/../../include") +include_directories("${CMAKE_CURRENT_LIST_DIR}/include") # Control xtensor warnings (OFF by default) option(SHOW_XTENSOR_WARNINGS "Show warnings from xtensor" OFF) @@ -32,14 +28,17 @@ if(NOT SHOW_XTENSOR_WARNINGS) endif() # Add numpy source and test files -file (GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../src/numpy.cpp") -file (GLOB TESTS "${CMAKE_CURRENT_SOURCE_DIR}/test_numpy.cpp") +file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp) -# Create numpy executables -add_executable(numpy_bindings ${TESTS} ${SOURCES}) +# Create numpy dynamic library +add_library(${PROJECT_NAME} SHARED ${SOURCES}) -# Set VS debugger working directory (if relevant) -set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY CMAKE_CURRENT_LIST_DIR) +# Define PY_DYNAMIC_MODULE for numpy +target_compile_definitions(${PROJECT_NAME} PRIVATE PY_DYNAMIC_MODULE) # Link numpy with pocketpy -target_link_libraries(${PROJECT_NAME} PRIVATE pocketpy) \ No newline at end of file +target_link_libraries( + ${PROJECT_NAME} + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/../..//build/Release/pocketpy.lib +) diff --git a/3rd/numpy/README.md b/3rd/numpy/README.md index e869995f..4cd0b2ed 100644 --- a/3rd/numpy/README.md +++ b/3rd/numpy/README.md @@ -1,49 +1,6 @@ -# numpy +# How to build -### How to run **numpy** module programs with **gsoc-2024-dev** [pybind11](https://github.com/pocketpy/gsoc-2024-dev/tree/main/pybind11) - -1. Prepare the python code file with the numpy operations you want to run. \ -\ - For example : let's try out numpy [arange](https://numpy.org/doc/stable/reference/generated/numpy.arange.html) function in `test_numpy.py` -```py - import numpy_bindings as np - - def test_arange(n): - a = np.arange(n) - print(a.sum()) - - test_arange(100) - ``` - -2. Read the script and execute it in `test_numpy.cpp`. -```cpp - #include - #include - #include - #include - - namespace py = pybind11; - using namespace pybind11; - - int main() { - py::scoped_interpreter guard{}; - std::ifstream file("test_numpy.py"); - std::stringstream buffer; - buffer << file.rdbuf(); - std::string script = buffer.str(); - py::exec(script); - - return 0; - } ``` - -3. Build the project at root to generate the executable at `build/gsoc2024`. -```sh - cmake -B build - cmake --build build -``` -4. Now run the executable to get the output. -```sh - |base| gsoc-2024-dev ±|main ✗|→ build/gsoc2024 - 4950 +cmake -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release ``` diff --git a/3rd/numpy/src/numpy.cpp b/3rd/numpy/src/numpy.cpp index bc15429e..0271b9f9 100644 --- a/3rd/numpy/src/numpy.cpp +++ b/3rd/numpy/src/numpy.cpp @@ -2869,7 +2869,7 @@ void array_creation_registry(py::module_& m) { } -PYBIND11_EMBEDDED_MODULE(numpy_bindings, m) { +PYBIND11_MODULE(numpy, m) { m.doc() = "Python bindings for pkpy::numpy::ndarray using pybind11"; m.attr("bool_") = "bool"; diff --git a/3rd/numpy/tests/test_numpy.py b/3rd/numpy/tests/test_numpy.py index e361d78b..6377ae63 100644 --- a/3rd/numpy/tests/test_numpy.py +++ b/3rd/numpy/tests/test_numpy.py @@ -1,12 +1,10 @@ -import sys import math +from typing import TYPE_CHECKING -is_pkpy = not hasattr(sys, 'getrefcount') - -if is_pkpy: - import numpy_bindings as np -else: +if TYPE_CHECKING: import numpy as np +else: + np = __import__('E:/pocketpy/3rd/numpy/build/Release/numpy.dll') def assert_equal(a, b): assert (a == b).all() @@ -888,3 +886,5 @@ assert_equal(arr1[-2:3:1], np.array([[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]], [[11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]])) + +print("ALL TESTS PASSED") \ No newline at end of file diff --git a/include/pocketpy/export.h b/include/pocketpy/export.h index d2a254fb..b7baee80 100644 --- a/include/pocketpy/export.h +++ b/include/pocketpy/export.h @@ -2,12 +2,17 @@ // clang-format off -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) - //define something for Windows (32-bit and 64-bit, this part is common) +#if defined(_WIN32) || defined(_WIN64) + #ifdef PY_DYNAMIC_MODULE + #define PK_API __declspec(dllimport) + #else + #define PK_API __declspec(dllexport) + #endif #define PK_EXPORT __declspec(dllexport) #define PY_SYS_PLATFORM 0 #define PY_SYS_PLATFORM_STRING "win32" #elif __EMSCRIPTEN__ + #define PK_API #define PK_EXPORT #define PY_SYS_PLATFORM 1 #define PY_SYS_PLATFORM_STRING "emscripten" @@ -27,17 +32,20 @@ #else # error "Unknown Apple platform" #endif + #define PK_API __attribute__((visibility("default"))) #define PK_EXPORT __attribute__((visibility("default"))) #elif __ANDROID__ + #define PK_API __attribute__((visibility("default"))) #define PK_EXPORT __attribute__((visibility("default"))) #define PY_SYS_PLATFORM 4 #define PY_SYS_PLATFORM_STRING "android" #elif __linux__ + #define PK_API __attribute__((visibility("default"))) #define PK_EXPORT __attribute__((visibility("default"))) #define PY_SYS_PLATFORM 5 #define PY_SYS_PLATFORM_STRING "linux" #else - #define PK_EXPORT + #define PK_API #define PY_SYS_PLATFORM 6 #define PY_SYS_PLATFORM_STRING "unknown" #endif diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index e1a3882f..6e89513b 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -14,7 +14,6 @@ // 4. stack balance guanrantee // 5. stack effect of each opcode // 6. py_TypeInfo -// 7. Direct assignment of py_NIL, py_True, py_False, py_None. They are slow. typedef struct VM { Frame* top_frame; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 8d5df06e..5db4762c 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -70,36 +70,27 @@ typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE PY_RETURN; /// + `SINGLE_MODE`: for REPL or jupyter notebook execution. enum py_CompileMode { EXEC_MODE, EVAL_MODE, SINGLE_MODE }; -/// A shorthand for `True`. -PK_EXPORT extern py_GlobalRef py_True; -/// A shorthand for `False`. -PK_EXPORT extern py_GlobalRef py_False; -/// A shorthand for `None`. -PK_EXPORT extern py_GlobalRef py_None; -/// A shorthand for `nil`. `nil` is not a valid python object. -PK_EXPORT extern py_GlobalRef py_NIL; - /************* Global Setup *************/ /// Initialize pocketpy and the default VM. -PK_EXPORT void py_initialize(); +PK_API void py_initialize(); /// Finalize pocketpy and free all VMs. -PK_EXPORT void py_finalize(); +PK_API void py_finalize(); /// Get the current VM index. -PK_EXPORT int py_currentvm(); +PK_API int py_currentvm(); /// Switch to a VM. /// @param index index of the VM ranging from 0 to 16 (exclusive). `0` is the default VM. -PK_EXPORT void py_switchvm(int index); +PK_API void py_switchvm(int index); /// Reset the current VM. -PK_EXPORT void py_resetvm(); +PK_API void py_resetvm(); /// Get the current VM context. This is used for user-defined data. -PK_EXPORT void* py_getvmctx(); +PK_API void* py_getvmctx(); /// Set the current VM context. This is used for user-defined data. -PK_EXPORT void py_setvmctx(void* ctx); +PK_API void py_setvmctx(void* ctx); /// Set `sys.argv`. Used for storing command-line arguments. -PK_EXPORT void py_sys_setargv(int argc, char** argv); +PK_API void py_sys_setargv(int argc, char** argv); /// Setup the callbacks for the current VM. -PK_EXPORT py_Callbacks* py_callbacks(); +PK_API py_Callbacks* py_callbacks(); /// Run a source string. /// @param source source string. @@ -107,13 +98,13 @@ PK_EXPORT py_Callbacks* py_callbacks(); /// @param mode compile mode. Use `EXEC_MODE` for statements `EVAL_MODE` for expressions. /// @param module target module. Use NULL for the main module. /// @return `true` if the execution is successful or `false` if an exception is raised. -PK_EXPORT bool py_exec(const char* source, +PK_API bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) PY_RAISE PY_RETURN; /// Evaluate a source string. Equivalent to `py_exec(source, "", EVAL_MODE, module)`. -PK_EXPORT bool py_eval(const char* source, py_Ref module) PY_RAISE PY_RETURN; +PK_API bool py_eval(const char* source, py_Ref module) PY_RAISE PY_RETURN; /// Run a source string with smart interpretation. /// Example: @@ -121,87 +112,96 @@ PK_EXPORT bool py_eval(const char* source, py_Ref module) PY_RAISE PY_RETURN; /// `py_newint(py_r1(), 123);` /// `py_smartexec("print(_0, _1)", NULL, py_r0(), py_r1());` /// `// "abc 123" will be printed`. -PK_EXPORT bool py_smartexec(const char* source, py_Ref module, ...) PY_RAISE PY_RETURN; +PK_API bool py_smartexec(const char* source, py_Ref module, ...) PY_RAISE PY_RETURN; /// Evaluate a source string with smart interpretation. /// Example: /// `py_newstr(py_r0(), "abc");` /// `py_smarteval("len(_)", NULL, py_r0());` /// `int res = py_toint(py_retval());` /// `// res will be 3`. -PK_EXPORT bool py_smarteval(const char* source, py_Ref module, ...) PY_RAISE PY_RETURN; +PK_API bool py_smarteval(const char* source, py_Ref module, ...) PY_RAISE PY_RETURN; /// Compile a source string into a code object. /// Use python's `exec()` or `eval()` to execute it. -PK_EXPORT bool py_compile(const char* source, +PK_API bool py_compile(const char* source, const char* filename, enum py_CompileMode mode, bool is_dynamic) PY_RAISE PY_RETURN; /// Python equivalent to `globals()`. -PK_EXPORT void py_newglobals(py_OutRef); +PK_API void py_newglobals(py_OutRef); /// Python equivalent to `locals()`. /// @return a temporary object, which expires on the associated function return. -PK_EXPORT void py_newlocals(py_OutRef); +PK_API void py_newlocals(py_OutRef); /************* Values Creation *************/ +/// A shorthand for `True`. +PK_API py_GlobalRef py_True(); +/// A shorthand for `False`. +PK_API py_GlobalRef py_False(); +/// A shorthand for `None`. +PK_API py_GlobalRef py_None(); +/// A shorthand for `nil`. `nil` is not a valid python object. +PK_API py_GlobalRef py_NIL(); + /// Create an `int` object. -PK_EXPORT void py_newint(py_OutRef, py_i64); +PK_API void py_newint(py_OutRef, py_i64); /// Create a `float` object. -PK_EXPORT void py_newfloat(py_OutRef, py_f64); +PK_API void py_newfloat(py_OutRef, py_f64); /// Create a `bool` object. -PK_EXPORT void py_newbool(py_OutRef, bool); +PK_API void py_newbool(py_OutRef, bool); /// Create a `str` object from a null-terminated string (utf-8). -PK_EXPORT void py_newstr(py_OutRef, const char*); +PK_API void py_newstr(py_OutRef, const char*); /// Create a `str` object with `n` UNINITIALIZED bytes plus `'\0'`. -PK_EXPORT char* py_newstrn(py_OutRef, int); +PK_API char* py_newstrn(py_OutRef, int); /// Create a `str` object from a `c11_sv`. -PK_EXPORT void py_newstrv(py_OutRef, c11_sv); +PK_API void py_newstrv(py_OutRef, c11_sv); /// Create a `bytes` object with `n` UNINITIALIZED bytes. -PK_EXPORT unsigned char* py_newbytes(py_OutRef, int n); +PK_API unsigned char* py_newbytes(py_OutRef, int n); /// Create a `None` object. -PK_EXPORT void py_newnone(py_OutRef); +PK_API void py_newnone(py_OutRef); /// Create a `NotImplemented` object. -PK_EXPORT void py_newnotimplemented(py_OutRef); +PK_API void py_newnotimplemented(py_OutRef); /// Create a `...` object. -PK_EXPORT void py_newellipsis(py_OutRef); +PK_API void py_newellipsis(py_OutRef); /// Create a `nil` object. `nil` is an invalid representation of an object. /// Don't use it unless you know what you are doing. -PK_EXPORT void py_newnil(py_OutRef); +PK_API void py_newnil(py_OutRef); /// Create a `tuple` with `n` UNINITIALIZED elements. /// You should initialize all elements before using it. -PK_EXPORT void py_newtuple(py_OutRef, int n); +PK_API void py_newtuple(py_OutRef, int n); /// Create an empty `list`. -PK_EXPORT void py_newlist(py_OutRef); +PK_API void py_newlist(py_OutRef); /// Create a `list` with `n` UNINITIALIZED elements. /// You should initialize all elements before using it. -PK_EXPORT void py_newlistn(py_OutRef, int n); +PK_API void py_newlistn(py_OutRef, int n); /// Create an empty `dict`. -PK_EXPORT void py_newdict(py_OutRef); +PK_API void py_newdict(py_OutRef); /// Create an UNINITIALIZED `slice` object. /// You should use `py_setslot()` to set `start`, `stop`, and `step`. -PK_EXPORT void py_newslice(py_OutRef); +PK_API void py_newslice(py_OutRef); /// Create a `nativefunc` object. -PK_EXPORT void py_newnativefunc(py_OutRef, py_CFunction); +PK_API void py_newnativefunc(py_OutRef, py_CFunction); /// Create a `function` object. -PK_EXPORT py_Name py_newfunction(py_OutRef out, +PK_API py_Name py_newfunction(py_OutRef out, const char* sig, py_CFunction f, const char* docstring, int slots); /// Create a `boundmethod` object. -PK_EXPORT void py_newboundmethod(py_OutRef out, py_Ref self, py_Ref func); +PK_API void py_newboundmethod(py_OutRef out, py_Ref self, py_Ref func); /************* Name Convertions *************/ /// Convert a null-terminated string to a name. -PK_EXPORT py_Name py_name(const char*); +PK_API py_Name py_name(const char*); /// Convert a name to a null-terminated string. -PK_EXPORT const char* py_name2str(py_Name); +PK_API const char* py_name2str(py_Name); /// Convert a `c11_sv` to a name. -PK_EXPORT py_Name py_namev(c11_sv); +PK_API py_Name py_namev(c11_sv); /// Convert a name to a `c11_sv`. -PK_EXPORT c11_sv py_name2sv(py_Name); +PK_API c11_sv py_name2sv(py_Name); #define py_ismagicname(name) (name <= __missing__) @@ -212,7 +212,7 @@ PK_EXPORT c11_sv py_name2sv(py_Name); /// @param base base type. /// @param module module where the type is defined. Use `NULL` for built-in types. /// @param dtor destructor function. Use `NULL` if not needed. -PK_EXPORT py_Type py_newtype(const char* name, +PK_API py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, py_Dtor dtor); @@ -223,36 +223,36 @@ PK_EXPORT py_Type py_newtype(const char* name, /// @param slots number of slots. Use `-1` to create a `__dict__`. /// @param udsize size of your userdata. /// @return pointer to the userdata. -PK_EXPORT void* py_newobject(py_OutRef out, py_Type type, int slots, int udsize); +PK_API void* py_newobject(py_OutRef out, py_Type type, int slots, int udsize); /************* Type Cast *************/ /// Convert an `int` object in python to `int64_t`. -PK_EXPORT py_i64 py_toint(py_Ref); +PK_API py_i64 py_toint(py_Ref); /// Convert a `float` object in python to `double`. -PK_EXPORT py_f64 py_tofloat(py_Ref); +PK_API py_f64 py_tofloat(py_Ref); /// Cast a `int` or `float` object in python to `double`. /// If successful, return true and set the value to `out`. /// Otherwise, return false and raise `TypeError`. -PK_EXPORT bool py_castfloat(py_Ref, py_f64* out) PY_RAISE; +PK_API bool py_castfloat(py_Ref, py_f64* out) PY_RAISE; /// 32-bit version of `py_castfloat`. -PK_EXPORT bool py_castfloat32(py_Ref, float* out) PY_RAISE; +PK_API bool py_castfloat32(py_Ref, float* out) PY_RAISE; /// Cast a `int` object in python to `int64_t`. -PK_EXPORT bool py_castint(py_Ref, py_i64* out) PY_RAISE; +PK_API bool py_castint(py_Ref, py_i64* out) PY_RAISE; /// Convert a `bool` object in python to `bool`. -PK_EXPORT bool py_tobool(py_Ref); +PK_API bool py_tobool(py_Ref); /// Convert a `type` object in python to `py_Type`. -PK_EXPORT py_Type py_totype(py_Ref); +PK_API py_Type py_totype(py_Ref); /// Convert a `str` object in python to null-terminated string. -PK_EXPORT const char* py_tostr(py_Ref); +PK_API const char* py_tostr(py_Ref); /// Convert a `str` object in python to char array. -PK_EXPORT const char* py_tostrn(py_Ref, int* size); +PK_API const char* py_tostrn(py_Ref, int* size); /// Convert a `str` object in python to `c11_sv`. -PK_EXPORT c11_sv py_tosv(py_Ref); +PK_API c11_sv py_tosv(py_Ref); /// Convert a `bytes` object in python to char array. -PK_EXPORT unsigned char* py_tobytes(py_Ref, int* size); +PK_API unsigned char* py_tobytes(py_Ref, int* size); /// Convert a user-defined object to its userdata. -PK_EXPORT void* py_touserdata(py_Ref); +PK_API void* py_touserdata(py_Ref); #define py_isint(self) py_istype(self, tp_int) #define py_isfloat(self) py_istype(self, tp_float) @@ -266,37 +266,37 @@ PK_EXPORT void* py_touserdata(py_Ref); #define py_isnone(self) py_istype(self, tp_NoneType) /// Get the type of the object. -PK_EXPORT py_Type py_typeof(py_Ref self); +PK_API py_Type py_typeof(py_Ref self); /// Get type by module and name. e.g. `py_gettype("time", py_name("struct_time"))`. /// Return `0` if not found. -PK_EXPORT py_Type py_gettype(const char* module, py_Name name); +PK_API py_Type py_gettype(const char* module, py_Name name); /// Check if the object is exactly the given type. -PK_EXPORT bool py_istype(py_Ref, py_Type); +PK_API bool py_istype(py_Ref, py_Type); /// Check if the object is an instance of the given type. -PK_EXPORT bool py_isinstance(py_Ref obj, py_Type type); +PK_API bool py_isinstance(py_Ref obj, py_Type type); /// Check if the derived type is a subclass of the base type. -PK_EXPORT bool py_issubclass(py_Type derived, py_Type base); +PK_API bool py_issubclass(py_Type derived, py_Type base); /// Get the magic method from the given type only. /// The returned reference is always valid. However, its value may be `nil`. -PK_EXPORT py_GlobalRef py_tpgetmagic(py_Type type, py_Name name); +PK_API py_GlobalRef py_tpgetmagic(py_Type type, py_Name name); /// Search the magic method from the given type to the base type. /// Return `NULL` if not found. -PK_EXPORT py_GlobalRef py_tpfindmagic(py_Type, py_Name name); +PK_API py_GlobalRef py_tpfindmagic(py_Type, py_Name name); /// Search the name from the given type to the base type. /// Return `NULL` if not found. -PK_EXPORT py_ItemRef py_tpfindname(py_Type, py_Name name); +PK_API py_ItemRef py_tpfindname(py_Type, py_Name name); /// Get the type object of the given type. -PK_EXPORT py_GlobalRef py_tpobject(py_Type type); +PK_API py_GlobalRef py_tpobject(py_Type type); /// Get the type name. -PK_EXPORT const char* py_tpname(py_Type type); +PK_API const char* py_tpname(py_Type type); /// Call a type to create a new instance. -PK_EXPORT bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE PY_RETURN; +PK_API bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE PY_RETURN; /// Check if the object is an instance of the given type. /// Raise `TypeError` if the check fails. -PK_EXPORT bool py_checktype(py_Ref self, py_Type type) PY_RAISE; +PK_API bool py_checktype(py_Ref self, py_Type type) PY_RAISE; #define py_checkint(self) py_checktype(self, tp_int) #define py_checkfloat(self) py_checktype(self, tp_float) @@ -307,9 +307,9 @@ PK_EXPORT bool py_checktype(py_Ref self, py_Type type) PY_RAISE; /// Get the i-th register. /// All registers are located in a contiguous memory. -PK_EXPORT py_GlobalRef py_getreg(int i); +PK_API py_GlobalRef py_getreg(int i); /// Set the i-th register. -PK_EXPORT void py_setreg(int i, py_Ref val); +PK_API void py_setreg(int i, py_Ref val); #define py_r0() py_getreg(0) #define py_r1() py_getreg(1) @@ -321,48 +321,48 @@ PK_EXPORT void py_setreg(int i, py_Ref val); #define py_r7() py_getreg(7) /// Get variable in the `__main__` module. -PK_EXPORT py_ItemRef py_getglobal(py_Name name); +PK_API py_ItemRef py_getglobal(py_Name name); /// Set variable in the `__main__` module. -PK_EXPORT void py_setglobal(py_Name name, py_Ref val); +PK_API void py_setglobal(py_Name name, py_Ref val); /// Get variable in the `builtins` module. -PK_EXPORT py_ItemRef py_getbuiltin(py_Name name); +PK_API py_ItemRef py_getbuiltin(py_Name name); /// Equivalent to `*dst = *src`. -PK_EXPORT void py_assign(py_Ref dst, py_Ref src); +PK_API void py_assign(py_Ref dst, py_Ref src); /// Get the last return value. -PK_EXPORT py_GlobalRef py_retval(); +PK_API py_GlobalRef py_retval(); /// Get an item from the object's `__dict__`. /// Return `NULL` if not found. -PK_EXPORT py_ItemRef py_getdict(py_Ref self, py_Name name); +PK_API py_ItemRef py_getdict(py_Ref self, py_Name name); /// Set an item to the object's `__dict__`. -PK_EXPORT void py_setdict(py_Ref self, py_Name name, py_Ref val); +PK_API void py_setdict(py_Ref self, py_Name name, py_Ref val); /// Delete an item from the object's `__dict__`. /// Return `true` if the deletion is successful. -PK_EXPORT bool py_deldict(py_Ref self, py_Name name); +PK_API bool py_deldict(py_Ref self, py_Name name); /// Prepare an insertion to the object's `__dict__`. -PK_EXPORT py_ItemRef py_emplacedict(py_Ref self, py_Name name); +PK_API py_ItemRef py_emplacedict(py_Ref self, py_Name name); /// Apply a function to all items in the object's `__dict__`. /// Return `true` if the function is successful for all items. /// NOTE: Be careful if `f` modifies the object's `__dict__`. -PK_EXPORT bool +PK_API bool py_applydict(py_Ref self, bool (*f)(py_Name name, py_Ref val, void* ctx), void* ctx) PY_RAISE; /// Get the i-th slot of the object. /// The object must have slots and `i` must be in valid range. -PK_EXPORT py_ObjectRef py_getslot(py_Ref self, int i); +PK_API py_ObjectRef py_getslot(py_Ref self, int i); /// Set the i-th slot of the object. -PK_EXPORT void py_setslot(py_Ref self, int i, py_Ref val); +PK_API void py_setslot(py_Ref self, int i, py_Ref val); /************* Inspection *************/ /// Get the current `function` object on the stack. /// Return `NULL` if not available. /// NOTE: This function should be placed at the beginning of your decl-based bindings. -PK_EXPORT py_StackRef py_inspect_currentfunction(); +PK_API py_StackRef py_inspect_currentfunction(); /// Get the current `module` object where the code is executed. /// Return `NULL` if not available. -PK_EXPORT py_GlobalRef py_inspect_currentmodule(); +PK_API py_GlobalRef py_inspect_currentmodule(); /************* Bindings *************/ @@ -370,23 +370,23 @@ PK_EXPORT py_GlobalRef py_inspect_currentmodule(); /// @param obj the target object. /// @param sig signature of the function. e.g. `add(x, y)`. /// @param f function to bind. -PK_EXPORT void py_bind(py_Ref obj, const char* sig, py_CFunction f); +PK_API void py_bind(py_Ref obj, const char* sig, py_CFunction f); /// Bind a method to type via "argc-based" style. /// @param type the target type. /// @param name name of the method. /// @param f function to bind. -PK_EXPORT void py_bindmethod(py_Type type, const char* name, py_CFunction f); +PK_API void py_bindmethod(py_Type type, const char* name, py_CFunction f); /// Bind a function to the object via "argc-based" style. /// @param obj the target object. /// @param name name of the function. /// @param f function to bind. -PK_EXPORT void py_bindfunc(py_Ref obj, const char* name, py_CFunction f); +PK_API void py_bindfunc(py_Ref obj, const char* name, py_CFunction f); /// Bind a property to type. /// @param type the target type. /// @param name name of the property. /// @param getter getter function. /// @param setter setter function. Use `NULL` if not needed. -PK_EXPORT void +PK_API void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter); #define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpgetmagic((type), __magic__), (f)) @@ -403,22 +403,22 @@ PK_EXPORT void /************* Python Equivalents *************/ /// Python equivalent to `getattr(self, name)`. -PK_EXPORT bool py_getattr(py_Ref self, py_Name name) PY_RAISE PY_RETURN; +PK_API bool py_getattr(py_Ref self, py_Name name) PY_RAISE PY_RETURN; /// Python equivalent to `setattr(self, name, val)`. -PK_EXPORT bool py_setattr(py_Ref self, py_Name name, py_Ref val) PY_RAISE; +PK_API bool py_setattr(py_Ref self, py_Name name, py_Ref val) PY_RAISE; /// Python equivalent to `delattr(self, name)`. -PK_EXPORT bool py_delattr(py_Ref self, py_Name name) PY_RAISE; +PK_API bool py_delattr(py_Ref self, py_Name name) PY_RAISE; /// Python equivalent to `self[key]`. -PK_EXPORT bool py_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN; +PK_API bool py_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN; /// Python equivalent to `self[key] = val`. -PK_EXPORT bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE; +PK_API bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE; /// Python equivalent to `del self[key]`. -PK_EXPORT bool py_delitem(py_Ref self, py_Ref key) PY_RAISE; +PK_API bool py_delitem(py_Ref self, py_Ref key) PY_RAISE; /// Perform a binary operation. /// The result will be set to `py_retval()`. /// The stack remains unchanged after the operation. -PK_EXPORT bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE PY_RETURN; +PK_API bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE PY_RETURN; #define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__) #define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__) @@ -439,69 +439,69 @@ PK_EXPORT bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_R /// Get the i-th object from the top of the stack. /// `i` should be negative, e.g. (-1) means TOS. -PK_EXPORT py_StackRef py_peek(int i); +PK_API py_StackRef py_peek(int i); /// Push the object to the stack. -PK_EXPORT void py_push(py_Ref src); +PK_API void py_push(py_Ref src); /// Push a `nil` object to the stack. -PK_EXPORT void py_pushnil(); +PK_API void py_pushnil(); /// Push a `None` object to the stack. -PK_EXPORT void py_pushnone(); +PK_API void py_pushnone(); /// Push a `py_Name` to the stack. This is used for keyword arguments. -PK_EXPORT void py_pushname(py_Name name); +PK_API void py_pushname(py_Name name); /// Pop an object from the stack. -PK_EXPORT void py_pop(); +PK_API void py_pop(); /// Shrink the stack by n. -PK_EXPORT void py_shrink(int n); +PK_API void py_shrink(int n); /// Get a temporary variable from the stack. -PK_EXPORT py_StackRef py_pushtmp(); +PK_API py_StackRef py_pushtmp(); /// Get the unbound method of the object. /// Assume the object is located at the top of the stack. /// If return true: `[self] -> [unbound, self]`. /// If return false: `[self] -> [self]` (no change). -PK_EXPORT bool py_pushmethod(py_Name name); +PK_API bool py_pushmethod(py_Name name); /// Call a callable object. /// Assume `argc + kwargc` arguments are already pushed to the stack. /// The result will be set to `py_retval()`. /// The stack size will be reduced by `argc + kwargc`. -PK_EXPORT bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE PY_RETURN; +PK_API bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE PY_RETURN; /// Evaluate an expression and push the result to the stack. /// This function is used for testing. -PK_EXPORT bool py_pusheval(const char* expr, py_GlobalRef module) PY_RAISE; +PK_API bool py_pusheval(const char* expr, py_GlobalRef module) PY_RAISE; /************* Modules *************/ /// Create a new module. -PK_EXPORT py_GlobalRef py_newmodule(const char* path); +PK_API py_GlobalRef py_newmodule(const char* path); /// Get a module by path. -PK_EXPORT py_GlobalRef py_getmodule(const char* path); +PK_API py_GlobalRef py_getmodule(const char* path); /// Import a module. /// The result will be set to `py_retval()`. /// -1: error, 0: not found, 1: success -PK_EXPORT int py_import(const char* path) PY_RAISE; +PK_API int py_import(const char* path) PY_RAISE; /************* Errors *************/ /// Raise an exception by type and message. Always return false. -PK_EXPORT bool py_exception(py_Type type, const char* fmt, ...) PY_RAISE; +PK_API bool py_exception(py_Type type, const char* fmt, ...) PY_RAISE; /// Raise an expection object. Always return false. -PK_EXPORT bool py_raise(py_Ref) PY_RAISE; +PK_API bool py_raise(py_Ref) PY_RAISE; /// Print the current exception. /// The exception will be set as handled. -PK_EXPORT void py_printexc(); +PK_API void py_printexc(); /// Format the current exception and return a null-terminated string. /// The result should be freed by the caller. /// The exception will be set as handled. -PK_EXPORT char* py_formatexc(); +PK_API char* py_formatexc(); /// Check if an exception is raised. -PK_EXPORT bool py_checkexc(bool ignore_handled); +PK_API bool py_checkexc(bool ignore_handled); /// Check if the exception is an instance of the given type. /// This function is roughly equivalent to python's `except as e:` block. /// If match, the exception will be stored in `py_retval()` as handled. -PK_EXPORT bool py_matchexc(py_Type type) PY_RETURN; +PK_API bool py_matchexc(py_Type type) PY_RETURN; /// Clear the current exception. /// @param p0 the unwinding point. Use `NULL` if not needed. -PK_EXPORT void py_clearexc(py_StackRef p0); +PK_API void py_clearexc(py_StackRef p0); #define NameError(n) py_exception(tp_NameError, "name '%n' is not defined", (n)) #define TypeError(...) py_exception(tp_TypeError, __VA_ARGS__) @@ -516,20 +516,20 @@ PK_EXPORT void py_clearexc(py_StackRef p0); #define UnboundLocalError(n) \ py_exception(tp_UnboundLocalError, "local variable '%n' referenced before assignment", (n)) -PK_EXPORT bool StopIteration() PY_RAISE; -PK_EXPORT bool KeyError(py_Ref key) PY_RAISE; +PK_API bool StopIteration() PY_RAISE; +PK_API bool KeyError(py_Ref key) PY_RAISE; /************* Operators *************/ /// Python equivalent to `bool(val)`. /// 1: true, 0: false, -1: error -PK_EXPORT int py_bool(py_Ref val) PY_RAISE; +PK_API int py_bool(py_Ref val) PY_RAISE; /// Compare two objects. /// 1: lhs == rhs, 0: lhs != rhs, -1: error -PK_EXPORT int py_equal(py_Ref lhs, py_Ref rhs) PY_RAISE; +PK_API int py_equal(py_Ref lhs, py_Ref rhs) PY_RAISE; /// Compare two objects. /// 1: lhs < rhs, 0: lhs >= rhs, -1: error -PK_EXPORT int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE; +PK_API int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE; #define py_eq(lhs, rhs) py_binaryop(lhs, rhs, __eq__, __eq__) #define py_ne(lhs, rhs) py_binaryop(lhs, rhs, __ne__, __ne__) @@ -539,76 +539,76 @@ PK_EXPORT int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE; #define py_ge(lhs, rhs) py_binaryop(lhs, rhs, __ge__, __le__) /// Python equivalent to `callable(val)`. -PK_EXPORT bool py_callable(py_Ref val); +PK_API bool py_callable(py_Ref val); /// Get the hash value of the object. -PK_EXPORT bool py_hash(py_Ref, py_i64* out) PY_RAISE; +PK_API bool py_hash(py_Ref, py_i64* out) PY_RAISE; /// Get the iterator of the object. -PK_EXPORT bool py_iter(py_Ref) PY_RAISE PY_RETURN; +PK_API bool py_iter(py_Ref) PY_RAISE PY_RETURN; /// Get the next element from the iterator. /// 1: success, 0: StopIteration, -1: error -PK_EXPORT int py_next(py_Ref) PY_RAISE PY_RETURN; +PK_API int py_next(py_Ref) PY_RAISE PY_RETURN; /// Python equivalent to `lhs is rhs`. -PK_EXPORT bool py_isidentical(py_Ref, py_Ref); +PK_API bool py_isidentical(py_Ref, py_Ref); /// Call a function. /// It prepares the stack and then performs a `vectorcall(argc, 0, false)`. /// The result will be set to `py_retval()`. /// The stack remains unchanged after the operation. -PK_EXPORT bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE PY_RETURN; +PK_API bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE PY_RETURN; #ifndef NDEBUG /// Call a `py_CFunction` in a safe way. /// This function does extra checks to help you debug `py_CFunction`. -PK_EXPORT bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) PY_RAISE PY_RETURN; +PK_API bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) PY_RAISE PY_RETURN; #else #define py_callcfunc(f, argc, argv) (f((argc), (argv))) #endif /// Python equivalent to `str(val)`. -PK_EXPORT bool py_str(py_Ref val) PY_RAISE PY_RETURN; +PK_API bool py_str(py_Ref val) PY_RAISE PY_RETURN; /// Python equivalent to `repr(val)`. -PK_EXPORT bool py_repr(py_Ref val) PY_RAISE PY_RETURN; +PK_API bool py_repr(py_Ref val) PY_RAISE PY_RETURN; /// Python equivalent to `len(val)`. -PK_EXPORT bool py_len(py_Ref val) PY_RAISE PY_RETURN; +PK_API bool py_len(py_Ref val) PY_RAISE PY_RETURN; /// Python equivalent to `json.dumps(val)`. -PK_EXPORT bool py_json_dumps(py_Ref val) PY_RAISE PY_RETURN; +PK_API bool py_json_dumps(py_Ref val) PY_RAISE PY_RETURN; /// Python equivalent to `json.loads(val)`. -PK_EXPORT bool py_json_loads(const char* source) PY_RAISE PY_RETURN; +PK_API bool py_json_loads(const char* source) PY_RAISE PY_RETURN; /************* Unchecked Functions *************/ -PK_EXPORT py_ObjectRef py_tuple_data(py_Ref self); -PK_EXPORT py_ObjectRef py_tuple_getitem(py_Ref self, int i); -PK_EXPORT void py_tuple_setitem(py_Ref self, int i, py_Ref val); -PK_EXPORT int py_tuple_len(py_Ref self); +PK_API py_ObjectRef py_tuple_data(py_Ref self); +PK_API py_ObjectRef py_tuple_getitem(py_Ref self, int i); +PK_API void py_tuple_setitem(py_Ref self, int i, py_Ref val); +PK_API int py_tuple_len(py_Ref self); -PK_EXPORT py_ItemRef py_list_data(py_Ref self); -PK_EXPORT py_ItemRef py_list_getitem(py_Ref self, int i); -PK_EXPORT void py_list_setitem(py_Ref self, int i, py_Ref val); -PK_EXPORT void py_list_delitem(py_Ref self, int i); -PK_EXPORT int py_list_len(py_Ref self); -PK_EXPORT void py_list_swap(py_Ref self, int i, int j); -PK_EXPORT void py_list_append(py_Ref self, py_Ref val); -PK_EXPORT py_ItemRef py_list_emplace(py_Ref self); -PK_EXPORT void py_list_clear(py_Ref self); -PK_EXPORT void py_list_insert(py_Ref self, int i, py_Ref val); +PK_API py_ItemRef py_list_data(py_Ref self); +PK_API py_ItemRef py_list_getitem(py_Ref self, int i); +PK_API void py_list_setitem(py_Ref self, int i, py_Ref val); +PK_API void py_list_delitem(py_Ref self, int i); +PK_API int py_list_len(py_Ref self); +PK_API void py_list_swap(py_Ref self, int i, int j); +PK_API void py_list_append(py_Ref self, py_Ref val); +PK_API py_ItemRef py_list_emplace(py_Ref self); +PK_API void py_list_clear(py_Ref self); +PK_API void py_list_insert(py_Ref self, int i, py_Ref val); /// -1: error, 0: not found, 1: found -PK_EXPORT int py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN; +PK_API int py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN; /// true: success, false: error -PK_EXPORT bool py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE; +PK_API bool py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE; /// -1: error, 0: not found, 1: found (and deleted) -PK_EXPORT int py_dict_delitem(py_Ref self, py_Ref key) PY_RAISE; +PK_API int py_dict_delitem(py_Ref self, py_Ref key) PY_RAISE; /// -1: error, 0: not found, 1: found -PK_EXPORT int py_dict_getitem_by_str(py_Ref self, const char* key) PY_RAISE PY_RETURN; +PK_API int py_dict_getitem_by_str(py_Ref self, const char* key) PY_RAISE PY_RETURN; /// true: success, false: error -PK_EXPORT bool py_dict_setitem_by_str(py_Ref self, const char* key, py_Ref val) PY_RAISE; +PK_API bool py_dict_setitem_by_str(py_Ref self, const char* key, py_Ref val) PY_RAISE; /// -1: error, 0: not found, 1: found (and deleted) -PK_EXPORT int py_dict_delitem_by_str(py_Ref self, const char* key) PY_RAISE; +PK_API int py_dict_delitem_by_str(py_Ref self, const char* key) PY_RAISE; /// true: success, false: error -PK_EXPORT bool +PK_API bool py_dict_apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx) PY_RAISE; /// noexcept -PK_EXPORT int py_dict_len(py_Ref self); +PK_API int py_dict_len(py_Ref self); /************* linalg module *************/ void py_newvec2(py_OutRef out, c11_vec2); @@ -625,7 +625,7 @@ c11_mat3x3* py_tomat3x3(py_Ref self); /************* Others *************/ /// An utility function to read a line from stdin for REPL. -PK_EXPORT int py_replinput(char* buf, int max_size); +PK_API int py_replinput(char* buf, int max_size); /// Python favored string formatting. /// %d: int diff --git a/include/pybind11/internal/builtins.h b/include/pybind11/internal/builtins.h index 34b8c462..52f65218 100644 --- a/include/pybind11/internal/builtins.h +++ b/include/pybind11/internal/builtins.h @@ -17,7 +17,9 @@ inline object eval(std::string_view code, handle globals = none(), handle locals return object::from_ret(); } else { handle eval = py_getbuiltin(py_name("eval")); - return eval(str(code), globals.is_none() ? dict() : globals, locals.is_none() ? dict() : locals); + return eval(str(code), + globals.is_none() ? dict() : globals, + locals.is_none() ? dict() : locals); } } @@ -75,7 +77,8 @@ inline bool isinstance(handle obj, type type) { return py_isinstance(obj.ptr(), inline bool python_error::match(type type) const { return isinstance(m_exception.ptr(), type); } template -constexpr inline bool is_pyobject_v = std::is_base_of_v> || std::is_same_v; +constexpr inline bool is_pyobject_v = + std::is_base_of_v> || std::is_same_v; template inline type type::of() { @@ -86,8 +89,8 @@ inline type type::of() { return type(T::type_or_check()); } } else { - auto it = m_type_map->find(typeid(T)); - if(it != m_type_map->end()) { + auto it = m_type_map.find(typeid(T)); + if(it != m_type_map.end()) { return type(it->second); } else { // if not found, raise error @@ -104,8 +107,8 @@ inline bool type::isinstance(handle obj) { if constexpr(is_pyobject_v) { // for every python object wrapper type, there must be a `type_or_check` method. // for some types, it returns the underlying type in pkpy, e.g., `int_` -> `tp_int`. - // for other types that may not have a corresponding type in pkpy, it returns a check function. - // e.g., `iterable` -> `[](handle h){ return hasattr(h, "iter"); }`. + // for other types that may not have a corresponding type in pkpy, it returns a check + // function. e.g., `iterable` -> `[](handle h){ return hasattr(h, "iter"); }`. auto type_or_check = T::type_or_check(); if constexpr(is_check_v) { return type_or_check(obj); @@ -117,7 +120,9 @@ inline bool type::isinstance(handle obj) { } } -inline bool issubclass(type derived, type base) { return py_issubclass(derived.index(), base.index()); } +inline bool issubclass(type derived, type base) { + return py_issubclass(derived.index(), base.index()); +} template inline bool isinstance(handle obj) { @@ -131,17 +136,23 @@ template struct type_caster; template -object cast(T&& value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = {}) { +object cast(T&& value, + return_value_policy policy = return_value_policy::automatic_reference, + handle parent = {}) { // decay_t can resolve c-array type, but remove_cv_ref_t can't. using underlying_type = std::decay_t; - if constexpr(std::is_convertible_v && !is_pyobject_v) { + if constexpr(std::is_convertible_v && + !is_pyobject_v) { return object(std::forward(value), object::realloc_t{}); } else if constexpr(is_unique_pointer_v) { using pointer = typename underlying_type::pointer; - return type_caster::cast(value.release(), return_value_policy::take_ownership, parent); + return type_caster::cast(value.release(), + return_value_policy::take_ownership, + parent); } else { - static_assert(!is_multiple_pointer_v, "multiple pointer is not supported."); + static_assert(!is_multiple_pointer_v, + "multiple pointer is not supported."); static_assert(!std::is_void_v>, "void* is not supported, consider using py::capsule."); @@ -163,7 +174,8 @@ object cast(T&& value, return_value_policy policy = return_value_policy::automat template T cast(handle obj, bool convert = true) { using caster_t = type_caster; - constexpr auto is_dangling_v = (std::is_reference_v || is_pointer_v) && caster_t::is_temporary_v; + constexpr auto is_dangling_v = + (std::is_reference_v || is_pointer_v) && caster_t::is_temporary_v; static_assert(!is_dangling_v, "dangling reference or pointer is not allowed."); assert(obj.ptr() != nullptr); diff --git a/include/pybind11/internal/class.h b/include/pybind11/internal/class.h index 5cf5ea52..ed05f988 100644 --- a/include/pybind11/internal/class.h +++ b/include/pybind11/internal/class.h @@ -25,7 +25,7 @@ public: static_cast(data)->~instance(); })), m_scope(scope) { - m_type_map->try_emplace(typeid(T), this->index()); + m_type_map.try_emplace(typeid(T), this->index()); auto& info = type_info::of(); info.name = name; @@ -40,7 +40,8 @@ public: auto info = &type_info::of(); int slot = ((std::is_same_v || ...) ? -1 : 0); - void* data = py_newobject(retv, steal(cls).index(), slot, sizeof(instance)); + void* data = + py_newobject(py_retval(), steal(cls).index(), slot, sizeof(instance)); new (data) instance{instance::Flag::Own, operator new (info->size), info}; return true; }, diff --git a/include/pybind11/internal/error.h b/include/pybind11/internal/error.h index 763d29f0..fbacb453 100644 --- a/include/pybind11/internal/error.h +++ b/include/pybind11/internal/error.h @@ -34,13 +34,9 @@ inline auto raise_call(Args&&... args) { using type = decltype(result); if constexpr(std::is_same_v) { - if(result != false) { - return result; - } + if(result != false) { return result; } } else if constexpr(std::is_same_v) { - if(result != -1) { - return result; - } + if(result != -1) { return result; } } else { static_assert(dependent_false, "invalid return type"); } @@ -84,10 +80,10 @@ class attribute_error : public std::runtime_error { inline object::operator bool () const { return raise_call(m_ptr); } -#define PKBIND_BINARY_OPERATOR(name, lop, rop) \ - inline object operator name (handle lhs, handle rhs) { \ - raise_call(lhs.ptr(), rhs.ptr(), lop, rop); \ - return object(retv, object::realloc_t{}); \ +#define PKBIND_BINARY_OPERATOR(name, lop, rop) \ + inline object operator name (handle lhs, handle rhs) { \ + raise_call(lhs.ptr(), rhs.ptr(), lop, rop); \ + return object::from_ret(); \ } PKBIND_BINARY_OPERATOR(==, __eq__, __eq__) diff --git a/include/pybind11/internal/function.h b/include/pybind11/internal/function.h index 00dffa01..3138fec0 100644 --- a/include/pybind11/internal/function.h +++ b/include/pybind11/internal/function.h @@ -515,20 +515,18 @@ struct template_parser tp_function_record = +[](py_Type& type) { + type = py_newtype("function_record", tp_object, nullptr, [](void* data) { static_cast(data)->~function_record(); }); - } + }; static bool is_function_record(handle h) { if(isinstance(h)) { auto slot = py_getslot(h.ptr(), 0); - if(slot) { return py_typeof(slot) == m_type; } + if(slot) { return py_typeof(slot) == tp_function_record; } } return false; } @@ -539,47 +537,42 @@ class cpp_function : public function { // bind the function std::string sig = name; sig += is_method ? "(self, *args, **kwargs)" : "(*args, **kwargs)"; - auto call = [](int argc, py_Ref stack) { - handle func = py_inspect_currentfunction(); - auto data = py_touserdata(py_getslot(func.ptr(), 0)); - auto& record = *static_cast(data); - try { - record(argc, stack); - return true; - } catch(std::domain_error& e) { - py_exception(tp_ValueError, e.what()); - } catch(std::invalid_argument& e) { - py_exception(tp_ValueError, e.what()); - } catch(std::length_error& e) { - py_exception(tp_ValueError, e.what()); - } catch(std::out_of_range& e) { - py_exception(tp_IndexError, e.what()); - } catch(std::range_error& e) { - py_exception(tp_ValueError, e.what()); - } catch(stop_iteration&) { StopIteration(); } catch(index_error& e) { - py_exception(tp_IndexError, e.what()); - } catch(key_error& e) { py_exception(tp_KeyError, e.what()); } catch(value_error& e) { - py_exception(tp_ValueError, e.what()); - } catch(type_error& e) { - py_exception(tp_TypeError, e.what()); - } catch(import_error& e) { - py_exception(tp_ImportError, e.what()); - } catch(attribute_error& e) { - py_exception(tp_AttributeError, e.what()); - } catch(std::exception& e) { py_exception(tp_RuntimeError, e.what()); } - return false; - }; - py_newfunction(m_ptr, sig.c_str(), call, nullptr, 1); - assert(m_type != 0 && "function record type not registered"); + py_newfunction(m_ptr, sig.c_str(), call, nullptr, 1); auto slot = py_getslot(m_ptr, 0); - void* data = py_newobject(slot, m_type, 0, sizeof(impl::function_record)); + void* data = py_newobject(slot, tp_function_record, 0, sizeof(impl::function_record)); new (data) impl::function_record(std::forward(fn), extras...); } - template - cpp_function(Fn&& fn, const Extras&... extras) : - cpp_function("lambda", std::forward(fn), extras...) {} +private: + static bool call(int argc, py_Ref stack) { + handle func = py_inspect_currentfunction(); + auto data = py_touserdata(py_getslot(func.ptr(), 0)); + auto& record = *static_cast(data); + try { + record(argc, stack); + return true; + } catch(std::domain_error& e) { + py_exception(tp_ValueError, e.what()); + } catch(std::invalid_argument& e) { + py_exception(tp_ValueError, e.what()); + } catch(std::length_error& e) { + py_exception(tp_ValueError, e.what()); + } catch(std::out_of_range& e) { + py_exception(tp_IndexError, e.what()); + } catch(std::range_error& e) { + py_exception(tp_ValueError, e.what()); + } catch(stop_iteration&) { StopIteration(); } catch(index_error& e) { + py_exception(tp_IndexError, e.what()); + } catch(key_error& e) { py_exception(tp_KeyError, e.what()); } catch(value_error& e) { + py_exception(tp_ValueError, e.what()); + } catch(type_error& e) { py_exception(tp_TypeError, e.what()); } catch(import_error& e) { + py_exception(tp_ImportError, e.what()); + } catch(attribute_error& e) { + py_exception(tp_AttributeError, e.what()); + } catch(std::exception& e) { py_exception(tp_RuntimeError, e.what()); } + return false; + }; }; class property : public object { diff --git a/include/pybind11/internal/kernel.h b/include/pybind11/internal/kernel.h index 340da4e0..ddabe830 100644 --- a/include/pybind11/internal/kernel.h +++ b/include/pybind11/internal/kernel.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -17,40 +18,18 @@ namespace pkbind { class handle; -/// hold the object temporarily -template -struct reg_t { - py_Ref value; +struct action { + using function = void (*)(); + inline static std::vector starts; - void operator= (py_Ref ref) & { py_setreg(N, ref); } - - operator py_Ref () & { - assert(value && "register is not initialized"); - return value; + static void initialize() noexcept { + for(auto func: starts) { + func(); + } } - void operator= (handle value) &; - - operator handle () &; - - // pkpy provide user 8 registers. - // 8th register is used for object pool, so N is limited to [0, 7). - static_assert(N >= 0 && N <= 6, "N must be in [0, 7)"); -}; - -struct retv_t { - py_Ref value; - - void operator= (py_Ref ref) & { py_assign(value, ref); } - - operator py_Ref () & { - assert(value && "return value is not initialized"); - return value; - } - - void operator= (handle value) &; - - operator handle () &; + // register a function to be called at the start of the vm. + static void register_start(function func) { starts.push_back(func); } }; /// hold the object long time. @@ -78,6 +57,7 @@ struct object_pool { /// alloc an object from pool, note that the object is uninitialized. static object_ref alloc() { + if(!indices_) { initialize(1024); } auto& indices = *indices_; if(cache != -1) { auto index = cache; @@ -126,25 +106,27 @@ struct object_pool { } }; -struct action { - using function = void (*)(); - inline static std::vector starts; +template +class lazy { +public: + lazy(void (*init)(T&)) : init(init) {} - static void initialize() noexcept { - for(auto func: starts) { - func(); + operator T& () { + if(!initialized) { + if(init) { init(value); } + initialized = true; } + return value; } - // register a function to be called at the start of the vm. - static void register_start(function func) { starts.push_back(func); } + T& operator* () { return static_cast(*this); } + + void reset() { initialized = false; } + +private: + T value; + bool initialized = false; + void (*init)(T&) = nullptr; }; -template -inline reg_t reg; - -inline retv_t retv; - -inline std::unordered_map* m_type_map = nullptr; - } // namespace pkbind diff --git a/include/pybind11/internal/module.h b/include/pybind11/internal/module.h index 2dd1dad4..0072de7f 100644 --- a/include/pybind11/internal/module.h +++ b/include/pybind11/internal/module.h @@ -50,4 +50,14 @@ using module_ = module; } \ static void _pkbind_register_##name(::pkbind::module& variable) +#define PYBIND11_MODULE(name, variable) \ + static void _pkbind_register_##name(::pkbind::module& variable); \ + extern "C" PK_EXPORT bool py_module_initialize() { \ + auto m = ::pkbind::module::create(#name); \ + _pkbind_register_##name(m); \ + py_assign(py_retval(), m.ptr()); \ + return true; \ + } \ + static void _pkbind_register_##name(::pkbind::module& variable) + } // namespace pkbind diff --git a/include/pybind11/internal/object.h b/include/pybind11/internal/object.h index db90fcd9..1d52f03a 100644 --- a/include/pybind11/internal/object.h +++ b/include/pybind11/internal/object.h @@ -261,7 +261,7 @@ public: object(handle h, ref_t) : handle(h) {} - static object from_ret() { return object(retv, realloc_t{}); } + static object from_ret() { return object(py_retval(), realloc_t{}); } operator object_pool::object_ref () const { return {m_ptr, m_index}; } @@ -281,24 +281,6 @@ T borrow(handle h) { return T(h, object::realloc_t{}); } -template -void reg_t::operator= (handle h) & { - py_setreg(N, h.ptr()); -} - -template -reg_t::operator handle () & { - assert(value && "register is not initialized"); - return value; -} - -inline void retv_t::operator= (handle h) & { py_assign(value, h.ptr()); } - -inline retv_t::operator handle () & { - assert(value && "return value is not initialized"); - return value; -} - static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_copyable_v); diff --git a/include/pybind11/internal/types.h b/include/pybind11/internal/types.h index f71821b7..d5354824 100644 --- a/include/pybind11/internal/types.h +++ b/include/pybind11/internal/types.h @@ -29,6 +29,8 @@ public: using object ::object; using object ::operator=; + inline static std::unordered_map m_type_map; + // note: type is global instance, so we use ref_t. explicit type(py_Type type) : object(py_tpobject(type), ref_t{}) {} @@ -49,14 +51,14 @@ class none : public object { PKBIND_TYPE_IMPL(object, none, tp_NoneType); // note: none is global instance, so we use ref_t. - none() : object(py_None, ref_t{}) {} + none() : object(py_None(), ref_t{}) {} }; class bool_ : public object { PKBIND_TYPE_IMPL(object, bool_, tp_bool); // same as none, bool is a singleton. - bool_(bool value) : object(value ? py_True : py_False, ref_t{}) {} + bool_(bool value) : object(value ? py_True() : py_False(), ref_t{}) {} explicit operator bool () { return py_tobool(ptr()); } }; @@ -101,7 +103,7 @@ public: iterator& operator++ () { int result = raise_call(m_ptr); if(result == 1) { - m_value = object(retv, realloc_t{}); + m_value = object::from_ret(); } else if(result == 0) { m_value = object(); } @@ -125,7 +127,7 @@ private: template iterator interface::begin() const { raise_call(ptr()); - return iterator(retv); + return iterator(py_retval()); } template @@ -330,24 +332,22 @@ class kwargs : public dict { // TODO: class capsule : public object { + PKBIND_TYPE_IMPL(object, capsule, *tp_capsule); + struct capsule_impl { void* data; void (*destructor)(void*); }; - inline static py_Type m_type = 0; - - PKBIND_TYPE_IMPL(object, capsule, m_type); - - static void register_() { - m_type = py_newtype("capsule", tp_object, nullptr, [](void* data) { + inline static lazy tp_capsule = +[](py_Type& type) { + type = py_newtype("capsule", tp_object, nullptr, [](void* data) { auto impl = static_cast(data); if(impl->data && impl->destructor) { impl->destructor(impl->data); } }); - } + }; capsule(void* data, void (*destructor)(void*) = nullptr) : object(alloc_t{}) { - void* impl = py_newobject(m_ptr, m_type, 0, sizeof(capsule_impl)); + void* impl = py_newobject(m_ptr, tp_capsule, 0, sizeof(capsule_impl)); new (impl) capsule_impl{data, destructor}; } diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 1593c2c7..5244cc6f 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -13,28 +13,6 @@ inline bool initialized = false; /// initialize the vm. inline void initialize(int object_pool_size = 1024) { if(!initialized) { py_initialize(); } - - // initialize all registers. - reg<0>.value = py_getreg(0); - reg<1>.value = py_getreg(1); - reg<2>.value = py_getreg(2); - reg<3>.value = py_getreg(3); - reg<4>.value = py_getreg(4); - reg<5>.value = py_getreg(5); - reg<6>.value = py_getreg(6); - - // initialize ret. - retv.value = py_retval(); - - // initialize object pool. - object_pool::initialize(object_pool_size); - - m_type_map = new std::unordered_map(); - - // register types. - capsule::register_(); - cpp_function::register_(); - action::initialize(); initialized = true; } @@ -42,9 +20,10 @@ inline void initialize(int object_pool_size = 1024) { /// finalize the vm. inline void finalize(bool test = false) { if(!initialized) { return; } - delete m_type_map; - m_type_map = nullptr; object_pool::finalize(); + type::m_type_map.clear(); + capsule::tp_capsule.reset(); + cpp_function::tp_function_record.reset(); if(test) { py_resetvm(); } else { diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index d8bb7481..cb29b1dc 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -56,40 +56,6 @@ constexpr bool is_py_list_like_v> = true; template constexpr bool is_py_list_like_v> = true; -template <> -struct type_caster> { - std::vector data; - - template - static object cast(U&& src, return_value_policy policy, handle parent) { - auto list = pkbind::list(); - for(auto&& item: src) { - list.append(pkbind::cast(bool(item), policy, parent)); - } - return list; - } - - bool load(handle src, bool convert) { - if(!isinstance(src)) { return false; } - - auto list = src.cast(); - data.clear(); - data.reserve(list.size()); - - for(auto item: list) { - type_caster caster; - if(!caster.load(item, convert)) { return false; } - data.push_back(caster.value()); - } - - return true; - } - - std::vector& value() { return data; } - - constexpr inline static bool is_temporary_v = true; -}; - template struct type_caster>> { T data; @@ -98,7 +64,11 @@ struct type_caster>> { static object cast(U&& src, return_value_policy policy, handle parent) { auto list = pkbind::list(); for(auto&& item: src) { - list.append(pkbind::cast(std::move(item), policy, parent)); + if constexpr(std::is_same_v>) { + list.append(pkbind::cast(bool(item), policy, parent)); + } else { + list.append(pkbind::cast(std::move(item), policy, parent)); + } } return list; } diff --git a/include/pybind11/tests/module.cpp b/include/pybind11/tests/module.cpp index 30429828..15e559f9 100644 --- a/include/pybind11/tests/module.cpp +++ b/include/pybind11/tests/module.cpp @@ -12,6 +12,17 @@ PYBIND11_EMBEDDED_MODULE(example, m) { }); } +PYBIND11_MODULE(example3, m) { + m.def("add", [](int a, int b) { + return a + b; + }); + + auto math = m.def_submodule("math"); + math.def("sub", [](int a, int b) { + return a - b; + }); +} + namespace { TEST_F(PYBIND11_TEST, module) { @@ -52,4 +63,20 @@ TEST_F(PYBIND11_TEST, raw_module) { EXPECT_EQ(math2.attr("sub")(4, 3).cast(), 1); } +TEST_F(PYBIND11_TEST, dynamic_module) { + py_module_initialize(); + + py::exec("import example3"); + EXPECT_EVAL_EQ("example3.add(1, 2)", 3); + + py::exec("from example3 import math"); + EXPECT_EVAL_EQ("math.sub(1, 2)", -1); + + py::exec("from example3.math import sub"); + EXPECT_EVAL_EQ("sub(1, 2)", -1); + + auto math = py::module::import("example3.math"); + EXPECT_EQ(math.attr("sub")(4, 3).cast(), 1); +} + } // namespace diff --git a/scripts/gen_docs.py b/scripts/gen_docs.py index 99815d3a..ca7c0006 100644 --- a/scripts/gen_docs.py +++ b/scripts/gen_docs.py @@ -13,7 +13,7 @@ class Function: is_py_return: bool def signature(self): - tmp = f"PK_EXPORT {self.ret} {self.name}{self.args}" + tmp = f"PK_API {self.ret} {self.name}{self.args}" return tmp + ';' def badges(self): @@ -37,7 +37,7 @@ class Function: with open('include/pocketpy/pocketpy.h') as f: header = f.read() -matches = re.finditer(r"((?:/// [^\n]+[\n])*?)PK_EXPORT\s+(\w+\*?)\s+(\w+)(\(.*?\))\s*(PY_RAISE)?\s*(PY_RETURN)?\s*;", header, re.DOTALL) +matches = re.finditer(r"((?:/// [^\n]+[\n])*?)PK_API\s+(\w+\*?)\s+(\w+)(\(.*?\))\s*(PY_RAISE)?\s*(PY_RETURN)?\s*;", header, re.DOTALL) # ^1 comment ^2 ret ^3 n ^4 args ^5 py_raise? ^6 py_return? functions: list[Function] = [] diff --git a/src/interpreter/dll.c b/src/interpreter/dll.c index c60b8ec2..4c2fc990 100644 --- a/src/interpreter/dll.c +++ b/src/interpreter/dll.c @@ -22,7 +22,10 @@ int load_module_from_dll_desktop_only(const char* path) PY_RAISE PY_RETURN { if(dll == NULL) return 0; py_module_initialize_t f_init = (py_module_initialize_t)dlsym(dll, f_init_name); #endif - if(f_init == NULL) return 0; + if(f_init == NULL) { + RuntimeError("%s() not found in '%s'", f_init_name, path); + return -1; + } bool success = f_init(); if(!success) return -1; return 1; diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index fed282c8..14d539d8 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -52,23 +52,23 @@ static void py_TypeInfo__ctor(py_TypeInfo* self, }; self->module = module; - self->annotations = *py_NIL; + self->annotations = *py_NIL(); } void VM__ctor(VM* self) { self->top_frame = NULL; - ModuleDict__ctor(&self->modules, NULL, *py_NIL); + ModuleDict__ctor(&self->modules, NULL, *py_NIL()); TypeList__ctor(&self->types); - self->builtins = *py_NIL; - self->main = *py_NIL; + self->builtins = *py_NIL(); + self->main = *py_NIL(); self->callbacks.importfile = pk_default_importfile; self->callbacks.print = pk_default_print; - self->last_retval = *py_NIL; - self->curr_exception = *py_NIL; + self->last_retval = *py_NIL(); + self->curr_exception = *py_NIL(); self->is_curr_exc_handled = false; self->ctx = NULL; @@ -329,7 +329,7 @@ py_Type pk_newtype(const char* name, if(base_ti && base_ti->is_sealed) { c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name)); } - py_TypeInfo__ctor(ti, py_name(name), index, base, base_ti, module ? *module : *py_NIL); + py_TypeInfo__ctor(ti, py_name(name), index, base, base_ti, module ? *module : *py_NIL()); if(!dtor && base) dtor = base_ti->dtor; ti->dtor = dtor; ti->is_python = is_python; diff --git a/src/modules/array2d.c b/src/modules/array2d.c index cf595440..6502cf99 100644 --- a/src/modules/array2d.c +++ b/src/modules/array2d.c @@ -106,7 +106,7 @@ static bool array2d_get(int argc, py_Ref argv) { PY_CHECK_ARG_TYPE(1, tp_int); PY_CHECK_ARG_TYPE(2, tp_int); if(argc == 3) { - default_ = py_None; + default_ = py_None(); } else if(argc == 4) { default_ = py_arg(3); } else { diff --git a/src/modules/json.c b/src/modules/json.c index 55152435..c3fdab68 100644 --- a/src/modules/json.c +++ b/src/modules/json.c @@ -21,9 +21,9 @@ static bool json_dumps(int argc, py_Ref argv) { void pk__add_module_json() { py_Ref mod = py_newmodule("json"); - py_setdict(mod, py_name("null"), py_None); - py_setdict(mod, py_name("true"), py_True); - py_setdict(mod, py_name("false"), py_False); + py_setdict(mod, py_name("null"), py_None()); + py_setdict(mod, py_name("true"), py_True()); + py_setdict(mod, py_name("false"), py_False()); py_bindfunc(mod, "loads", json_loads); py_bindfunc(mod, "dumps", json_dumps); diff --git a/src/objects/codeobject.c b/src/objects/codeobject.c index 8a39eba9..28842f33 100644 --- a/src/objects/codeobject.c +++ b/src/objects/codeobject.c @@ -162,7 +162,7 @@ void CodeObject__dtor(CodeObject* self) { void Function__ctor(Function* self, FuncDecl_ decl, py_TValue* module) { PK_INCREF(decl); self->decl = decl; - self->module = module ? *module : *py_NIL; + self->module = module ? *module : *py_NIL(); self->clazz = NULL; self->closure = NULL; self->cfunc = NULL; diff --git a/src/public/internal.c b/src/public/internal.c index fe7ab656..64bae2b4 100644 --- a/src/public/internal.c +++ b/src/public/internal.c @@ -11,13 +11,9 @@ VM* pk_current_vm; -py_GlobalRef py_True; -py_GlobalRef py_False; -py_GlobalRef py_None; -py_GlobalRef py_NIL; - static VM pk_default_vm; static VM* pk_all_vm[16]; +static py_TValue _True, _False, _None, _NIL; void py_initialize() { if(pk_current_vm){ @@ -30,18 +26,18 @@ void py_initialize() { pk_current_vm = pk_all_vm[0] = &pk_default_vm; // initialize some convenient references - static py_TValue _True, _False, _None, _NIL; py_newbool(&_True, true); py_newbool(&_False, false); py_newnone(&_None); py_newnil(&_NIL); - py_True = &_True; - py_False = &_False; - py_None = &_None; - py_NIL = &_NIL; VM__ctor(&pk_default_vm); } +py_GlobalRef py_True() { return &_True; } +py_GlobalRef py_False() { return &_False; } +py_GlobalRef py_None() { return &_None; } +py_GlobalRef py_NIL() { return &_NIL; } + void py_finalize() { for(int i = 1; i < 16; i++) { VM* vm = pk_all_vm[i]; @@ -169,7 +165,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) { py_Ref cls_var = py_tpfindmagic(py_totype(self), name); if(cls_var) { self[0] = *cls_var; - self[1] = *py_NIL; + self[1] = *py_NIL(); return true; } return false; @@ -197,7 +193,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) { } case tp_staticmethod: self[0] = *py_getslot(cls_var, 0); - self[1] = *py_NIL; + self[1] = *py_NIL(); break; case tp_classmethod: self[0] = *py_getslot(cls_var, 0); diff --git a/src/public/modules.c b/src/public/modules.c index 6be8c503..aa57ba42 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -676,11 +676,11 @@ py_TValue pk_builtins__register() { // some patches py_bindmagic(tp_NoneType, __repr__, NoneType__repr__); - *py_tpgetmagic(tp_NoneType, __hash__) = *py_None; + *py_tpgetmagic(tp_NoneType, __hash__) = *py_None(); py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__); - *py_tpgetmagic(tp_ellipsis, __hash__) = *py_None; + *py_tpgetmagic(tp_ellipsis, __hash__) = *py_None(); py_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__); - *py_tpgetmagic(tp_NotImplementedType, __hash__) = *py_None; + *py_tpgetmagic(tp_NotImplementedType, __hash__) = *py_None(); return *builtins; } diff --git a/src/public/py_dict.c b/src/public/py_dict.c index 62d7cf12..04619000 100644 --- a/src/public/py_dict.c +++ b/src/public/py_dict.c @@ -389,7 +389,7 @@ static bool dict_update(int argc, py_Ref argv) { static bool dict_get(int argc, py_Ref argv) { Dict* self = py_touserdata(argv); if(argc > 3) return TypeError("get() takes at most 3 arguments (%d given)", argc); - py_Ref default_val = argc == 3 ? py_arg(2) : py_None; + py_Ref default_val = argc == 3 ? py_arg(2) : py_None(); DictEntry* entry; if(!Dict__try_get(self, py_arg(1), &entry)) return false; *py_retval() = entry ? entry->val : *default_val; @@ -399,7 +399,7 @@ static bool dict_get(int argc, py_Ref argv) { static bool dict_pop(int argc, py_Ref argv) { Dict* self = py_touserdata(argv); if(argc < 2 || argc > 3) return TypeError("pop() takes 1 or 2 arguments (%d given)", argc - 1); - py_Ref default_val = argc == 3 ? py_arg(2) : py_None; + py_Ref default_val = argc == 3 ? py_arg(2) : py_None(); int res = Dict__pop(self, py_arg(1)); if(res == -1) return false; if(res == 0) { py_assign(py_retval(), default_val); } @@ -482,7 +482,7 @@ py_Type pk_dict__register() { py_bindmethod(type, "keys", dict_keys); py_bindmethod(type, "values", dict_values); - py_setdict(py_tpobject(type), __hash__, py_None); + py_setdict(py_tpobject(type), __hash__, py_None()); return type; } diff --git a/src/public/py_exception.c b/src/public/py_exception.c index 9985bba0..784085d2 100644 --- a/src/public/py_exception.c +++ b/src/public/py_exception.c @@ -134,8 +134,8 @@ bool py_matchexc(py_Type type) { void py_clearexc(py_StackRef p0) { VM* vm = pk_current_vm; - vm->last_retval = *py_NIL; - vm->curr_exception = *py_NIL; + vm->last_retval = *py_NIL(); + vm->curr_exception = *py_NIL(); vm->is_curr_exc_handled = false; /* Don't clear this, because StopIteration() may corrupt the class defination */ diff --git a/src/public/py_list.c b/src/public/py_list.c index 2dafd0fb..f8489042 100644 --- a/src/public/py_list.c +++ b/src/public/py_list.c @@ -444,6 +444,6 @@ py_Type pk_list__register() { py_bind(py_tpobject(type), "sort(self, key=None, reverse=False)", list_sort); - py_setdict(py_tpobject(type), __hash__, py_None); + py_setdict(py_tpobject(type), __hash__, py_None()); return type; } diff --git a/src/public/py_property.c b/src/public/py_property.c index 0f93f78c..f0e1a151 100644 --- a/src/public/py_property.c +++ b/src/public/py_property.c @@ -8,7 +8,7 @@ static bool property__new__(int argc, py_Ref argv) { py_newobject(py_retval(), tp_property, 2, 0); if(argc == 1 + 1) { py_setslot(py_retval(), 0, py_arg(1)); - py_setslot(py_retval(), 1, py_None); + py_setslot(py_retval(), 1, py_None()); } else if(argc == 1 + 2) { py_setslot(py_retval(), 0, py_arg(1)); py_setslot(py_retval(), 1, py_arg(2)); diff --git a/src/public/py_slice.c b/src/public/py_slice.c index 66c8110b..de96f24e 100644 --- a/src/public/py_slice.c +++ b/src/public/py_slice.c @@ -100,7 +100,7 @@ py_Type pk_slice__register() { py_bindmagic(type, __eq__, slice__eq__); py_bindmagic(type, __ne__, slice__ne__); - py_setdict(py_tpobject(type), __hash__, py_None); + py_setdict(py_tpobject(type), __hash__, py_None()); py_bindproperty(type, "start", slice_start, NULL); py_bindproperty(type, "stop", slice_stop, NULL); diff --git a/src/public/stack_ops.c b/src/public/stack_ops.c index cd656758..ff84bc48 100644 --- a/src/public/stack_ops.c +++ b/src/public/stack_ops.c @@ -30,7 +30,7 @@ void py_setdict(py_Ref self, py_Name name, py_Ref val) { } py_ItemRef py_emplacedict(py_Ref self, py_Name name){ - py_setdict(self, name, py_NIL); + py_setdict(self, name, py_NIL()); return py_getdict(self, name); } diff --git a/src/public/values.c b/src/public/values.c index 84b00015..20baf8d8 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -67,7 +67,7 @@ void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFu if(setter) { py_newnativefunc(py_getslot(&tmp, 1), setter); } else { - py_setslot(&tmp, 1, py_None); + py_setslot(&tmp, 1, py_None()); } py_setdict(py_tpobject(type), py_name(name), &tmp); }