pocketpy
This commit is contained in:
parent
936d8addf9
commit
16733fdb0e
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "dependencies/pocketpy"]
|
||||
path = dependencies/pocketpy
|
||||
url = https://github.com/pocketpy/pocketpy.git
|
||||
0
dependencies/__init__.py
vendored
Normal file
0
dependencies/__init__.py
vendored
Normal file
1
dependencies/pocketpy
vendored
1
dependencies/pocketpy
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 8361c7d4a181bf94931b0f1841032d58cdeee481
|
||||
2
dependencies/pocketpy/.gitattributes
vendored
Normal file
2
dependencies/pocketpy/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
13
dependencies/pocketpy/.github/FUNDING.yml
vendored
Normal file
13
dependencies/pocketpy/.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: blueloveTH
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
29
dependencies/pocketpy/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
dependencies/pocketpy/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: blueloveTH
|
||||
|
||||
---
|
||||
|
||||
Thanks for taking the time to fill out a bug report!
|
||||
Please provide a descriptive title above and fill in the following fields.
|
||||
|
||||
### Bug description
|
||||
A clear and concise description of what the bug is.
|
||||
You can paste sources here that may cause the error.
|
||||
|
||||
### Steps to reproduce
|
||||
- upload the full stacktrace from your own code line to the error line
|
||||
- upload a minimum reproducible example
|
||||
- additional information to help us reproduce the error
|
||||
|
||||
### Environment information
|
||||
You need to provide these strings:
|
||||
- pocketpy's version
|
||||
- platform string (win32/linux/darwin/emscripten/android/ios)
|
||||
- 32-bit or 64-bit
|
||||
|
||||
### Additional context
|
||||
Add any other context about the error.
|
||||
20
dependencies/pocketpy/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
dependencies/pocketpy/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[Feature]"
|
||||
labels: enhancement
|
||||
assignees: blueloveTH
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
157
dependencies/pocketpy/.github/workflows/main.yml
vendored
Normal file
157
dependencies/pocketpy/.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
name: build
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'web/**'
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'web/**'
|
||||
- '**.md'
|
||||
jobs:
|
||||
build_win32_amalgamated:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Compile
|
||||
shell: powershell
|
||||
run: |
|
||||
python amalgamate.py
|
||||
cd amalgamated
|
||||
cl.exe /std:c++17 /EHsc /utf-8 /O2 /I. /DPK_ENABLE_OS=1 main.cpp /link /out:pkpy.exe
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: amalgamated/pkpy.exe
|
||||
build_win32:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- name: Compile
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p output/windows/x86_64
|
||||
python cmake_build.py
|
||||
cp main.exe output/windows/x86_64
|
||||
cp pocketpy.dll output/windows/x86_64
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
- name: Unit Test
|
||||
run: python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
build_linux:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Clang
|
||||
uses: egor-tensin/setup-clang@v1
|
||||
with:
|
||||
version: 15
|
||||
platform: x64
|
||||
- name: Install libc++
|
||||
run: sudo apt-get install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev
|
||||
- name: Unit Test with Coverage
|
||||
run: bash run_tests.sh
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
directory: .coverage
|
||||
if: github.ref == 'refs/heads/main'
|
||||
- name: Compile
|
||||
run: |
|
||||
mkdir -p output/linux/x86_64
|
||||
python cmake_build.py
|
||||
cp main output/linux/x86_64
|
||||
cp libpocketpy.so output/linux/x86_64
|
||||
env:
|
||||
CXX: clang++
|
||||
CC: clang
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
- name: C Binding Test
|
||||
run: bash run_c_binding_test.sh
|
||||
build_linux_x86:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Alpine Linux for aarch64
|
||||
uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: x86
|
||||
packages: gcc g++ make cmake libc-dev linux-headers python3
|
||||
- name: Build and Test
|
||||
run: |
|
||||
uname -m
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
python scripts/run_tests.py benchmark
|
||||
shell: alpine.sh --root {0}
|
||||
build_darwin:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile and Test
|
||||
run: |
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
- run: |
|
||||
python amalgamate.py
|
||||
cd plugins/macos/pocketpy
|
||||
mkdir -p output/macos
|
||||
xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
|
||||
cp -r build/Release/pocketpy.bundle output/macos
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: plugins/macos/pocketpy/output
|
||||
build_android:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r23
|
||||
local-cache: false
|
||||
add-to-path: false
|
||||
- name: Compile Shared Library
|
||||
run: |
|
||||
bash build_android.sh arm64-v8a
|
||||
bash build_android.sh armeabi-v7a
|
||||
bash build_android.sh x86_64
|
||||
|
||||
mkdir -p output/android/arm64-v8a
|
||||
mkdir -p output/android/armeabi-v7a
|
||||
mkdir -p output/android/x86_64
|
||||
|
||||
cp build/android/arm64-v8a/libpocketpy.so output/android/arm64-v8a
|
||||
cp build/android/armeabi-v7a/libpocketpy.so output/android/armeabi-v7a
|
||||
cp build/android/x86_64/libpocketpy.so output/android/x86_64
|
||||
env:
|
||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
build_ios:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile Frameworks
|
||||
run: |
|
||||
git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake
|
||||
bash build_ios.sh
|
||||
mkdir -p output/ios
|
||||
cp -r build/pocketpy.xcframework output/ios/pocketpy.xcframework
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: output
|
||||
41
dependencies/pocketpy/.github/workflows/website.yml
vendored
Normal file
41
dependencies/pocketpy/.github/workflows/website.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
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: |
|
||||
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'
|
||||
30
dependencies/pocketpy/.gitignore
vendored
Normal file
30
dependencies/pocketpy/.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
__pycache__/
|
||||
.vscode
|
||||
.ipynb_checkpoints
|
||||
.DS_Store
|
||||
.coverage
|
||||
.idea
|
||||
|
||||
gmon.out
|
||||
gprof.txt
|
||||
amalgamated
|
||||
web/lib
|
||||
|
||||
*.a
|
||||
*.so
|
||||
*.dll
|
||||
*.dylib
|
||||
|
||||
plugins/unity/
|
||||
plugins/macos/pocketpy/pocketpy.*
|
||||
main.exe
|
||||
main.obj
|
||||
pocketpy.exp
|
||||
pocketpy.lib
|
||||
APPS
|
||||
build
|
||||
|
||||
main
|
||||
pocketpy.dSYM
|
||||
libpocketpy.dylib.dSYM/
|
||||
main.dSYM/
|
||||
18
dependencies/pocketpy/3rd/cjson/CMakeLists.txt
vendored
Normal file
18
dependencies/pocketpy/3rd/cjson/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(cjson)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
include_directories(include)
|
||||
include_directories(../../include)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_library(
|
||||
cjson
|
||||
STATIC
|
||||
src/cJSON.c
|
||||
src/cJSONw.cpp
|
||||
)
|
||||
10
dependencies/pocketpy/3rd/cjson/LICENSE
vendored
Normal file
10
dependencies/pocketpy/3rd/cjson/LICENSE
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Sofware without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
300
dependencies/pocketpy/3rd/cjson/include/cJSON.h
vendored
Normal file
300
dependencies/pocketpy/3rd/cjson/include/cJSON.h
vendored
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 16
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
8
dependencies/pocketpy/3rd/cjson/include/cJSONw.hpp
vendored
Normal file
8
dependencies/pocketpy/3rd/cjson/include/cJSONw.hpp
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
#include "cJSON.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_cjson(VM* vm);
|
||||
|
||||
} // namespace pkpy
|
||||
3119
dependencies/pocketpy/3rd/cjson/src/cJSON.c
vendored
Normal file
3119
dependencies/pocketpy/3rd/cjson/src/cJSON.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
131
dependencies/pocketpy/3rd/cjson/src/cJSONw.cpp
vendored
Normal file
131
dependencies/pocketpy/3rd/cjson/src/cJSONw.cpp
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
#include "cJSONw.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
|
||||
static cJSON* convert_python_object_to_cjson(PyObject* obj, VM* vm);
|
||||
static PyObject* convert_cjson_to_python_object(const cJSON * const item, VM* vm);
|
||||
|
||||
template<typename T>
|
||||
static cJSON* convert_list_to_cjson(const T& list, VM* vm){
|
||||
cJSON *cjson_list = cJSON_CreateArray();
|
||||
for(auto& element : list){
|
||||
cJSON_AddItemToArray(cjson_list, convert_python_object_to_cjson(element, vm));
|
||||
}
|
||||
return cjson_list;
|
||||
}
|
||||
|
||||
static cJSON* covert_dict_to_cjson(const Dict& dict, VM* vm){
|
||||
cJSON *cjson_object = cJSON_CreateObject();
|
||||
dict.apply([&](PyObject* key, PyObject* val){
|
||||
cJSON_AddItemToObject(cjson_object, CAST(Str&, key).c_str(), convert_python_object_to_cjson(val, vm));
|
||||
});
|
||||
return cjson_object;
|
||||
}
|
||||
|
||||
static cJSON* convert_python_object_to_cjson(PyObject* obj, VM* vm){
|
||||
if(obj == vm->None) return cJSON_CreateNull();
|
||||
Type obj_t = vm->_tp(obj);
|
||||
switch(obj_t){
|
||||
case VM::tp_int.index: cJSON_CreateNumber(_CAST(i64, obj));
|
||||
case VM::tp_float.index: cJSON_CreateNumber(_CAST(f64, obj));
|
||||
case VM::tp_bool.index: cJSON_CreateBool(obj == vm->True);
|
||||
case VM::tp_str.index: cJSON_CreateString(_CAST(Str&, obj).c_str());
|
||||
case VM::tp_dict.index: return covert_dict_to_cjson(_CAST(Dict&, obj), vm);
|
||||
case VM::tp_list.index: return convert_list_to_cjson<List>(_CAST(List&, obj), vm);
|
||||
case VM::tp_tuple.index: return convert_list_to_cjson<Tuple>(_CAST(Tuple&, obj), vm);
|
||||
default: break;
|
||||
}
|
||||
vm->TypeError(_S("unrecognized type ", _type_name(vm, obj_t).escape()));
|
||||
PK_UNREACHABLE()
|
||||
}
|
||||
|
||||
|
||||
static PyObject* convert_cjson_to_list(const cJSON * const item, VM* vm){
|
||||
List output;
|
||||
cJSON *element = item->child;
|
||||
while(element != NULL){
|
||||
output.push_back(convert_cjson_to_python_object(element, vm));
|
||||
element = element->next;
|
||||
}
|
||||
return VAR(std::move(output));
|
||||
}
|
||||
|
||||
static PyObject* convert_cjson_to_dict(const cJSON* const item, VM* vm){
|
||||
Dict output(vm);
|
||||
cJSON *child = item->child;
|
||||
while(child != NULL){
|
||||
const char* key = child->string;
|
||||
const cJSON *child_value = cJSON_GetObjectItemCaseSensitive(item, key);
|
||||
output.set(VAR(key), convert_cjson_to_python_object(child_value, vm));
|
||||
child = child->next;
|
||||
}
|
||||
return VAR(std::move(output));
|
||||
}
|
||||
|
||||
static PyObject* convert_cjson_to_python_object(const cJSON * const item, VM* vm)
|
||||
{
|
||||
if (cJSON_IsString(item))
|
||||
{
|
||||
return VAR(Str(item->valuestring));
|
||||
}
|
||||
else if (cJSON_IsNumber(item)){
|
||||
if(item->valuedouble != item->valueint){
|
||||
return VAR(item->valuedouble);
|
||||
}
|
||||
return VAR(item->valueint);
|
||||
}
|
||||
else if (cJSON_IsBool(item)){
|
||||
return item->valueint!=0 ? vm->True : vm->False;
|
||||
}
|
||||
else if (cJSON_IsNull(item)){
|
||||
return vm->None;
|
||||
}
|
||||
else if (cJSON_IsArray(item)){
|
||||
return convert_cjson_to_list(item, vm);
|
||||
}
|
||||
else if (cJSON_IsObject(item)){
|
||||
return convert_cjson_to_dict(item, vm);
|
||||
}
|
||||
return vm->None;
|
||||
}
|
||||
|
||||
void add_module_cjson(VM* vm){
|
||||
PyObject* mod = vm->new_module("cjson");
|
||||
|
||||
PK_LOCAL_STATIC cJSON_Hooks hooks;
|
||||
hooks.malloc_fn = pool64_alloc;
|
||||
hooks.free_fn = pool64_dealloc;
|
||||
cJSON_InitHooks(&hooks);
|
||||
|
||||
vm->bind_func<1>(mod, "loads", [](VM* vm, ArgsView args){
|
||||
std::string_view sv;
|
||||
if(is_type(args[0], vm->tp_bytes)){
|
||||
sv = PK_OBJ_GET(Bytes, args[0]).sv();
|
||||
}else{
|
||||
sv = CAST(Str&, args[0]).sv();
|
||||
}
|
||||
cJSON *json = cJSON_ParseWithLength(sv.data(), sv.size());
|
||||
if(json == NULL){
|
||||
const char* start = cJSON_GetErrorPtr();
|
||||
const char* end = start;
|
||||
while(*end != '\0' && *end != '\n') end++;
|
||||
vm->IOError(_S("cjson: ", std::string_view(start, end-start)));
|
||||
}
|
||||
PyObject* output = convert_cjson_to_python_object(json, vm);
|
||||
cJSON_Delete(json);
|
||||
return output;
|
||||
});
|
||||
|
||||
vm->bind_func<1>(mod, "dumps", [](VM* vm, ArgsView args) {
|
||||
return vm->py_json(args[0]);
|
||||
// cJSON* cjson = convert_python_object_to_cjson(args[0], vm);
|
||||
// char* str = cJSON_Print(cjson);
|
||||
// cJSON_Delete(cjson);
|
||||
// PyObject* ret = VAR((const char*)str);
|
||||
// hooks.free_fn(str);
|
||||
// return ret;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
1122
dependencies/pocketpy/3rd/ios.toolchain.cmake
vendored
Normal file
1122
dependencies/pocketpy/3rd/ios.toolchain.cmake
vendored
Normal file
File diff suppressed because it is too large
Load Diff
15
dependencies/pocketpy/3rd/lua_bridge/include/lua_bridge.hpp
vendored
Normal file
15
dependencies/pocketpy/3rd/lua_bridge/include/lua_bridge.hpp
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy.h"
|
||||
|
||||
extern "C"{
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
void initialize_lua_bridge(VM* vm, lua_State* newL);
|
||||
|
||||
} // namespace pkpy
|
||||
353
dependencies/pocketpy/3rd/lua_bridge/src/lua_bridge.cpp
vendored
Normal file
353
dependencies/pocketpy/3rd/lua_bridge/src/lua_bridge.cpp
vendored
Normal file
@ -0,0 +1,353 @@
|
||||
#include "lua_bridge.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
static lua_State* _L;
|
||||
static void lua_push_from_python(VM*, PyObject*);
|
||||
static PyObject* lua_popx_to_python(VM*);
|
||||
|
||||
template<typename T>
|
||||
static void table_apply(VM* vm, T f){
|
||||
PK_ASSERT(lua_istable(_L, -1));
|
||||
lua_pushnil(_L); // [key]
|
||||
while(lua_next(_L, -2) != 0){ // [key, val]
|
||||
lua_pushvalue(_L, -2); // [key, val, key]
|
||||
PyObject* key = lua_popx_to_python(vm);
|
||||
PyObject* val = lua_popx_to_python(vm);
|
||||
f(key, val); // [key]
|
||||
}
|
||||
lua_pop(_L, 1); // []
|
||||
}
|
||||
|
||||
struct LuaExceptionGuard{
|
||||
int base_size;
|
||||
LuaExceptionGuard(){ base_size = lua_gettop(_L); }
|
||||
~LuaExceptionGuard(){
|
||||
int delta = lua_gettop(_L) - base_size;
|
||||
if(delta > 0) lua_pop(_L, delta);
|
||||
}
|
||||
};
|
||||
|
||||
#define LUA_PROTECTED(__B) { LuaExceptionGuard __guard; __B; }
|
||||
|
||||
struct PyLuaObject{
|
||||
PK_ALWAYS_PASS_BY_POINTER(PyLuaObject)
|
||||
int r;
|
||||
PyLuaObject(){ r = luaL_ref(_L, LUA_REGISTRYINDEX); }
|
||||
~PyLuaObject(){ luaL_unref(_L, LUA_REGISTRYINDEX, r); }
|
||||
};
|
||||
|
||||
struct PyLuaTable: PyLuaObject{
|
||||
PY_CLASS(PyLuaTable, lua, Table)
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
Type t = PK_OBJ_GET(Type, type);
|
||||
PyTypeInfo* ti = &vm->_all_types[t];
|
||||
ti->subclass_enabled = false;
|
||||
ti->m__getattr__ = [](VM* vm, PyObject* obj, StrName name){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
std::string_view name_sv = name.sv();
|
||||
lua_pushlstring(_L, name_sv.data(), name_sv.size());
|
||||
lua_gettable(_L, -2);
|
||||
PyObject* ret = lua_popx_to_python(vm);
|
||||
lua_pop(_L, 1);
|
||||
return ret;
|
||||
)
|
||||
};
|
||||
|
||||
ti->m__setattr__ = [](VM* vm, PyObject* obj, StrName name, PyObject* val){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
std::string_view name_sv = name.sv();
|
||||
lua_pushlstring(_L, name_sv.data(), name_sv.size());
|
||||
lua_push_from_python(vm, val);
|
||||
lua_settable(_L, -3);
|
||||
lua_pop(_L, 1);
|
||||
)
|
||||
};
|
||||
|
||||
ti->m__delattr__ = [](VM* vm, PyObject* obj, StrName name){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
std::string_view name_sv = name.sv();
|
||||
lua_pushlstring(_L, name_sv.data(), name_sv.size());
|
||||
lua_pushnil(_L);
|
||||
lua_settable(_L, -3);
|
||||
lua_pop(_L, 1);
|
||||
)
|
||||
return true;
|
||||
};
|
||||
|
||||
vm->bind_constructor<1>(type, [](VM* vm, ArgsView args){
|
||||
lua_newtable(_L); // push an empty table onto the stack
|
||||
PyObject* obj = vm->heap.gcnew<PyLuaTable>(PK_OBJ_GET(Type, args[0]));
|
||||
return obj;
|
||||
});
|
||||
|
||||
vm->bind__len__(t, [](VM* vm, PyObject* obj){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
i64 len = 0;
|
||||
lua_pushnil(_L);
|
||||
while(lua_next(_L, -2) != 0){ len += 1; lua_pop(_L, 1); }
|
||||
lua_pop(_L, 1);
|
||||
return len;
|
||||
});
|
||||
|
||||
vm->bind__getitem__(t, [](VM* vm, PyObject* obj, PyObject* key){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
lua_push_from_python(vm, key);
|
||||
lua_gettable(_L, -2);
|
||||
PyObject* ret = lua_popx_to_python(vm);
|
||||
lua_pop(_L, 1);
|
||||
return ret;
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind__setitem__(t, [](VM* vm, PyObject* obj, PyObject* key, PyObject* val){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
lua_push_from_python(vm, key);
|
||||
lua_push_from_python(vm, val);
|
||||
lua_settable(_L, -3);
|
||||
lua_pop(_L, 1);
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind__delitem__(t, [](VM* vm, PyObject* obj, PyObject* key){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
lua_push_from_python(vm, key);
|
||||
lua_pushnil(_L);
|
||||
lua_settable(_L, -3);
|
||||
lua_pop(_L, 1);
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind__contains__(t, [](VM* vm, PyObject* obj, PyObject* key){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, obj);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
lua_push_from_python(vm, key);
|
||||
lua_gettable(_L, -2);
|
||||
bool ret = lua_isnil(_L, -1) == 0;
|
||||
lua_pop(_L, 2);
|
||||
return ret ? vm->True : vm->False;
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind(type, "keys(self) -> list", [](VM* vm, ArgsView args){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
List ret;
|
||||
table_apply(vm, [&](PyObject* key, PyObject* val){ ret.push_back(key); });
|
||||
lua_pop(_L, 1);
|
||||
return VAR(std::move(ret));
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind(type, "values(self) -> list", [](VM* vm, ArgsView args){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
List ret;
|
||||
table_apply(vm, [&](PyObject* key, PyObject* val){ ret.push_back(val); });
|
||||
lua_pop(_L, 1);
|
||||
return VAR(std::move(ret));
|
||||
)
|
||||
});
|
||||
|
||||
vm->bind(type, "items(self) -> list[tuple]", [](VM* vm, ArgsView args){
|
||||
const PyLuaTable& self = _CAST(PyLuaTable&, args[0]);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
List ret;
|
||||
table_apply(vm, [&](PyObject* key, PyObject* val){
|
||||
PyObject* item = VAR(Tuple(key, val));
|
||||
ret.push_back(item);
|
||||
});
|
||||
lua_pop(_L, 1);
|
||||
return VAR(std::move(ret));
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
static PyObject* lua_popx_multi_to_python(VM* vm, int count){
|
||||
if(count == 0){
|
||||
return vm->None;
|
||||
}else if(count == 1){
|
||||
return lua_popx_to_python(vm);
|
||||
}else if(count > 1){
|
||||
Tuple ret(count);
|
||||
for(int i=0; i<count; i++){
|
||||
ret[i] = lua_popx_to_python(vm);
|
||||
}
|
||||
return VAR(std::move(ret));
|
||||
}
|
||||
PK_FATAL_ERROR()
|
||||
}
|
||||
|
||||
struct PyLuaFunction: PyLuaObject{
|
||||
PY_CLASS(PyLuaFunction, lua, Function)
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind_notimplemented_constructor<PyLuaFunction>(type);
|
||||
vm->_all_types[PK_OBJ_GET(Type, type)].subclass_enabled = false;
|
||||
|
||||
vm->bind_method<-1>(type, "__call__", [](VM* vm, ArgsView args){
|
||||
if(args.size() < 1) vm->TypeError("__call__ takes at least 1 argument");
|
||||
const PyLuaFunction& self = _CAST(PyLuaFunction&, args[0]);
|
||||
int base_size = lua_gettop(_L);
|
||||
LUA_PROTECTED(
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, self.r);
|
||||
for(int i=1; i<args.size(); i++){
|
||||
lua_push_from_python(vm, args[i]);
|
||||
}
|
||||
if(lua_pcall(_L, args.size()-1, LUA_MULTRET, 0)){
|
||||
const char* error = lua_tostring(_L, -1);
|
||||
lua_pop(_L, 1);
|
||||
vm->RuntimeError(error);
|
||||
}
|
||||
return lua_popx_multi_to_python(vm, lua_gettop(_L) - base_size);
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void lua_push_from_python(VM* vm, PyObject* val){
|
||||
if(val == vm->None){
|
||||
lua_pushnil(_L);
|
||||
return;
|
||||
}
|
||||
Type t = vm->_tp(val);
|
||||
switch(t.index){
|
||||
case VM::tp_bool.index:
|
||||
lua_pushboolean(_L, val == vm->True);
|
||||
return;
|
||||
case VM::tp_int.index:
|
||||
lua_pushinteger(_L, _CAST(i64, val));
|
||||
return;
|
||||
case VM::tp_float.index:
|
||||
lua_pushnumber(_L, _CAST(f64, val));
|
||||
return;
|
||||
case VM::tp_str.index: {
|
||||
std::string_view sv = _CAST(Str, val).sv();
|
||||
lua_pushlstring(_L, sv.data(), sv.size());
|
||||
return;
|
||||
}
|
||||
case VM::tp_tuple.index: {
|
||||
lua_newtable(_L);
|
||||
int i = 1;
|
||||
for(PyObject* obj: PK_OBJ_GET(Tuple, val)){
|
||||
lua_push_from_python(vm, obj);
|
||||
lua_rawseti(_L, -2, i++);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case VM::tp_list.index: {
|
||||
lua_newtable(_L);
|
||||
int i = 1;
|
||||
for(PyObject* obj: PK_OBJ_GET(List, val)){
|
||||
lua_push_from_python(vm, obj);
|
||||
lua_rawseti(_L, -2, i++);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case VM::tp_dict.index: {
|
||||
lua_newtable(_L);
|
||||
PK_OBJ_GET(Dict, val).apply([&](PyObject* key, PyObject* val){
|
||||
lua_push_from_python(vm, key);
|
||||
lua_push_from_python(vm, val);
|
||||
lua_settable(_L, -3);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(is_type(val, PyLuaTable::_type(vm))){
|
||||
const PyLuaTable& table = _CAST(PyLuaTable&, val);
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, table.r);
|
||||
return;
|
||||
}
|
||||
|
||||
if(is_type(val, PyLuaFunction::_type(vm))){
|
||||
const PyLuaFunction& func = _CAST(PyLuaFunction&, val);
|
||||
lua_rawgeti(_L, LUA_REGISTRYINDEX, func.r);
|
||||
return;
|
||||
}
|
||||
vm->RuntimeError(_S("unsupported python type: ", _type_name(vm, t).escape()));
|
||||
}
|
||||
|
||||
PyObject* lua_popx_to_python(VM* vm) {
|
||||
int type = lua_type(_L, -1);
|
||||
switch (type) {
|
||||
case LUA_TNIL: {
|
||||
lua_pop(_L, 1);
|
||||
return vm->None;
|
||||
}
|
||||
case LUA_TBOOLEAN: {
|
||||
bool val = lua_toboolean(_L, -1);
|
||||
lua_pop(_L, 1);
|
||||
return val ? vm->True : vm->False;
|
||||
}
|
||||
case LUA_TNUMBER: {
|
||||
double val = lua_tonumber(_L, -1);
|
||||
lua_pop(_L, 1);
|
||||
return VAR(val);
|
||||
}
|
||||
case LUA_TSTRING: {
|
||||
const char* val = lua_tostring(_L, -1);
|
||||
lua_pop(_L, 1);
|
||||
return VAR(val);
|
||||
}
|
||||
case LUA_TTABLE: {
|
||||
PyObject* obj = vm->heap.gcnew<PyLuaTable>(PyLuaTable::_type(vm));
|
||||
return obj;
|
||||
}
|
||||
case LUA_TFUNCTION: {
|
||||
PyObject* obj = vm->heap.gcnew<PyLuaFunction>(PyLuaFunction::_type(vm));
|
||||
return obj;
|
||||
}
|
||||
default: {
|
||||
const char* type_name = lua_typename(_L, type);
|
||||
lua_pop(_L, 1);
|
||||
vm->RuntimeError(_S("unsupported lua type: '", type_name, "'"));
|
||||
}
|
||||
}
|
||||
PK_UNREACHABLE()
|
||||
}
|
||||
|
||||
void initialize_lua_bridge(VM* vm, lua_State* newL){
|
||||
PyObject* mod = vm->new_module("lua");
|
||||
|
||||
if(_L != nullptr){
|
||||
throw std::runtime_error("lua bridge already initialized");
|
||||
}
|
||||
_L = newL;
|
||||
|
||||
PyLuaTable::register_class(vm, mod);
|
||||
PyLuaFunction::register_class(vm, mod);
|
||||
|
||||
vm->bind(mod, "dostring(__source: str)", [](VM* vm, ArgsView args){
|
||||
const char* source = CAST(CString, args[0]);
|
||||
int base_size = lua_gettop(_L);
|
||||
if (luaL_dostring(_L, source)) {
|
||||
const char* error = lua_tostring(_L, -1);
|
||||
lua_pop(_L, 1); // pop error message from the stack
|
||||
vm->RuntimeError(error);
|
||||
}
|
||||
return lua_popx_multi_to_python(vm, lua_gettop(_L) - base_size);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
93
dependencies/pocketpy/CMakeLists.txt
vendored
Normal file
93
dependencies/pocketpy/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(pocketpy)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /utf-8 /O2")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -frtti -O2")
|
||||
|
||||
# disable -Wshorten-64-to-32 for apple
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-shorten-64-to-32")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
aux_source_directory(src POCKETPY_SRC)
|
||||
|
||||
option(PK_USE_CJSON "" OFF)
|
||||
if(PK_USE_CJSON)
|
||||
add_subdirectory(3rd/cjson)
|
||||
add_definitions(-DPK_USE_CJSON)
|
||||
endif()
|
||||
|
||||
option(PK_ENABLE_OS "" OFF)
|
||||
if(PK_ENABLE_OS)
|
||||
add_definitions(-DPK_ENABLE_OS=1)
|
||||
endif()
|
||||
|
||||
option(PK_NO_EXPORT_C_API "" OFF)
|
||||
if(PK_NO_EXPORT_C_API)
|
||||
add_definitions(-DPK_NO_EXPORT_C_API)
|
||||
endif()
|
||||
|
||||
# PK_IS_MAIN determines whether the project is being used from root
|
||||
# or if it is added as a dependency (through add_subdirectory for example).
|
||||
if ("${CMAKE_SOURCE_DIR}" STREQUAL ".")
|
||||
set(PK_IS_MAIN TRUE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" OFF)
|
||||
else()
|
||||
set(PK_IS_MAIN FALSE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" ON)
|
||||
endif()
|
||||
|
||||
if(PK_BUILD_SHARED_LIB)
|
||||
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
|
||||
elseif(PK_BUILD_STATIC_LIB)
|
||||
add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC})
|
||||
else()
|
||||
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
|
||||
set(PROJECT_EXE_NAME main)
|
||||
add_executable(${PROJECT_EXE_NAME} src2/main.cpp)
|
||||
target_link_libraries(${PROJECT_EXE_NAME} ${PROJECT_NAME})
|
||||
target_link_libraries(${PROJECT_EXE_NAME} ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
if(PK_USE_CJSON)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE $<BUILD_INTERFACE:cjson>)
|
||||
endif()
|
||||
|
||||
option(PK_INSTALL "Generate the install target" OFF)
|
||||
if (PK_INSTALL)
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}_target
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY include
|
||||
DESTINATION include
|
||||
FILES_MATCHING PATTERN "*.h"
|
||||
PATTERN "typings" EXCLUDE
|
||||
)
|
||||
|
||||
# generate config.cmake
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}_target
|
||||
FILE ${PROJECT_NAME}-config.cmake
|
||||
DESTINATION "share/${PROJECT_NAME}"
|
||||
)
|
||||
endif()
|
||||
21
dependencies/pocketpy/LICENSE
vendored
Normal file
21
dependencies/pocketpy/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 blueloveTH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
224
dependencies/pocketpy/README.md
vendored
Normal file
224
dependencies/pocketpy/README.md
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
# pocketpy: python interpreter in 1 file
|
||||
|
||||
<p>
|
||||
<a title="Build" href="https://github.com/pocketpy/pocketpy/actions/workflows" ><img src="https://github.com/pocketpy/pocketpy/actions/workflows/main.yml/badge.svg" /></a>
|
||||
<a href="https://codecov.io/gh/pocketpy/pocketpy" >
|
||||
<img src="https://codecov.io/gh/pocketpy/pocketpy/branch/main/graph/badge.svg?token=TI9KAFL0RG"/>
|
||||
</a>
|
||||
<a href="https://en.wikipedia.org/wiki/C%2B%2B#Standardization">
|
||||
<img alt="C++17" src="https://img.shields.io/badge/C%2B%2B-17-blue.svg"></a>
|
||||
<a href="https://github.com/blueloveth/pocketpy/blob/main/LICENSE">
|
||||
<img alt="GitHub" src="https://img.shields.io/github/license/blueloveth/pocketpy.svg?color=blue"></a>
|
||||
<a href="https://github.com/blueloveth/pocketpy/releases">
|
||||
<img alt="GitHub release" src="https://img.shields.io/github/release/blueloveth/pocketpy.svg"></a>
|
||||
<!-- docs -->
|
||||
<a href="https://pocketpy.dev">
|
||||
<img alt="Website" src="https://img.shields.io/website/https/pocketpy.dev.svg?down_color=red&down_message=offline&up_color=blue&up_message=online"></a>
|
||||
<a title="Discord" href="https://discord.gg/WWaq72GzXv" >
|
||||
<img src="https://img.shields.io/discord/1048978026131640390.svg" /></a>
|
||||
</p>
|
||||
|
||||
pkpy is a lightweight(~15K LOC) Python interpreter for game scripting, built on C++17 with STL.
|
||||
|
||||
It aims to be an alternative to lua for game scripting, with elegant syntax, powerful features and competitive performance.
|
||||
pkpy is extremely easy to embed via a single header file `pocketpy.h`, without external dependencies.
|
||||
|
||||
Please see https://pocketpy.dev for details or try [Live Demo](https://pocketpy.dev/static/web/).
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
pkpy should work on any platform with a C++17 compiler.
|
||||
These platforms are officially tested.
|
||||
|
||||
+ Windows 64-bit
|
||||
+ Linux 64-bit / 32-bit
|
||||
+ macOS 64-bit
|
||||
+ Android 64-bit / 32-bit
|
||||
+ iOS 64-bit
|
||||
+ Emscripten 32-bit
|
||||
+ Raspberry Pi OS 64-bit
|
||||
|
||||
## Quick Start
|
||||
|
||||
You have two options to integrate pkpy into your project.
|
||||
|
||||
#### Use the single header file
|
||||
|
||||
Download the `pocketpy.h` on our [GitHub Release](https://github.com/pocketpy/pocketpy/releases) page.
|
||||
And `#include` it in your project. The header can only be included once.
|
||||
|
||||
#### Use CMake
|
||||
|
||||
Clone the whole repository as a submodule into your project,
|
||||
In your CMakelists.txt, add the following lines:
|
||||
|
||||
```cmake
|
||||
add_subdirectory(pocketpy)
|
||||
target_link_libraries(<your_target> pocketpy)
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
# exceptions must be enabled for emscripten
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fexceptions")
|
||||
endif()
|
||||
```
|
||||
|
||||
See [CMakeLists.txt](https://github.com/pocketpy/pocketpy/blob/main/CMakeLists.txt) for details.
|
||||
|
||||
It is safe to use `main` branch in production if CI badge is green.
|
||||
|
||||
### Compile Flags
|
||||
|
||||
To compile it with your project, these flags must be set:
|
||||
|
||||
+ `--std=c++17` flag must be set
|
||||
+ RTTI must be enabled
|
||||
+ Exception must be enabled
|
||||
+ For MSVC, `/utf-8` flag must be set
|
||||
|
||||
For development build, use this snippet.
|
||||
```bash
|
||||
# prerequisites
|
||||
pip install cmake
|
||||
# build the repo
|
||||
python cmake_build.py
|
||||
# unittest
|
||||
python scripts/run_tests.py
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```cpp
|
||||
#include "pocketpy.h"
|
||||
|
||||
using namespace pkpy;
|
||||
|
||||
int main(){
|
||||
// Create a virtual machine
|
||||
VM* vm = new VM();
|
||||
|
||||
// Hello world!
|
||||
vm->exec("print('Hello world!')");
|
||||
|
||||
// Create a list
|
||||
vm->exec("a = [1, 2, 3]");
|
||||
|
||||
// Eval the sum of the list
|
||||
PyObject* result = vm->eval("sum(a)");
|
||||
std::cout << "Sum of the list: "<< py_cast<int>(vm, result) << std::endl; // 6
|
||||
|
||||
// Bindings
|
||||
vm->bind(vm->_main, "add(a: int, b: int)",
|
||||
[](VM* vm, ArgsView args){
|
||||
int a = py_cast<int>(vm, args[0]);
|
||||
int b = py_cast<int>(vm, args[1]);
|
||||
return py_var(vm, a + b);
|
||||
});
|
||||
|
||||
// Call the function
|
||||
PyObject* f_add = vm->_main->attr("add");
|
||||
result = vm->call(f_add, py_var(vm, 3), py_var(vm, 7));
|
||||
std::cout << "Sum of 2 variables: "<< py_cast<int>(vm, result) << std::endl; // 10
|
||||
|
||||
// Dispose the virtual machine
|
||||
delete vm;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
Check this [Cheatsheet](https://reference.pocketpy.dev/python.html)
|
||||
for a quick overview of the supported features.
|
||||
|
||||
| Name | Example | Supported |
|
||||
| --------------- | ------------------------------- | --------- |
|
||||
| If Else | `if..else..elif` | ✅ |
|
||||
| Loop | `for/while/break/continue` | ✅ |
|
||||
| Function | `def f(x,*args,y=1):` | ✅ |
|
||||
| Subclass | `class A(B):` | ✅ |
|
||||
| List | `[1, 2, 'a']` | ✅ |
|
||||
| ListComp | `[i for i in range(5)]` | ✅ |
|
||||
| Slice | `a[1:2], a[:2], a[1:]` | ✅ |
|
||||
| Tuple | `(1, 2, 'a')` | ✅ |
|
||||
| Dict | `{'a': 1, 'b': 2}` | ✅ |
|
||||
| F-String | `f'value is {x}'` | ✅ |
|
||||
| Unpacking | `a, b = 1, 2` | ✅ |
|
||||
| Star Unpacking | `a, *b = [1, 2, 3]` | ✅ |
|
||||
| Exception | `raise/try..catch..finally` | ✅ |
|
||||
| Dynamic Code | `eval()/exec()` | ✅ |
|
||||
| Reflection | `hasattr()/getattr()/setattr()` | ✅ |
|
||||
| Import | `import/from..import` | ✅ |
|
||||
| Context Block | `with <expr> as <id>:` | ✅ |
|
||||
| Type Annotation | `def f(a:int, b:float=1)` | ✅ |
|
||||
| Generator | `yield i` | ✅ |
|
||||
| Decorator | `@cache` | ✅ |
|
||||
|
||||
## Performance
|
||||
|
||||
Currently, pkpy is as fast as cpython 3.9.
|
||||
Performance results for cpython 3.9 are applicable to for pkpy.
|
||||
|
||||
See https://pocketpy.dev/performance/ for details.
|
||||
|
||||
And these are the results of the primes benchmark on Intel i5-12400F, WSL (Ubuntu 20.04 LTS), which *roughly* reflects the performance among c++, lua, pkpy and cpython.
|
||||
|
||||
| name | version | time | file |
|
||||
| ---- | ---- | ---- | ---- |
|
||||
| c++ | gnu++11 | `0.104s ■□□□□□□□□□□□□□□□` | [benchmarks/primes.cpp](https://github.com/pocketpy/pocketpy/blob/9481d653b60b81f4590a4d48f2be496f6962261e/benchmarks/primes.cpp) |
|
||||
| lua | 5.3.3 | `1.576s ■■■■■■■■■□□□□□□□` | [benchmarks/primes.lua](https://github.com/pocketpy/pocketpy/blob/9481d653b60b81f4590a4d48f2be496f6962261e/benchmarks/primes.lua) |
|
||||
| pkpy | 1.2.7 | `2.385s ■■■■■■■■■■■■■□□□` | [benchmarks/primes.py](https://github.com/pocketpy/pocketpy/blob/9481d653b60b81f4590a4d48f2be496f6962261e/benchmarks/primes.py) |
|
||||
| cpython | 3.8.10 | `2.871s ■■■■■■■■■■■■■■■■` | [benchmarks/primes.py](https://github.com/pocketpy/pocketpy/blob/9481d653b60b81f4590a4d48f2be496f6962261e/benchmarks/primes.py) |
|
||||
|
||||
## Used By
|
||||
|
||||
| | Description |
|
||||
|-----------------------------------------------------------------|--------------------------------------------------------------------------|
|
||||
| [TIC-80](https://github.com/nesbox/TIC-80) | TIC-80 is a fantasy computer for making, playing and sharing tiny games. |
|
||||
| [MiniPythonIDE](https://github.com/CU-Production/MiniPythonIDE) | A python ide base on pocketpy |
|
||||
| [py-js](https://github.com/shakfu/py-js) | Python3 externals for Max / MSP |
|
||||
| [crescent](https://github.com/chukobyte/crescent) | Crescent is a cross-platform 2D fighting and beat-em-up game engine. |
|
||||
|
||||
Submit a pull request to add your project here.
|
||||
|
||||
## Contribution
|
||||
|
||||
All kinds of contributions are welcome.
|
||||
|
||||
- Submit a Pull Request
|
||||
- fix a bug
|
||||
- add a new feature
|
||||
- Open an Issue
|
||||
- any suggestions
|
||||
- any questions
|
||||
|
||||
If you find pkpy useful, consider star this repository (●'◡'●)
|
||||
|
||||
## Sponsor this project
|
||||
|
||||
You can sponsor this project via these ways.
|
||||
|
||||
+ [Github Sponsors](https://github.com/sponsors/blueloveTH)
|
||||
+ [Buy me a coffee](https://www.buymeacoffee.com/blueloveth)
|
||||
|
||||
Your sponsorship will help us develop pkpy continuously.
|
||||
|
||||
## Reference
|
||||
|
||||
+ [cpython](https://github.com/python/cpython)
|
||||
|
||||
The official implementation of Python programming language.
|
||||
|
||||
+ [byterun](https://www.aosabook.org/en/500L/a-python-interpreter-written-in-python.html)
|
||||
|
||||
An excellent learning material. It illustrates how Python's virtual machine works.
|
||||
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#blueloveth/pocketpy&Date)
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](http://opensource.org/licenses/MIT)
|
||||
0
dependencies/pocketpy/__init__.py
vendored
Normal file
0
dependencies/pocketpy/__init__.py
vendored
Normal file
96
dependencies/pocketpy/amalgamate.py
vendored
Normal file
96
dependencies/pocketpy/amalgamate.py
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
import os
|
||||
|
||||
assert os.system("python prebuild.py") == 0
|
||||
|
||||
with open("include/pocketpy/opcodes.h", "rt", encoding='utf-8') as f:
|
||||
OPCODES_TEXT = '\n' + f.read() + '\n'
|
||||
|
||||
pipeline = [
|
||||
["config.h", "export.h", "_generated.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h"],
|
||||
["obj.h", "dict.h", "codeobject.h", "frame.h", "profiler.h"],
|
||||
["gc.h", "vm.h", "ceval.h", "lexer.h", "expr.h", "compiler.h", "repl.h"],
|
||||
["cffi.h", "bindings.h", "iter.h", "base64.h", "csv.h", "collections.h", "array2d.h", "dataclasses.h", "random.h", "linalg.h", "easing.h", "io.h", "modules.h"],
|
||||
["pocketpy.h", "pocketpy_c.h"]
|
||||
]
|
||||
|
||||
copied = set()
|
||||
text = ""
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
if os.path.exists("amalgamated"):
|
||||
shutil.rmtree("amalgamated")
|
||||
time.sleep(0.5)
|
||||
os.mkdir("amalgamated")
|
||||
|
||||
def remove_copied_include(text):
|
||||
text = text.replace("#pragma once", "")
|
||||
|
||||
def _replace(m):
|
||||
key = m.group(1)
|
||||
if key.startswith("pocketpy/"):
|
||||
key = key[9:]
|
||||
if key in ["user_config.h", "cJSONw.hpp"]:
|
||||
return m.group(0)
|
||||
if "opcodes.h" in key:
|
||||
return OPCODES_TEXT
|
||||
assert key in copied, f"include {key} not found"
|
||||
return ""
|
||||
|
||||
text = re.sub(
|
||||
r'#include\s+"(.+)"\s*',
|
||||
_replace,
|
||||
text
|
||||
)
|
||||
return text
|
||||
|
||||
for seq in pipeline:
|
||||
for j in seq:
|
||||
print(j)
|
||||
with open("include/pocketpy/"+j, "rt", encoding='utf-8') as f:
|
||||
text += remove_copied_include(f.read()) + '\n'
|
||||
copied.add(j)
|
||||
j = j.replace(".h", ".cpp")
|
||||
if os.path.exists("src/"+j):
|
||||
with open("src/"+j, "rt", encoding='utf-8') as f:
|
||||
text += remove_copied_include(f.read()) + '\n'
|
||||
copied.add(j)
|
||||
|
||||
# use LF line endings instead of CRLF
|
||||
with open("amalgamated/pocketpy.h", "wt", encoding='utf-8', newline='\n') as f:
|
||||
final_text = \
|
||||
r'''/*
|
||||
* Copyright (c) 2024 blueloveTH
|
||||
* Distributed Under The MIT License
|
||||
* https://github.com/pocketpy/pocketpy
|
||||
*/
|
||||
|
||||
#ifndef POCKETPY_H
|
||||
#define POCKETPY_H
|
||||
''' + text + '\n#endif // POCKETPY_H'
|
||||
f.write(final_text)
|
||||
|
||||
shutil.copy("src2/main.cpp", "amalgamated/main.cpp")
|
||||
with open("amalgamated/main.cpp", "rt", encoding='utf-8') as f:
|
||||
text = f.read()
|
||||
text = text.replace('#include "pocketpy/pocketpy.h"', '#include "pocketpy.h"')
|
||||
with open("amalgamated/main.cpp", "wt", encoding='utf-8', newline='\n') as f:
|
||||
f.write(text)
|
||||
|
||||
if sys.platform in ['linux', 'darwin']:
|
||||
ok = os.system("clang++ -o main amalgamated/main.cpp -O1 --std=c++17 -frtti -stdlib=libc++")
|
||||
if ok == 0:
|
||||
print("Test build success!")
|
||||
|
||||
print("amalgamated/pocketpy.h")
|
||||
|
||||
def sync(path):
|
||||
shutil.copy("amalgamated/pocketpy.h", os.path.join(path, "pocketpy.h"))
|
||||
with open(os.path.join(path, "pocketpy.cpp"), "wt", encoding='utf-8', newline='\n') as f:
|
||||
f.write("#include \"pocketpy.h\"\n")
|
||||
|
||||
sync("plugins/macos/pocketpy")
|
||||
0
dependencies/pocketpy/benchmarks/__init__.py
vendored
Normal file
0
dependencies/pocketpy/benchmarks/__init__.py
vendored
Normal file
10
dependencies/pocketpy/benchmarks/fib.py
vendored
Normal file
10
dependencies/pocketpy/benchmarks/fib.py
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
def fib(n):
|
||||
if n < 2:
|
||||
return n
|
||||
return fib(n-1) + fib(n-2)
|
||||
|
||||
assert fib(32) == 2178309
|
||||
|
||||
# from dis import dis
|
||||
# dis(fib)
|
||||
# 7049155 calls
|
||||
8
dependencies/pocketpy/benchmarks/function_0.py
vendored
Normal file
8
dependencies/pocketpy/benchmarks/function_0.py
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
def f(a, b, c):
|
||||
pass
|
||||
|
||||
for i in range(10000000):
|
||||
f(1, 2, 3)
|
||||
f(1, 2, 3)
|
||||
f(1, 2, 3)
|
||||
f(1, 2, 3)
|
||||
11
dependencies/pocketpy/benchmarks/function_1.py
vendored
Normal file
11
dependencies/pocketpy/benchmarks/function_1.py
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
class A:
|
||||
def f(self, a, b, c):
|
||||
pass
|
||||
|
||||
a = A()
|
||||
for i in range(10000000):
|
||||
a.f(1, 2, 3)
|
||||
a.f(1, 2, 3)
|
||||
a.f(1, 2, 3)
|
||||
a.f(1, 2, 3)
|
||||
|
||||
46
dependencies/pocketpy/benchmarks/ldtk_cjson.py
vendored
Normal file
46
dependencies/pocketpy/benchmarks/ldtk_cjson.py
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
try:
|
||||
import os
|
||||
except ImportError:
|
||||
exit(0)
|
||||
|
||||
import sys
|
||||
is_pkpy = not hasattr(sys, 'getrefcount')
|
||||
|
||||
os.chdir('benchmarks')
|
||||
|
||||
if is_pkpy:
|
||||
try:
|
||||
import cjson as json
|
||||
except ImportError:
|
||||
print('[cJSON not Enabled]')
|
||||
exit(0)
|
||||
else:
|
||||
import json
|
||||
|
||||
_2489KB = 'WorldMap_GridVania_layout.ldtk'
|
||||
_1093KB = 'WorldMap_Free_layout.ldtk'
|
||||
_339KB = 'Typical_2D_platformer_example.ldtk'
|
||||
|
||||
with open(f'res/{_2489KB}', 'r') as f:
|
||||
json_content = f.read()
|
||||
|
||||
data: dict = json.loads(json_content)
|
||||
assert isinstance(data, dict)
|
||||
|
||||
# serialize and deserialize
|
||||
dumped: str = json.dumps(data)
|
||||
for _ in range(10):
|
||||
loaded: dict = json.loads(dumped)
|
||||
assert len(data) == len(loaded)
|
||||
assert data == loaded
|
||||
|
||||
#### very very slow!!
|
||||
import pickle
|
||||
|
||||
with open(f'res/{_339KB}', 'r') as f:
|
||||
json_content = f.read()
|
||||
data: dict = json.loads(json_content)
|
||||
|
||||
data_pickled: bytes = pickle.dumps(data)
|
||||
assert isinstance(data_pickled, bytes)
|
||||
assert pickle.loads(data_pickled) == data
|
||||
30
dependencies/pocketpy/benchmarks/ldtk_json.py
vendored
Normal file
30
dependencies/pocketpy/benchmarks/ldtk_json.py
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
try:
|
||||
import os
|
||||
except ImportError:
|
||||
exit(0)
|
||||
|
||||
os.chdir('benchmarks')
|
||||
|
||||
import json
|
||||
|
||||
_2489KB = 'WorldMap_GridVania_layout.ldtk'
|
||||
_1093KB = 'WorldMap_Free_layout.ldtk'
|
||||
_339KB = 'Typical_2D_platformer_example.ldtk'
|
||||
|
||||
with open(f'res/{_2489KB}', 'r') as f:
|
||||
json_content = f.read()
|
||||
|
||||
data: dict = json.loads(json_content)
|
||||
assert isinstance(data, dict)
|
||||
|
||||
# serialize and deserialize
|
||||
dumped: str = json.dumps(data)
|
||||
loaded: dict = json.loads(dumped)
|
||||
assert len(data) == len(loaded)
|
||||
assert data == loaded
|
||||
|
||||
#### very very slow!! DO NOT RUN IT
|
||||
# import pickle
|
||||
# data_pickled: bytes = pickle.dumps(data)
|
||||
# assert isinstance(data_pickled, bytes)
|
||||
# assert pickle.loads(data_pickled) == data
|
||||
2
dependencies/pocketpy/benchmarks/loop_0.py
vendored
Normal file
2
dependencies/pocketpy/benchmarks/loop_0.py
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
for i in range(10000000):
|
||||
pass
|
||||
2
dependencies/pocketpy/benchmarks/loop_1.py
vendored
Normal file
2
dependencies/pocketpy/benchmarks/loop_1.py
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
for i in range(10000000):
|
||||
x = i
|
||||
6
dependencies/pocketpy/benchmarks/loop_2.py
vendored
Normal file
6
dependencies/pocketpy/benchmarks/loop_2.py
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
x = 0
|
||||
|
||||
for i in range(10000000):
|
||||
x += 1
|
||||
|
||||
assert x == 10000000
|
||||
5
dependencies/pocketpy/benchmarks/loop_3.py
vendored
Normal file
5
dependencies/pocketpy/benchmarks/loop_3.py
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
for i in range(10000000):
|
||||
x = i + 1
|
||||
y = x * 2
|
||||
z = y - 5
|
||||
a = x * y // z
|
||||
167
dependencies/pocketpy/benchmarks/primes.cpp
vendored
Normal file
167
dependencies/pocketpy/benchmarks/primes.cpp
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
typedef long long LL;
|
||||
|
||||
struct Node{
|
||||
std::unordered_map<int, Node*> children;
|
||||
bool terminal;
|
||||
|
||||
Node(){
|
||||
terminal = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Sieve{
|
||||
LL limit;
|
||||
std::vector<bool> prime;
|
||||
|
||||
Sieve(LL limit){
|
||||
this->limit = limit;
|
||||
prime = std::vector<bool>(limit + 1, false);
|
||||
}
|
||||
|
||||
std::vector<LL> to_list(){
|
||||
std::vector<LL> result;
|
||||
result.push_back(2);
|
||||
result.push_back(3);
|
||||
for(LL p = 5; p <= limit; p++){
|
||||
if(prime[p]){
|
||||
result.push_back(p);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void omit_squares(){
|
||||
LL r = 5;
|
||||
while(r * r < limit){
|
||||
if(prime[r]){
|
||||
LL i = r * r;
|
||||
while(i < limit){
|
||||
prime[i] = false;
|
||||
i = i + r * r;
|
||||
}
|
||||
}
|
||||
r += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void step1(LL x, LL y){
|
||||
LL n = (4 * x * x) + (y * y);
|
||||
if(n <= limit && (n % 12 == 1 || n % 12 == 5)){
|
||||
prime[n] = !prime[n];
|
||||
}
|
||||
}
|
||||
|
||||
void step2(LL x, LL y){
|
||||
LL n = (3 * x * x) + (y * y);
|
||||
if(n <= limit && n % 12 == 7){
|
||||
prime[n] = !prime[n];
|
||||
}
|
||||
}
|
||||
|
||||
void step3(LL x, LL y){
|
||||
LL n = (3 * x * x) - (y * y);
|
||||
if(x > y && n <= limit && n % 12 == 11){
|
||||
prime[n] = !prime[n];
|
||||
}
|
||||
}
|
||||
|
||||
void loop_y(LL x){
|
||||
LL y = 1;
|
||||
while(y * y < limit){
|
||||
step1(x, y);
|
||||
step2(x, y);
|
||||
step3(x, y);
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void loop_x(){
|
||||
LL x = 1;
|
||||
while(x * x < limit){
|
||||
loop_y(x);
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void calc(){
|
||||
loop_x();
|
||||
omit_squares();
|
||||
}
|
||||
};
|
||||
|
||||
Node *generate_trie(std::vector<LL> l){
|
||||
Node *root = new Node();
|
||||
for(LL el : l){
|
||||
Node *head = root;
|
||||
std::string s = std::to_string(el);
|
||||
for(char ch : s){
|
||||
if(head->children.find(ch) == head->children.end()){
|
||||
head->children[ch] = new Node();
|
||||
}
|
||||
head = head->children[ch];
|
||||
}
|
||||
head->terminal = true;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
std::vector<LL> find(LL upper_bound, LL prefix){
|
||||
Sieve *sieve = new Sieve(upper_bound);
|
||||
sieve->calc();
|
||||
std::string str_prefix = std::to_string(prefix);
|
||||
Node *head = generate_trie(sieve->to_list());
|
||||
for(char ch : str_prefix){
|
||||
if(head->children.find(ch) == head->children.end()){
|
||||
return std::vector<LL>();
|
||||
}
|
||||
head = head->children[ch];
|
||||
}
|
||||
|
||||
std::queue<std::pair<Node*, std::string>> q;
|
||||
std::vector<LL> result;
|
||||
q.push(std::make_pair(head, str_prefix));
|
||||
while(!q.empty()){
|
||||
std::pair<Node*, std::string> top = q.front();
|
||||
q.pop();
|
||||
if(top.first->terminal){
|
||||
result.push_back(std::stoll(top.second));
|
||||
}
|
||||
for(std::pair<char, Node*> p : top.first->children){
|
||||
q.push(std::make_pair(p.second, top.second + p.first));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(result.begin(), result.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
void verify(){
|
||||
std::vector<LL> left = {2, 23, 29};
|
||||
std::vector<LL> right = find(100, 2);
|
||||
if(left != right){
|
||||
std::cout << "left != right" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(){
|
||||
const LL UPPER_BOUND = 5000000;
|
||||
const LL PREFIX = 32338;
|
||||
|
||||
verify();
|
||||
std::vector<LL> results = find(UPPER_BOUND, PREFIX);
|
||||
std::vector<LL> expected = {323381, 323383, 3233803, 3233809, 3233851, 3233863, 3233873, 3233887, 3233897};
|
||||
if(results != expected){
|
||||
std::cout << "results != expected" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
168
dependencies/pocketpy/benchmarks/primes.lua
vendored
Normal file
168
dependencies/pocketpy/benchmarks/primes.lua
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
local UPPER_BOUND = 5000000
|
||||
local PREFIX = 32338
|
||||
|
||||
local Node = {}
|
||||
function Node:new()
|
||||
local obj = {}
|
||||
setmetatable(obj, self)
|
||||
self.__index = self
|
||||
obj.children = {}
|
||||
obj.terminal = false
|
||||
return obj
|
||||
end
|
||||
|
||||
local Sieve = {}
|
||||
function Sieve:new(limit)
|
||||
local obj = {}
|
||||
setmetatable(obj, self)
|
||||
self.__index = self
|
||||
obj.limit = limit
|
||||
obj.prime = {}
|
||||
for i = 0, limit do
|
||||
obj.prime[i] = false
|
||||
end
|
||||
return obj
|
||||
end
|
||||
|
||||
function Sieve:to_list()
|
||||
local result = {2, 3}
|
||||
for p = 5, self.limit do
|
||||
if self.prime[p] then
|
||||
table.insert(result, p)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function Sieve:omit_squares()
|
||||
local r = 5
|
||||
while r * r < self.limit do
|
||||
if self.prime[r] then
|
||||
local i = r * r
|
||||
while i < self.limit do
|
||||
self.prime[i] = false
|
||||
i = i + r * r
|
||||
end
|
||||
end
|
||||
r = r + 1
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function Sieve:step1(x, y)
|
||||
local n = (4 * x * x) + (y * y)
|
||||
if n <= self.limit and (n % 12 == 1 or n % 12 == 5) then
|
||||
self.prime[n] = not self.prime[n]
|
||||
end
|
||||
end
|
||||
|
||||
function Sieve:step2(x, y)
|
||||
local n = (3 * x * x) + (y * y)
|
||||
if n <= self.limit and n % 12 == 7 then
|
||||
self.prime[n] = not self.prime[n]
|
||||
end
|
||||
end
|
||||
|
||||
function Sieve:step3(x, y)
|
||||
local n = (3 * x * x) - (y * y)
|
||||
if x > y and n <= self.limit and n % 12 == 11 then
|
||||
self.prime[n] = not self.prime[n]
|
||||
end
|
||||
end
|
||||
|
||||
function Sieve:loop_y(x)
|
||||
local y = 1
|
||||
while y * y < self.limit do
|
||||
self:step1(x, y)
|
||||
self:step2(x, y)
|
||||
self:step3(x, y)
|
||||
y = y + 1
|
||||
end
|
||||
end
|
||||
|
||||
function Sieve:loop_x()
|
||||
local x = 1
|
||||
while x * x < self.limit do
|
||||
self:loop_y(x)
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
function Sieve:calc()
|
||||
self:loop_x()
|
||||
return self:omit_squares()
|
||||
end
|
||||
|
||||
local function generate_trie(l)
|
||||
local root = Node:new()
|
||||
for _, el in ipairs(l) do
|
||||
local head = root
|
||||
-- attempt to call a nil value (method 'split')
|
||||
-- how to fix? use string.split
|
||||
el = tostring(el)
|
||||
for i=1, #el do
|
||||
local ch = el:sub(i, i)
|
||||
if not head.children[ch] then
|
||||
head.children[ch] = Node:new()
|
||||
end
|
||||
head = head.children[ch]
|
||||
end
|
||||
head.terminal = true
|
||||
end
|
||||
return root
|
||||
end
|
||||
|
||||
local function find(upper_bound, prefix_)
|
||||
local primes = Sieve:new(upper_bound):calc()
|
||||
local str_prefix = tostring(prefix_)
|
||||
local head = generate_trie(primes:to_list())
|
||||
for i=1, #str_prefix do
|
||||
local ch = str_prefix:sub(i, i)
|
||||
head = head.children[ch]
|
||||
if head == nil then
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local queue, result = {{head, str_prefix}}, {}
|
||||
while #queue > 0 do
|
||||
local tuple = table.remove(queue)
|
||||
local top, prefix = tuple[1], tuple[2]
|
||||
if top.terminal then
|
||||
table.insert(result, tonumber(prefix))
|
||||
end
|
||||
for ch, v in pairs(top.children) do
|
||||
table.insert(queue, 1, {v, prefix .. ch})
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(result)
|
||||
return result
|
||||
end
|
||||
|
||||
local function verify()
|
||||
local left = {2, 23, 29}
|
||||
local right = find(100, 2)
|
||||
if #left ~= #right then
|
||||
print("length not equal")
|
||||
os.exit(1)
|
||||
end
|
||||
for i, v in ipairs(left) do
|
||||
if v ~= right[i] then
|
||||
print(string.format("%s != %s", v, right[i]))
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
verify()
|
||||
local results = find(UPPER_BOUND, PREFIX)
|
||||
local expected = {323381, 323383, 3233803, 3233809, 3233851, 3233863, 3233873, 3233887, 3233897}
|
||||
|
||||
for i, v in ipairs(results) do
|
||||
if v ~= expected[i] then
|
||||
print(string.format("%s != %s", v, expected[i]))
|
||||
os.exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
111
dependencies/pocketpy/benchmarks/primes.py
vendored
Normal file
111
dependencies/pocketpy/benchmarks/primes.py
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
UPPER_BOUND = 5000000
|
||||
PREFIX = 32338
|
||||
|
||||
# exit(0)
|
||||
|
||||
class Node:
|
||||
def __init__(self):
|
||||
self.children = {}
|
||||
self.terminal = False
|
||||
|
||||
|
||||
class Sieve:
|
||||
def __init__(self, limit):
|
||||
self.limit = limit
|
||||
self.prime = [False] * (limit + 1)
|
||||
|
||||
def to_list(self):
|
||||
result = [2, 3]
|
||||
for p in range(5, self.limit + 1):
|
||||
if self.prime[p]:
|
||||
result.append(p)
|
||||
return result
|
||||
|
||||
def omit_squares(self):
|
||||
r = 5
|
||||
while r * r < self.limit:
|
||||
if self.prime[r]:
|
||||
i = r * r
|
||||
while i < self.limit:
|
||||
self.prime[i] = False
|
||||
i = i + r * r
|
||||
r += 1
|
||||
return self
|
||||
|
||||
def step1(self, x, y):
|
||||
n = (4 * x * x) + (y * y)
|
||||
if n <= self.limit and (n % 12 == 1 or n % 12 == 5):
|
||||
self.prime[n] = not self.prime[n]
|
||||
|
||||
def step2(self, x, y):
|
||||
n = (3 * x * x) + (y * y)
|
||||
if n <= self.limit and n % 12 == 7:
|
||||
self.prime[n] = not self.prime[n]
|
||||
|
||||
def step3(self, x, y):
|
||||
n = (3 * x * x) - (y * y)
|
||||
if x > y and n <= self.limit and n % 12 == 11:
|
||||
self.prime[n] = not self.prime[n]
|
||||
|
||||
def loop_y(self, x):
|
||||
y = 1
|
||||
while y * y < self.limit:
|
||||
self.step1(x, y)
|
||||
self.step2(x, y)
|
||||
self.step3(x, y)
|
||||
y += 1
|
||||
|
||||
def loop_x(self):
|
||||
x = 1
|
||||
while x * x < self.limit:
|
||||
self.loop_y(x)
|
||||
x += 1
|
||||
|
||||
def calc(self):
|
||||
self.loop_x()
|
||||
return self.omit_squares()
|
||||
|
||||
|
||||
def generate_trie(l):
|
||||
root = Node()
|
||||
for el in l:
|
||||
head = root
|
||||
for ch in str(el):
|
||||
if ch not in head.children:
|
||||
head.children[ch] = Node()
|
||||
head = head.children[ch]
|
||||
head.terminal = True
|
||||
return root
|
||||
|
||||
|
||||
def find(upper_bound, prefix):
|
||||
primes = Sieve(upper_bound).calc()
|
||||
str_prefix = str(prefix)
|
||||
head = generate_trie(primes.to_list())
|
||||
for ch in str_prefix:
|
||||
head = head.children.get(ch)
|
||||
if head is None: # either ch does not exist or the value is None
|
||||
return None
|
||||
|
||||
queue, result = [(head, str_prefix)], []
|
||||
while queue:
|
||||
top, prefix = queue.pop()
|
||||
if top.terminal:
|
||||
result.append(int(prefix))
|
||||
for ch, v in top.children.items():
|
||||
queue.insert(0, (v, prefix + ch))
|
||||
|
||||
result.sort()
|
||||
return result
|
||||
|
||||
|
||||
def verify():
|
||||
left = [2, 23, 29]
|
||||
right = find(100, 2)
|
||||
if left != right:
|
||||
print(f"{left} != {right}")
|
||||
exit(1)
|
||||
|
||||
verify()
|
||||
results = find(UPPER_BOUND, PREFIX)
|
||||
assert results == [323381, 323383, 3233803, 3233809, 3233851, 3233863, 3233873, 3233887, 3233897]
|
||||
6
dependencies/pocketpy/benchmarks/recursive.py
vendored
Normal file
6
dependencies/pocketpy/benchmarks/recursive.py
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
def f(n):
|
||||
if n == 900:
|
||||
return -1
|
||||
return f(n + 1)
|
||||
|
||||
assert f(0) == -1
|
||||
5553
dependencies/pocketpy/benchmarks/res/Typical_2D_platformer_example.ldtk
vendored
Normal file
5553
dependencies/pocketpy/benchmarks/res/Typical_2D_platformer_example.ldtk
vendored
Normal file
File diff suppressed because one or more lines are too long
14948
dependencies/pocketpy/benchmarks/res/WorldMap_Free_layout.ldtk
vendored
Normal file
14948
dependencies/pocketpy/benchmarks/res/WorldMap_Free_layout.ldtk
vendored
Normal file
File diff suppressed because one or more lines are too long
33256
dependencies/pocketpy/benchmarks/res/WorldMap_GridVania_layout.ldtk
vendored
Normal file
33256
dependencies/pocketpy/benchmarks/res/WorldMap_GridVania_layout.ldtk
vendored
Normal file
File diff suppressed because one or more lines are too long
20
dependencies/pocketpy/benchmarks/simple.py
vendored
Normal file
20
dependencies/pocketpy/benchmarks/simple.py
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
def is_prime(x):
|
||||
if x<2:
|
||||
return False
|
||||
for i in range(2,x):
|
||||
if x%i == 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
def test(n):
|
||||
k = 0
|
||||
for i in range(n):
|
||||
if is_prime(i):
|
||||
k += 1
|
||||
return k
|
||||
|
||||
# from dis import dis
|
||||
# dis(test)
|
||||
# dis(is_prime)
|
||||
|
||||
assert test(10000) == 1229
|
||||
22
dependencies/pocketpy/benchmarks/sort.py
vendored
Normal file
22
dependencies/pocketpy/benchmarks/sort.py
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
import random
|
||||
|
||||
a = [random.randint(-100000, 100000) for i in range(100000)]
|
||||
|
||||
def __qsort(a: list, L: int, R: int):
|
||||
if L >= R: return;
|
||||
mid = a[(R+L)//2];
|
||||
i, j = L, R
|
||||
while i<=j:
|
||||
while a[i]<mid: i+=1
|
||||
while a[j]>mid: j-=1
|
||||
if i<=j:
|
||||
a[i], a[j] = a[j], a[i]
|
||||
i+=1
|
||||
j-=1
|
||||
__qsort(a, L, j)
|
||||
__qsort(a, i, R)
|
||||
|
||||
from dis import dis
|
||||
# dis(__qsort)
|
||||
|
||||
__qsort(a, 0, len(a)-1)
|
||||
6
dependencies/pocketpy/benchmarks/sum.py
vendored
Normal file
6
dependencies/pocketpy/benchmarks/sum.py
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
def f(n):
|
||||
if n == 0:
|
||||
return 0
|
||||
return n + f(n-1)
|
||||
|
||||
assert f(900) == 405450
|
||||
48
dependencies/pocketpy/build.sh
vendored
Normal file
48
dependencies/pocketpy/build.sh
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if clang++ is installed
|
||||
if ! type -P clang++ >/dev/null 2>&1; then
|
||||
echo "clang++ is required and not installed. Kindly install it."
|
||||
echo "Run: sudo apt-get install libc++-dev libc++abi-dev clang"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "It takes a moment to finish building."
|
||||
echo ""
|
||||
echo "> Running prebuild.py... "
|
||||
|
||||
python prebuild.py
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "prebuild.py failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC=$(find src/ -name "*.cpp")
|
||||
|
||||
echo "> Compiling and linking source files... "
|
||||
|
||||
FLAGS="-std=c++17 -O1 -stdlib=libc++ -frtti -Wfatal-errors -Iinclude"
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
LIB_EXTENSION=".dylib"
|
||||
FLAGS="$FLAGS -undefined dynamic_lookup"
|
||||
LINK_FLAGS=""
|
||||
else
|
||||
LIB_EXTENSION=".so"
|
||||
LINK_FLAGS="-Wl,-rpath=."
|
||||
fi
|
||||
|
||||
clang++ $FLAGS -o libpocketpy$LIB_EXTENSION $SRC -fPIC -shared
|
||||
|
||||
# compile main.cpp and link to libpocketpy.so
|
||||
echo "> Compiling main.cpp and linking to libpocketpy$LIB_EXTENSION..."
|
||||
|
||||
clang++ $FLAGS -o main -O1 src2/main.cpp -L. -lpocketpy $LINK_FLAGS
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Build completed. Type \"./main\" to enter REPL."
|
||||
else
|
||||
echo "Build failed."
|
||||
exit 1
|
||||
fi
|
||||
18
dependencies/pocketpy/build_android.sh
vendored
Normal file
18
dependencies/pocketpy/build_android.sh
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
# if no $1 default arm64-v8a
|
||||
if [ -z $1 ]; then
|
||||
$1=arm64-v8a
|
||||
fi
|
||||
|
||||
mkdir -p build/android/$1
|
||||
cd build/android/$1
|
||||
|
||||
cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=$1 \
|
||||
-DANDROID_PLATFORM=android-22 \
|
||||
-DANDROID_STL=c++_shared \
|
||||
../../.. \
|
||||
-DPK_BUILD_SHARED_LIB=ON -DPK_USE_CJSON=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
cmake --build . --config Release
|
||||
18
dependencies/pocketpy/build_ios.sh
vendored
Normal file
18
dependencies/pocketpy/build_ios.sh
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
FLAGS="-DCMAKE_TOOLCHAIN_FILE=3rd/ios.toolchain.cmake -DPK_BUILD_STATIC_LIB=ON -DDEPLOYMENT_TARGET=13.0"
|
||||
|
||||
cmake -B os64 -G Xcode $FLAGS -DPLATFORM=OS64 ..
|
||||
cmake --build os64 --config Release
|
||||
|
||||
cmake -B simulatorarm64 -G Xcode $FLAGS -DPLATFORM=SIMULATORARM64 ..
|
||||
cmake --build simulatorarm64 --config Release
|
||||
|
||||
xcodebuild -create-xcframework \
|
||||
-library os64/Release-iphoneos/libpocketpy.a -headers ../include \
|
||||
-library simulatorarm64/Release-iphonesimulator/libpocketpy.a -headers ../include \
|
||||
-output pocketpy.xcframework
|
||||
|
||||
|
||||
7
dependencies/pocketpy/build_web.sh
vendored
Normal file
7
dependencies/pocketpy/build_web.sh
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
python prebuild.py
|
||||
|
||||
rm -rf web/lib
|
||||
mkdir web/lib
|
||||
|
||||
SRC=$(find src/ -name "*.cpp")
|
||||
em++ $SRC -Iinclude/ -fexceptions -frtti -s -Os -sEXPORTED_FUNCTIONS=_pkpy_new_repl,_pkpy_repl_input,_pkpy_new_vm -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js
|
||||
5
dependencies/pocketpy/build_with_warnings.sh
vendored
Normal file
5
dependencies/pocketpy/build_with_warnings.sh
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
SRC=$(find src/ -name "*.cpp")
|
||||
|
||||
FLAGS="-std=c++17 -O1 -stdlib=libc++ -Iinclude -frtti -W -Wno-unused-parameter -Wno-sign-compare"
|
||||
|
||||
clang++ $FLAGS -o main -O1 src2/main.cpp $SRC
|
||||
23
dependencies/pocketpy/c_bindings/CMakeLists.txt
vendored
Normal file
23
dependencies/pocketpy/c_bindings/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
|
||||
project(test_c_bindings)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" ON)
|
||||
|
||||
add_subdirectory(
|
||||
..
|
||||
${CMAKE_CURRENT_LIST_DIR}/build/pocketpy/
|
||||
)
|
||||
|
||||
include_directories(
|
||||
../include
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} test.c)
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
pocketpy
|
||||
)
|
||||
420
dependencies/pocketpy/c_bindings/test.c
vendored
Normal file
420
dependencies/pocketpy/c_bindings/test.c
vendored
Normal file
@ -0,0 +1,420 @@
|
||||
#include "pocketpy_c.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//tests the c bindings for pocketpy
|
||||
|
||||
void check_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (!result) {
|
||||
printf("ERROR: failed where it should have succeed at line %i\n", lineno);
|
||||
char* message;
|
||||
if (!pkpy_clear_error(vm, &message)) {
|
||||
printf("clear error reported everything was fine\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("%s\n", message);
|
||||
free(message);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void fail_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (result) {
|
||||
printf("ERROR: succeeded where it should have failed line %i\n", lineno);
|
||||
exit(1);
|
||||
} else {
|
||||
char* message;
|
||||
if (pkpy_clear_error(vm, &message)) {
|
||||
printf("actually errored! line %i\n", lineno);
|
||||
free(message);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void error_impl(pkpy_vm* vm, bool result, int lineno) {
|
||||
if (result) {
|
||||
printf("ERROR: succeeded where it should have failed line %i\n", lineno);
|
||||
exit(1);
|
||||
} else {
|
||||
char* message;
|
||||
if (!pkpy_clear_error(vm, &message)){
|
||||
printf("clear error reported everything was fine\n");
|
||||
exit(1);
|
||||
} else {
|
||||
printf("successfully errored with this message: \n");
|
||||
printf("%s\n", message);
|
||||
free(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define check(r) check_impl(vm, (r), __LINE__)
|
||||
#define fail(r) fail_impl(vm, (r), __LINE__)
|
||||
#define error(r) error_impl(vm, (r), __LINE__)
|
||||
|
||||
int test_binding(pkpy_vm* vm) {
|
||||
pkpy_push_int(vm, 12);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_multiple_return(pkpy_vm* vm) {
|
||||
pkpy_push_int(vm, 12);
|
||||
pkpy_push_int(vm, 13);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int test_minus(pkpy_vm* vm) {
|
||||
int a, b;
|
||||
pkpy_to_int(vm, 0, &a);
|
||||
pkpy_to_int(vm, 1, &b);
|
||||
pkpy_push_int(vm, a - b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_fib(pkpy_vm* vm) {
|
||||
int n;
|
||||
pkpy_to_int(vm, 0, &n);
|
||||
if (n == 1) {
|
||||
pkpy_push_int(vm, n);
|
||||
} else {
|
||||
pkpy_getglobal(vm, pkpy_name("test_fib"));
|
||||
pkpy_push_null(vm);
|
||||
pkpy_push_int(vm, n-1);
|
||||
pkpy_vectorcall(vm, 1);
|
||||
int r_int;
|
||||
pkpy_to_int(vm, -1, &r_int);
|
||||
pkpy_pop_top(vm);
|
||||
pkpy_push_int(vm, r_int + n);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_default_argument(pkpy_vm* vm){
|
||||
int x;
|
||||
pkpy_to_int(vm, -1, &x);
|
||||
bool ok = x == 5;
|
||||
pkpy_push_bool(vm, ok);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_return_none(pkpy_vm* vm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_error_propagate(pkpy_vm* vm) {
|
||||
pkpy_error(vm, "NameError", pkpy_string("catch me"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test_nested_error(pkpy_vm* vm) {
|
||||
pkpy_getglobal(vm, pkpy_name("error_from_python"));
|
||||
pkpy_push_null(vm);
|
||||
pkpy_vectorcall(vm, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PRINT_TITLE(x) printf("\n====== %s ======\n", x)
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
pkpy_vm* vm = pkpy_new_vm(true);
|
||||
|
||||
PRINT_TITLE("test basic exec");
|
||||
check(pkpy_exec(vm, "print('hello world!')"));
|
||||
fail(pkpy_getglobal(vm, pkpy_name("nonexistatn")));
|
||||
|
||||
// test int methods
|
||||
PRINT_TITLE("test int methods");
|
||||
int r_int;
|
||||
check(pkpy_push_int(vm, 11));
|
||||
pkpy_CName m_eleven = pkpy_name("eleven");
|
||||
check(pkpy_setglobal(vm, m_eleven));
|
||||
check(pkpy_exec(vm, "print(eleven)"));
|
||||
check(pkpy_getglobal(vm, m_eleven));
|
||||
check(pkpy_is_int(vm, -1));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("%i\n", r_int); // 11
|
||||
printf("%i\n", pkpy_stack_size(vm)); // 1
|
||||
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test float methods");
|
||||
double r_float;
|
||||
check(pkpy_push_float(vm, 11.125));
|
||||
pkpy_CName m_elevenf = pkpy_name("elevenf");
|
||||
check(pkpy_setglobal(vm, m_elevenf));
|
||||
check(pkpy_exec(vm, "print(elevenf)"));
|
||||
check(pkpy_getglobal(vm, m_elevenf));
|
||||
check(pkpy_is_float(vm, -1));
|
||||
check(pkpy_to_float(vm, -1, &r_float));
|
||||
printf("%.3f\n", r_float);
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test bool methods");
|
||||
bool r_bool;
|
||||
check(pkpy_push_bool(vm, false));
|
||||
pkpy_CName m_false_test = pkpy_name("false_test");
|
||||
check(pkpy_setglobal(vm, m_false_test));
|
||||
check(pkpy_exec(vm, "print(false_test)"));
|
||||
check(pkpy_getglobal(vm, m_false_test));
|
||||
check(pkpy_is_bool(vm, -1));
|
||||
check(pkpy_to_bool(vm, -1, &r_bool));
|
||||
printf("%i\n", r_bool);
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test string methods");
|
||||
pkpy_CString r_string;
|
||||
check(pkpy_push_string(vm, pkpy_string("hello!")));
|
||||
check(pkpy_setglobal(vm, pkpy_name("hello1")));
|
||||
check(pkpy_exec(vm, "print(hello1)"));
|
||||
check(pkpy_push_string(vm, pkpy_string("hello!")));
|
||||
check(pkpy_is_string(vm, -1));
|
||||
check(pkpy_to_string(vm, -1, &r_string));
|
||||
|
||||
puts(r_string);
|
||||
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test none methods");
|
||||
check(pkpy_push_none(vm));
|
||||
pkpy_CName m_none = pkpy_name("none");
|
||||
check(pkpy_setglobal(vm, m_none));
|
||||
check(pkpy_exec(vm, "print(none)"));
|
||||
check(pkpy_getglobal(vm, m_none));
|
||||
check(pkpy_is_none(vm, -1));
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test voidp methods");
|
||||
void* vp = (void*) 123;
|
||||
check(pkpy_push_voidp(vm, vp));
|
||||
check(pkpy_setglobal(vm, pkpy_name("vp")));
|
||||
check(pkpy_exec(vm, "print(vp)"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("vp")));
|
||||
check(pkpy_is_voidp(vm, -1));
|
||||
vp = NULL;
|
||||
check(pkpy_to_voidp(vm, -1, &vp));
|
||||
printf("%i\n", (int) (intptr_t) vp);
|
||||
fail(pkpy_is_int(vm, -1));
|
||||
fail(pkpy_is_float(vm, -1));
|
||||
fail(pkpy_is_bool(vm, -1));
|
||||
fail(pkpy_is_string(vm, -1));
|
||||
fail(pkpy_is_none(vm, -1));
|
||||
|
||||
PRINT_TITLE("test sizing and indexing");
|
||||
int stack_size = pkpy_stack_size(vm);
|
||||
printf("stack size %i\n", stack_size);
|
||||
check(pkpy_is_int(vm, 0));
|
||||
check(pkpy_is_float(vm, 1));
|
||||
check(pkpy_is_bool(vm, 2));
|
||||
check(pkpy_is_string(vm, 3));
|
||||
check(pkpy_is_none(vm, 4));
|
||||
check(pkpy_is_voidp(vm, 5));
|
||||
check(pkpy_is_int(vm, -6));
|
||||
check(pkpy_is_float(vm, -5));
|
||||
check(pkpy_is_bool(vm, -4));
|
||||
check(pkpy_is_string(vm, -3));
|
||||
check(pkpy_is_none(vm, -2));
|
||||
check(pkpy_is_voidp(vm, -1));
|
||||
|
||||
PRINT_TITLE("test error catching");
|
||||
error(pkpy_exec(vm, "let's make sure syntax errors get caught"));
|
||||
//stack should be cleared after error is resolved
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test simple call");
|
||||
check(pkpy_exec(vm, "def x(x, y) : return x - y"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_push_int(vm, 2));
|
||||
check(pkpy_push_int(vm, 3));
|
||||
check(pkpy_vectorcall(vm, 2));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("x : %i\n", r_int);
|
||||
|
||||
PRINT_TITLE("test vararg call");
|
||||
check(pkpy_exec(vm, "def vararg_x(*x) : return sum(x)"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("vararg_x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_push_int(vm, 1));
|
||||
check(pkpy_push_int(vm, 2));
|
||||
check(pkpy_push_int(vm, 3));
|
||||
check(pkpy_push_int(vm, 4));
|
||||
check(pkpy_push_int(vm, 5));
|
||||
check(pkpy_push_int(vm, 6));
|
||||
check(pkpy_vectorcall(vm, 6));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("vararg_x : %i\n", r_int);
|
||||
|
||||
PRINT_TITLE("test keyword call");
|
||||
check(pkpy_exec(vm, "def keyword_x(x=1, y=1) : return x+y"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("keyword_x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_push_int(vm, 3));
|
||||
check(pkpy_vectorcall(vm, 1));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("keyword_x : %i\n", r_int); // 3+1
|
||||
|
||||
check(pkpy_getglobal(vm, pkpy_name("keyword_x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_vectorcall(vm, 0));
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("keyword_x : %i\n", r_int); // 1+1
|
||||
check(pkpy_stack_size(vm) == 4);
|
||||
check(pkpy_pop(vm, 4)); // clear stack
|
||||
|
||||
PRINT_TITLE("test return many");
|
||||
check(pkpy_exec(vm, "def retmany_x() : return 1, 2, 3"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("retmany_x")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_vectorcall(vm, 0));
|
||||
|
||||
check(pkpy_stack_size(vm) == 1);
|
||||
check(pkpy_unpack_sequence(vm, 3));
|
||||
check(pkpy_stack_size(vm) == 3);
|
||||
|
||||
check(pkpy_to_int(vm, -3, &r_int));
|
||||
printf("retmany_x : %i\n", r_int);
|
||||
check(pkpy_to_int(vm, -2, &r_int));
|
||||
printf("retmany_x : %i\n", r_int);
|
||||
check(pkpy_to_int(vm, -1, &r_int));
|
||||
printf("retmany_x : %i\n", r_int);
|
||||
|
||||
// test argument error
|
||||
check(pkpy_getglobal(vm, pkpy_name("x")));
|
||||
check(pkpy_push_null(vm));
|
||||
error(pkpy_vectorcall(vm, 0));
|
||||
|
||||
check(pkpy_exec(vm, "l = []"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("l")));
|
||||
check(pkpy_get_unbound_method(vm, pkpy_name("append")));
|
||||
check(pkpy_push_string(vm, pkpy_string("hello")));
|
||||
check(pkpy_vectorcall(vm, 1));
|
||||
check(pkpy_pop_top(vm)); // pop None returned by append()
|
||||
check(pkpy_exec(vm, "print(l)"));
|
||||
|
||||
PRINT_TITLE("test bindings");
|
||||
check(pkpy_push_function(vm, "test_binding()", test_binding));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_binding")));
|
||||
check(pkpy_exec(vm, "print(test_binding())"));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
check(pkpy_push_function(vm, "test_multiple_return()", test_multiple_return));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_multiple_return")));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
check(pkpy_push_function(vm, "test_default_argument(x=5)", test_default_argument));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_vectorcall(vm, 0));
|
||||
check(pkpy_stack_size(vm) == 1);
|
||||
check(pkpy_is_bool(vm, -1) == true);
|
||||
check(pkpy_to_bool(vm, -1, &r_bool));
|
||||
check(r_bool == true);
|
||||
check(pkpy_pop_top(vm));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test bindings 2");
|
||||
check(pkpy_push_function(vm, "test_minus(a, b)", test_minus));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_minus")));
|
||||
check(pkpy_exec(vm, "print(test_minus(5, 3))"));
|
||||
check(pkpy_exec(vm, "for i in range(5): print(test_minus(5, i))"));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test bindings fib");
|
||||
check(pkpy_push_function(vm, "test_fib(n: int) -> int", test_fib));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_fib")));
|
||||
check(pkpy_exec(vm, "print(test_fib(10))"));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test error propagate");
|
||||
check(pkpy_push_function(vm, "test_error_propagate()", test_error_propagate));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_error_propagate")));
|
||||
error(pkpy_exec(vm, "test_error_propagate()"));
|
||||
|
||||
check(pkpy_getglobal(vm, pkpy_name("test_multiple_return")));
|
||||
check(pkpy_push_null(vm));
|
||||
check(pkpy_vectorcall(vm, 0));
|
||||
check(pkpy_stack_size(vm) == 1);
|
||||
check(pkpy_unpack_sequence(vm, 2));
|
||||
check(pkpy_stack_size(vm) == 2);
|
||||
check(pkpy_pop(vm, 2));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test other errors");
|
||||
check(pkpy_getglobal(vm, pkpy_name("test_error_propagate")));
|
||||
check(pkpy_pop_top(vm));
|
||||
fail(pkpy_getglobal(vm, pkpy_name("nonexistant")));
|
||||
error(pkpy_exec(vm, "raise NameError('testing error throwing from python')"));
|
||||
|
||||
PRINT_TITLE("test TypeError");
|
||||
check(pkpy_push_float(vm, 2.0));
|
||||
error(pkpy_to_int(vm, -1, &r_int));
|
||||
|
||||
PRINT_TITLE("test complicated errors");
|
||||
pkpy_exec(vm, "test_error_propagate()");
|
||||
check(pkpy_check_error(vm));
|
||||
pkpy_clear_error(vm, NULL);
|
||||
|
||||
//this should be catchable
|
||||
check(pkpy_exec(vm, "try : test_error_propagate(); except NameError : pass"));
|
||||
error(pkpy_error(vm, "Exception", pkpy_string("test direct error mechanism")));
|
||||
|
||||
//more complicated error handling
|
||||
check(pkpy_exec(vm, "def error_from_python() : raise NotImplementedError()"));
|
||||
check(pkpy_push_function(vm, "test_nested_error()", test_nested_error));
|
||||
check(pkpy_setglobal(vm, pkpy_name("test_nested_error")));
|
||||
error(pkpy_exec(vm, "test_nested_error()"));
|
||||
|
||||
PRINT_TITLE("test getattr/setattr");
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
check(pkpy_exec(vm, "import math"));
|
||||
check(pkpy_getglobal(vm, pkpy_name("math")));
|
||||
check(pkpy_getattr(vm, pkpy_name("pi")));
|
||||
check(pkpy_to_float(vm, -1, &r_float));
|
||||
printf("pi: %.2f\n", (float)r_float);
|
||||
check(pkpy_pop(vm, 1));
|
||||
|
||||
// math.pi = 2
|
||||
check(pkpy_push_int(vm, 2));
|
||||
check(pkpy_eval(vm, "math"));
|
||||
check(pkpy_setattr(vm, pkpy_name("pi")));
|
||||
check(pkpy_exec(vm, "print(math.pi)"));
|
||||
|
||||
PRINT_TITLE("test eval");
|
||||
check(pkpy_eval(vm, "math.pi"));
|
||||
check(pkpy_to_float(vm, -1, &r_float));
|
||||
printf("pi: %.2f\n", (float)r_float);
|
||||
check(pkpy_pop(vm, 1));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
|
||||
PRINT_TITLE("test py_repr");
|
||||
check(pkpy_eval(vm, "['1', 2, (3, '4')]"));
|
||||
check(pkpy_py_repr(vm));
|
||||
check(pkpy_to_string(vm, -1, &r_string));
|
||||
|
||||
puts(r_string);
|
||||
check(pkpy_pop_top(vm));
|
||||
check(pkpy_stack_size(vm) == 0);
|
||||
return 0;
|
||||
}
|
||||
112
dependencies/pocketpy/c_bindings/test_answers.txt
vendored
Normal file
112
dependencies/pocketpy/c_bindings/test_answers.txt
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
|
||||
====== test basic exec ======
|
||||
hello world!
|
||||
|
||||
====== test int methods ======
|
||||
11
|
||||
11
|
||||
1
|
||||
|
||||
====== test float methods ======
|
||||
11.125
|
||||
11.125
|
||||
|
||||
====== test bool methods ======
|
||||
False
|
||||
0
|
||||
|
||||
====== test string methods ======
|
||||
hello!
|
||||
hello!
|
||||
|
||||
====== test none methods ======
|
||||
None
|
||||
|
||||
====== test voidp methods ======
|
||||
<void* at 0x7b>
|
||||
123
|
||||
|
||||
====== test sizing and indexing ======
|
||||
stack size 6
|
||||
|
||||
====== test error catching ======
|
||||
successfully errored with this message:
|
||||
File "main.py", line 1
|
||||
let's make sure syntax errors get caught
|
||||
SyntaxError: EOL while scanning string literal
|
||||
|
||||
====== test simple call ======
|
||||
x : -1
|
||||
|
||||
====== test vararg call ======
|
||||
vararg_x : 21
|
||||
|
||||
====== test keyword call ======
|
||||
keyword_x : 4
|
||||
keyword_x : 2
|
||||
|
||||
====== test return many ======
|
||||
retmany_x : 1
|
||||
retmany_x : 2
|
||||
retmany_x : 3
|
||||
successfully errored with this message:
|
||||
TypeError: x() takes 2 positional arguments but 0 were given
|
||||
['hello']
|
||||
|
||||
====== test bindings ======
|
||||
12
|
||||
|
||||
====== test bindings 2 ======
|
||||
2
|
||||
5
|
||||
4
|
||||
3
|
||||
2
|
||||
1
|
||||
|
||||
====== test bindings fib ======
|
||||
55
|
||||
|
||||
====== test error propagate ======
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
test_error_propagate()
|
||||
NameError: catch me
|
||||
|
||||
====== test other errors ======
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
raise NameError('testing error throwing from python')
|
||||
NameError: testing error throwing from python
|
||||
|
||||
====== test TypeError ======
|
||||
successfully errored with this message:
|
||||
TypeError: expected 'int', got 'float'
|
||||
|
||||
====== test complicated errors ======
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
test_error_propagate()
|
||||
NameError: catch me
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
Exception: test direct error mechanism
|
||||
successfully errored with this message:
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1
|
||||
test_nested_error()
|
||||
File "main.py", line 1, in error_from_python
|
||||
def error_from_python() : raise NotImplementedError()
|
||||
NotImplementedError
|
||||
|
||||
====== test getattr/setattr ======
|
||||
pi: 3.14
|
||||
2
|
||||
|
||||
====== test eval ======
|
||||
pi: 2.00
|
||||
|
||||
====== test py_repr ======
|
||||
['1', 2, (3, '4')]
|
||||
25
dependencies/pocketpy/cmake_build.py
vendored
Normal file
25
dependencies/pocketpy/cmake_build.py
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
assert os.system("python prebuild.py") == 0
|
||||
|
||||
if not os.path.exists("build"):
|
||||
os.mkdir("build")
|
||||
|
||||
os.chdir("build")
|
||||
|
||||
code = os.system("cmake .. -DPK_USE_CJSON=ON -DPK_ENABLE_OS=ON -DCMAKE_BUILD_TYPE=Release")
|
||||
assert code == 0
|
||||
code = os.system("cmake --build . --config Release")
|
||||
assert code == 0
|
||||
|
||||
if sys.platform == "win32":
|
||||
shutil.copy("Release/main.exe", "../main.exe")
|
||||
shutil.copy("Release/pocketpy.dll", "../pocketpy.dll")
|
||||
elif sys.platform == "darwin":
|
||||
shutil.copy("main", "../main")
|
||||
shutil.copy("libpocketpy.dylib", "../libpocketpy.dylib")
|
||||
else:
|
||||
shutil.copy("main", "../main")
|
||||
shutil.copy("libpocketpy.so", "../libpocketpy.so")
|
||||
11
dependencies/pocketpy/compile_flags.txt
vendored
Normal file
11
dependencies/pocketpy/compile_flags.txt
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
-xc++
|
||||
|
||||
-Wall
|
||||
-W*
|
||||
|
||||
-std=c++17
|
||||
-stdlib=libc++
|
||||
|
||||
-Iinclude/
|
||||
-I3rd/cjson/include/
|
||||
-I3rd/lua_bridge/include/
|
||||
19
dependencies/pocketpy/docs/C-API/call.md
vendored
Normal file
19
dependencies/pocketpy/docs/C-API/call.md
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
title: Call
|
||||
icon: dot
|
||||
order: 6
|
||||
---
|
||||
|
||||
### `bool pkpy_vectorcall(pkpy_vm*, int argc)`
|
||||
|
||||
Wraps `vm->vectorcall(argc)`. This function is used to call a function with a fixed number of arguments. The arguments are popped from the stack. The return value is pushed onto the stack.
|
||||
|
||||
1. First push the function to call.
|
||||
2. Push `self` argument if it is a method call. Otherwise, call `pkpy_push_null`.
|
||||
3. Push arguments from left to right.
|
||||
|
||||
!!!
|
||||
Unlike lua, a python function always returns a value.
|
||||
If the function returns `void`, it will push `None` onto the stack.
|
||||
You can call `pkpy_pop_top` to discard the return value.
|
||||
!!!
|
||||
23
dependencies/pocketpy/docs/C-API/error.md
vendored
Normal file
23
dependencies/pocketpy/docs/C-API/error.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
title: Error Handling
|
||||
icon: dot
|
||||
order: 5
|
||||
---
|
||||
|
||||
#### `bool pkpy_clear_error(pkpy_vm*, char** message)`
|
||||
|
||||
+ If a method returns false, call the `pkpy_clear_error` method to check the error and clear it
|
||||
+ If `pkpy_clear_error` returns false, it means that no error was set, and it takes no action
|
||||
+ If `pkpy_clear_error` returns true, it means there was an error and it was cleared. It will provide a string summary of the error in the message parameter if it is not `NULL`.
|
||||
|
||||
!!!
|
||||
You are responsible for freeing `message`.
|
||||
!!!
|
||||
|
||||
#### `bool pkpy_check_error(pkpy_vm*)`
|
||||
|
||||
Return true if the vm is currently in an error state.
|
||||
|
||||
#### `bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString message)`
|
||||
|
||||
Set the error state of the vm. It is almost equivalent to `raise` in python.
|
||||
3
dependencies/pocketpy/docs/C-API/index.yml
vendored
Normal file
3
dependencies/pocketpy/docs/C-API/index.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
label: C-API
|
||||
icon: code
|
||||
order: 1
|
||||
42
dependencies/pocketpy/docs/C-API/introduction.md
vendored
Normal file
42
dependencies/pocketpy/docs/C-API/introduction.md
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
---
|
||||
title: Introduction
|
||||
icon: dot
|
||||
order: 10
|
||||
---
|
||||
|
||||
### What C-API is for
|
||||
|
||||
The C-APIs are designed for these purposes:
|
||||
|
||||
1. Your target platform does not support C++17. You compile pkpy into a static library and use its exported C-APIs.
|
||||
2. You want to write a native module that can be imported via `__import__` at runtime. By using C-APIs, the module is portable across different compilers without C++ ABI compatibility issues.
|
||||
|
||||
Our C-APIs take a lot of inspiration from the lua C-APIs.
|
||||
Methods return a `bool` indicating if the operation succeeded or not.
|
||||
Special thanks for [@koltenpearson](https://github.com/koltenpearson)'s contribution.
|
||||
|
||||
!!!
|
||||
C-APIs are always stable and backward compatible.
|
||||
!!!
|
||||
|
||||
### Basic functions
|
||||
|
||||
+ `pkpy_vm* pkpy_new_vm(bool enable_os)`
|
||||
|
||||
Wraps `new VM(enable_os)` in C++.
|
||||
|
||||
+ `void pkpy_delete_vm(pkpy_vm*)`
|
||||
|
||||
Wraps `delete vm` in C++.
|
||||
|
||||
+ `bool pkpy_exec(pkpy_vm*, const char* source)`
|
||||
|
||||
Wraps `vm->exec`. Execute a string of source code.
|
||||
|
||||
+ `bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module)`
|
||||
|
||||
Wraps `vm->exec_2`. Execute a string of source code with more options.
|
||||
|
||||
+ `void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv)`
|
||||
|
||||
Wraps `vm->set_main_argv`. Set the `sys.argv` before executing scripts.
|
||||
21
dependencies/pocketpy/docs/C-API/specials.md
vendored
Normal file
21
dependencies/pocketpy/docs/C-API/specials.md
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Specials
|
||||
icon: dot
|
||||
order: 6
|
||||
---
|
||||
|
||||
+ `void pkpy_free(void* p)`
|
||||
|
||||
Wraps `free(p)` in C++.
|
||||
|
||||
+ `pkpy_CString pkpy_string(const char*)`
|
||||
|
||||
Construct a `pkpy_CString` from a null-terminated C string.
|
||||
|
||||
+ `pkpy_CName pkpy_name(const char*)`
|
||||
|
||||
Construct a `pkpy_CName` from a null-terminated C string. You should cache the result of this function if you are going to use it multiple times.
|
||||
|
||||
+ `pkpy_CString pkpy_name_to_string(pkpy_CName)`
|
||||
|
||||
Convert a `pkpy_CName` to a `pkpy_CString`.
|
||||
153
dependencies/pocketpy/docs/C-API/stack.md
vendored
Normal file
153
dependencies/pocketpy/docs/C-API/stack.md
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
---
|
||||
title: Stack Manipulation
|
||||
icon: dot
|
||||
order: 8
|
||||
---
|
||||
|
||||
### Basic manipulation
|
||||
|
||||
+ `bool pkpy_dup(pkpy_vm*, int)`
|
||||
|
||||
Duplicate the value at the given index.
|
||||
|
||||
+ `bool pkpy_pop(pkpy_vm*, int)`
|
||||
|
||||
Pop `n` values from the stack.
|
||||
|
||||
+ `bool pkpy_pop_top(pkpy_vm*)`
|
||||
|
||||
Pop the top value from the stack.
|
||||
|
||||
+ `bool pkpy_dup_top(pkpy_vm*)`
|
||||
|
||||
Duplicate the top value on the stack.
|
||||
|
||||
+ `bool pkpy_rot_two(pkpy_vm*)`
|
||||
|
||||
Swap the top two values on the stack.
|
||||
|
||||
+ `int pkpy_stack_size(pkpy_vm*)`
|
||||
|
||||
Get the element count of the stack.
|
||||
|
||||
|
||||
### Basic push, check and convert
|
||||
|
||||
+ `pkpy_push_xxx` pushes a value onto the stack.
|
||||
+ `pkpy_is_xxx` checks if the value at the given index is of the given type.
|
||||
+ `pkpy_to_xxx` converts the value at the given index to the given type.
|
||||
|
||||
Stack index is 0-based instead of 1-based. And it can be negative, which means the index is counted from the top of the stack.
|
||||
|
||||
```c
|
||||
// int
|
||||
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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*);
|
||||
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
|
||||
|
||||
+ `pkpy_push_null(pkpy_vm*)`
|
||||
|
||||
Push a `PY_NULL` onto the stack. It is used for `pkpy_vectorcall`.
|
||||
|
||||
+ `pkpy_push_function(pkpy_vm*, const char* sig, pkpy_CFunction f)`
|
||||
|
||||
Push a function onto the stack. `sig` is the function signature, e.g. `add(a: int, b: int) -> int`. `f` is the function pointer.
|
||||
|
||||
+ `pkpy_push_module(pkpy_vm*, const char* name)`
|
||||
|
||||
Push a new module onto the stack. `name` is the module name. This is not `import`. It creates a new module object.
|
||||
|
||||
### Variable access
|
||||
|
||||
+ `bool pkpy_getattr(pkpy_vm*, pkpy_CName name)`
|
||||
|
||||
Push `b.<name>` onto the stack. Return false if the attribute is not found.
|
||||
|
||||
```
|
||||
[b] -> [b.<name>]
|
||||
```
|
||||
|
||||
+ `bool pkpy_setattr(pkpy_vm*, pkpy_CName name)`
|
||||
|
||||
Set `b.<name>` to the value at the top of the stack.
|
||||
First push the value, then push `b`.
|
||||
|
||||
```
|
||||
[value, b] -> []
|
||||
```
|
||||
|
||||
+ `bool pkpy_getglobal(pkpy_vm*, pkpy_CName name)`
|
||||
|
||||
Push a global/builtin variable onto the stack. Return false if the variable is not found.
|
||||
|
||||
```
|
||||
[] -> [value]
|
||||
```
|
||||
|
||||
+ `bool pkpy_setglobal(pkpy_vm*, pkpy_CName name)`
|
||||
|
||||
Set a global variable to the value at the top of the stack.
|
||||
|
||||
```
|
||||
[value] -> []
|
||||
```
|
||||
|
||||
+ `bool pkpy_eval(pkpy_vm*, const char* source)`
|
||||
|
||||
Evaluate a string and push the result onto the stack.
|
||||
|
||||
```
|
||||
[] -> [result]
|
||||
```
|
||||
|
||||
+ `bool pkpy_unpack_sequence(pkpy_vm*, int size)`
|
||||
|
||||
Unpack a sequence at the top of the stack. `size` is the element count of the sequence.
|
||||
|
||||
```
|
||||
[a] -> [a[0], a[1], ..., a[size - 1]]
|
||||
```
|
||||
|
||||
+ `bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name)`
|
||||
|
||||
It is used for method call.
|
||||
Get an unbound method from the object at the top of the stack. `name` is the method name.
|
||||
Also push the object as self.
|
||||
|
||||
```
|
||||
[obj] -> [obj.<name> self]
|
||||
```
|
||||
+ `bool pkpy_py_repr(pkpy_vm*)`
|
||||
|
||||
Get the repr of the value at the top of the stack.
|
||||
|
||||
```
|
||||
[value] -> [repr(value)]
|
||||
```
|
||||
267
dependencies/pocketpy/docs/bindings.md
vendored
Normal file
267
dependencies/pocketpy/docs/bindings.md
vendored
Normal file
@ -0,0 +1,267 @@
|
||||
---
|
||||
icon: cpu
|
||||
title: Write Bindings
|
||||
order: 18
|
||||
---
|
||||
|
||||
In order to use a C/C++ library in python, you need to write bindings for it.
|
||||
|
||||
## Manual bindings
|
||||
|
||||
pkpy uses an universal signature to wrap a function pointer as a python function or method that can be called in python code, i.e `NativeFuncC`.
|
||||
|
||||
```cpp
|
||||
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
||||
```
|
||||
+ The first argument is the pointer of `VM` instance.
|
||||
+ The second argument is an array-like object indicates the arguments list. You can use `[]` operator to get the element and call `size()` to get the length of the array.
|
||||
+ The return value is a `PyObject*`, which should not be `nullptr`. If there is no return value, return `vm->None`.
|
||||
|
||||
### Bind a function or method
|
||||
|
||||
Use `vm->bind` to bind a function or method.
|
||||
|
||||
+ `PyObject* bind(PyObject*, const char* sig, NativeFuncC)`
|
||||
+ `PyObject* bind(PyObject*, const char* sig, const char* docstring, NativeFuncC)`
|
||||
|
||||
```cpp
|
||||
|
||||
vm->bind(obj, "add(a: int, b: int) -> int", [](VM* vm, ArgsView args){
|
||||
int a = py_cast<int>(vm, args[0]);
|
||||
int b = py_cast<int>(vm, args[1]);
|
||||
return py_var(vm, a + b);
|
||||
});
|
||||
|
||||
// or you can provide a docstring
|
||||
vm->bind(obj,
|
||||
"add(a: int, b: int) -> int",
|
||||
"add two integers", [](VM* vm, ArgsView args){
|
||||
int a = py_cast<int>(vm, args[0]);
|
||||
int b = py_cast<int>(vm, args[1]);
|
||||
return py_var(vm, a + b);
|
||||
});
|
||||
```
|
||||
|
||||
#### How to capture something
|
||||
|
||||
By default, the lambda being bound is a C function pointer,
|
||||
you cannot capture anything! The following example does not compile.
|
||||
|
||||
```cpp
|
||||
int x = 1;
|
||||
vm->bind(obj, "f() -> int", [x](VM* vm, ArgsView args){
|
||||
// error: cannot capture 'x'
|
||||
return py_var(vm, x);
|
||||
});
|
||||
```
|
||||
|
||||
I do not encourage you to capture something in a lambda being bound
|
||||
because:
|
||||
1. Captured lambda runs slower and causes "code-bloat".
|
||||
2. Captured values are unsafe, especially for `PyObject*` as they could leak by accident.
|
||||
|
||||
However, there are 3 ways to capture something when you really need to.
|
||||
The most safe and elegant way is to subclass `VM` and add a member variable.
|
||||
|
||||
```cpp
|
||||
class YourVM : public VM{
|
||||
public:
|
||||
int x;
|
||||
YourVM() : VM() {}
|
||||
};
|
||||
|
||||
int main(){
|
||||
YourVM* vm = new YourVM();
|
||||
vm->x = 1;
|
||||
vm->bind(obj, "f() -> int", [](VM* _vm, ArgsView args){
|
||||
// do a static_cast and you can get any extra members of YourVM
|
||||
YourVM* vm = static_cast<YourVM*>(_vm);
|
||||
return py_var(vm, vm->x);
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The 2nd way is to use `vm->bind`'s last parameter `userdata`, you can store a POD type smaller than 8 bytes.
|
||||
And use `lambda_get_userdata<T>(args.begin())` to get it inside the lambda body.
|
||||
|
||||
```cpp
|
||||
int x = 1;
|
||||
vm->bind(obj, "f() -> int", [](VM* vm, ArgsView args){
|
||||
// get the userdata
|
||||
int x = lambda_get_userdata<int>(args.begin());
|
||||
return py_var(vm, x);
|
||||
}, x); // capture x
|
||||
```
|
||||
|
||||
The 3rd way is to change the macro `PK_ENABLE_STD_FUNCTION` in `config.h`:
|
||||
```cpp
|
||||
#define PK_ENABLE_STD_FUNCTION 0 // => 1
|
||||
```
|
||||
|
||||
Then you can use standard capture list in lambda.
|
||||
|
||||
### Bind a struct
|
||||
|
||||
Assume you have a struct `Point` declared as follows.
|
||||
|
||||
```cpp
|
||||
struct Point{
|
||||
int x;
|
||||
int y;
|
||||
}
|
||||
```
|
||||
|
||||
You can write a wrapper class `wrapped__Point`. Add `PY_CLASS` macro into your wrapper class and implement a static function `_register`.
|
||||
|
||||
Inside the `_register` function, do bind methods and properties.
|
||||
|
||||
```cpp
|
||||
PY_CLASS(T, mod, name)
|
||||
|
||||
// T is the struct type in cpp
|
||||
// mod is the module name in python
|
||||
// name is the class name in python
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```cpp
|
||||
struct wrapped__Point{
|
||||
// special macro for wrapper class
|
||||
PY_CLASS(wrapped__Point, builtins, Point)
|
||||
// ^T ^module ^name
|
||||
|
||||
// wrapped value
|
||||
Point value;
|
||||
|
||||
// special method _ returns a pointer of the wrapped value
|
||||
Point* _() { return &value; }
|
||||
|
||||
// define default constructors
|
||||
wrapped__Point() = default;
|
||||
wrapped__Point(const wrapped__Point&) = default;
|
||||
|
||||
// define wrapped constructor
|
||||
wrapped__Point(Point value){
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
// enable default constructor and struct-like methods
|
||||
// if you don't use this, you must bind a `__new__` method as constructor
|
||||
PY_STRUCT_LIKE(wrapped__Point)
|
||||
|
||||
// wrap field x
|
||||
PY_FIELD(wrapped__Point, "x", _, x)
|
||||
// wrap field y
|
||||
PY_FIELD(wrapped__Point, "y", _, y)
|
||||
|
||||
// __init__ method
|
||||
vm->bind(type, "__init__(self, x, y)", [](VM* vm, ArgsView args){
|
||||
wrapped__Point& self = _py_cast<wrapped__Point&>(vm, args[0]);
|
||||
self.value.x = py_cast<int>(vm, args[1]);
|
||||
self.value.y = py_cast<int>(vm, args[2]);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
// other custom methods
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
int main(){
|
||||
VM* vm = new VM();
|
||||
// register the wrapper class somewhere
|
||||
wrapped__Point::register_class(vm, vm->builtins);
|
||||
|
||||
// use the Point class
|
||||
vm->exec("a = Point(1, 2)");
|
||||
vm->exec("print(a.x)"); // 1
|
||||
vm->exec("print(a.y)"); // 2
|
||||
|
||||
delete vm;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
#### Handle gc for container types
|
||||
|
||||
If your custom type stores `PyObject*` in its fields, you need to handle gc for them.
|
||||
|
||||
```cpp
|
||||
struct Container{
|
||||
PY_CLASS(Container, builtins, Container)
|
||||
|
||||
PyObject* a;
|
||||
std::vector<PyObject*> b;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Add a magic method `_gc_mark() const` to your custom type.
|
||||
|
||||
```cpp
|
||||
struct Container{
|
||||
PY_CLASS(Container, builtins, Container)
|
||||
|
||||
PyObject* a;
|
||||
std::vector<PyObject*> b;
|
||||
// ...
|
||||
|
||||
void _gc_mark() const{
|
||||
// mark a
|
||||
if(a) PK_OBJ_MARK(a);
|
||||
|
||||
// mark elements in b
|
||||
for(PyObject* obj : b){
|
||||
if(obj) PK_OBJ_MARK(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For global objects, use the callback in `vm->heap`.
|
||||
```cpp
|
||||
void (*_gc_marker_ex)(VM*) = nullptr;
|
||||
```
|
||||
It will be invoked before a GC starts. So you can mark objects inside the callback to keep them alive.
|
||||
|
||||
### Others
|
||||
|
||||
You may see somewhere in the code that `vm->bind_method<>` or `vm->bind_func<>` is used.
|
||||
They are old style binding functions and are deprecated.
|
||||
It is recommended to use `vm->bind`.
|
||||
|
||||
For some magic methods, we provide specialized binding function.
|
||||
They do not take universal function pointer as argument.
|
||||
You need to provide the detailed `Type` object and the corresponding function pointer.
|
||||
|
||||
```cpp
|
||||
PyObject* f_add(VM* vm, PyObject* lhs, PyObject* rhs){
|
||||
int a = py_cast<int>(vm, lhs);
|
||||
int b = py_cast<int>(vm, rhs);
|
||||
return py_var(vm, a + b);
|
||||
}
|
||||
|
||||
vm->bind__add__(vm->tp_int, f_add);
|
||||
```
|
||||
|
||||
This specialized binding function has optimizations and result in better performance when calling from python code.
|
||||
|
||||
For example, `vm->bind__add__` is preferred over `vm->bind_method<1>(type, "__add__", ...)`.
|
||||
|
||||
|
||||
## Automatic bindings
|
||||
|
||||
pkpy supports automatic binding generation **only for C libraries**.
|
||||
See [pkpy-bindings](https://github.com/blueloveTH/pkpy-bindings) for details.
|
||||
|
||||
It takes a C header file and generates a python module stub (`*.pyi`) and a C++ binding file (`*.cpp`).
|
||||
|
||||
|
||||
## Further reading
|
||||
|
||||
See [random.cpp](https://github.com/pocketpy/pocketpy/blob/main/src/random.cpp) for an example used by `random` module.
|
||||
|
||||
See [collections.cpp](https://github.com/pocketpy/pocketpy/blob/main/src/collections.cpp) for a modern implementation of `collections.deque`.
|
||||
104
dependencies/pocketpy/docs/bindings_lua.md
vendored
Normal file
104
dependencies/pocketpy/docs/bindings_lua.md
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
---
|
||||
icon: cpu
|
||||
title: Reuse Lua Bindings
|
||||
order: 17
|
||||
---
|
||||
|
||||
!!!
|
||||
This feature is available in `v1.4.0` or higher.
|
||||
!!!
|
||||
|
||||
pkpy provides a lua bridge to reuse lua bindings.
|
||||
It allows you to run lua code and call lua functions in python
|
||||
by embedding a lua virtual machine.
|
||||
|
||||
Add `lua_bridge.hpp` and `lua_bridge.cpp` in [3rd/lua_bridge](https://github.com/pocketpy/pocketpy/tree/main/3rd/lua_bridge) to your project.
|
||||
Make sure `lua.h`, `lualib.h` and `lauxlib.h` are in your include path
|
||||
because `lua_bridge.hpp` needs them.
|
||||
|
||||
The lua bridge is based on lua 5.1.5 for maximum compatibility.
|
||||
lua 5.2 or higher should also work.
|
||||
|
||||
### Setup
|
||||
|
||||
Use `initialize_lua_bridge(VM*, lua_State*)` to initialize the lua bridge.
|
||||
This creates a new module `lua` in your python virtual machine.
|
||||
|
||||
You can use `lua.dostring` to execute lua code and get the result.
|
||||
And use `lua.Table()` to create a lua table.
|
||||
A `lua.Table` instance in python is a dict-like object which provides a bunch of
|
||||
magic methods to access the underlying lua table.
|
||||
|
||||
```python
|
||||
class Table:
|
||||
def keys(self) -> list:
|
||||
"""Return a list of keys in the table."""
|
||||
|
||||
def values(self) -> list:
|
||||
"""Return a list of values in the table."""
|
||||
|
||||
def items(self) -> list[tuple]:
|
||||
"""Return a list of (key, value) pairs in the table."""
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Return the length of the table."""
|
||||
|
||||
def __contains__(self, key) -> bool:
|
||||
"""Return True if the table contains the key."""
|
||||
|
||||
def __getitem__(self, key): ...
|
||||
def __setitem__(self, key, value): ...
|
||||
def __delitem__(self, key): ...
|
||||
def __getattr__(self, key): ...
|
||||
def __setattr__(self, key, value): ...
|
||||
def __delattr__(self, key): ...
|
||||
```
|
||||
|
||||
Only basic types can be passed between python and lua.
|
||||
The following table shows the type mapping.
|
||||
If you pass an unsupported type, an exception will be raised.
|
||||
|
||||
| Python type | Lua type | Allow create in Python? | Reference? |
|
||||
| ----------- | -------- | ---------------------- | --------- |
|
||||
| `None` | `nil` | YES | NO |
|
||||
| `bool` | `boolean` | YES | NO |
|
||||
| `int` | `number` | YES | NO |
|
||||
| `float` | `number` | YES | NO |
|
||||
| `str` | `string` | YES | NO |
|
||||
| `tuple` | `table` | YES | NO |
|
||||
| `list` | `table` | YES | NO |
|
||||
| `dict` | `table` | YES | NO |
|
||||
| `lua.Table` | `table` | YES | YES |
|
||||
| `lua.Function`| `function`| NO | YES |
|
||||
|
||||
### Example
|
||||
```cpp
|
||||
#include "lua_bridge.hpp"
|
||||
|
||||
using namespace pkpy;
|
||||
|
||||
int main(){
|
||||
VM* vm = new VM();
|
||||
|
||||
// create lua state
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
|
||||
// initialize lua bridge
|
||||
initialize_lua_bridge(vm, L);
|
||||
|
||||
// dostring to get _G
|
||||
vm->exec("import lua");
|
||||
vm->exec("g = lua.dostring('return _G')");
|
||||
|
||||
// create a table
|
||||
vm->exec("t = lua.Table()");
|
||||
vm->exec("t.a = 1");
|
||||
vm->exec("t.b = 2");
|
||||
|
||||
// call lua function
|
||||
vm->exec("g.print(t.a + t.b)"); // 3
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
342
dependencies/pocketpy/docs/cheatsheet.md
vendored
Normal file
342
dependencies/pocketpy/docs/cheatsheet.md
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
---
|
||||
icon: log
|
||||
title: 'Cheatsheet'
|
||||
order: 22
|
||||
---
|
||||
|
||||
## Basics
|
||||
|
||||
Setup pocketpy
|
||||
|
||||
```cpp
|
||||
#include "pocketpy.h"
|
||||
using namespace pkpy;
|
||||
```
|
||||
|
||||
Create a python virtual machine
|
||||
|
||||
```cpp
|
||||
VM* vm = new VM();
|
||||
```
|
||||
|
||||
Dispose a python virtual machine
|
||||
|
||||
```cpp
|
||||
delete vm;
|
||||
```
|
||||
|
||||
Execute a source string
|
||||
|
||||
```cpp
|
||||
vm->exec("print('Hello!')");
|
||||
```
|
||||
|
||||
Evaluate a source string
|
||||
|
||||
```cpp
|
||||
PyObject* obj = vm->eval("123");
|
||||
std::cout << py_cast<int>(vm, obj); // 123
|
||||
```
|
||||
|
||||
Compile a source string into a code object
|
||||
|
||||
```cpp
|
||||
CodeObject_ co = vm->compile("print('Hello!')", "main.py", EXEC_MODE);
|
||||
```
|
||||
|
||||
Execute a compiled code object
|
||||
|
||||
```cpp
|
||||
try{
|
||||
vm->_exec(co); // may throw
|
||||
}catch(Exception& e){
|
||||
std::cerr << e.summary() << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
## Interop with native types
|
||||
|
||||
Create primitive objects
|
||||
|
||||
```cpp
|
||||
PyObject* obj;
|
||||
obj = py_var(vm, 1); // create a int
|
||||
obj = py_var(vm, 1.0); // create a float
|
||||
obj = py_var(vm, "123"); // create a string
|
||||
obj = py_var(vm, true); // create a bool
|
||||
```
|
||||
|
||||
Create a tuple object
|
||||
|
||||
```cpp
|
||||
// obj = (1, 1.0, '123')
|
||||
Tuple t(3);
|
||||
t[0] = py_var(vm, 1);
|
||||
t[1] = py_var(vm, 1.0);
|
||||
t[2] = py_var(vm, "123");
|
||||
PyObject* obj = py_var(vm, std::move(t));
|
||||
```
|
||||
|
||||
Create a list object
|
||||
|
||||
```cpp
|
||||
// obj = [1, 1.0, '123']
|
||||
List t;
|
||||
t.push_back(py_var(vm, 1));
|
||||
t.push_back(py_var(vm, 1.0));
|
||||
t.push_back(py_var(vm, "123"));
|
||||
PyObject* obj = py_var(vm, std::move(t));
|
||||
```
|
||||
|
||||
Create a dict object
|
||||
|
||||
```cpp
|
||||
// obj = {'x': 1, 'y': '123'}
|
||||
Dict d(vm);
|
||||
d.set(py_var(vm, "x"), py_var(vm, 1));
|
||||
d.set(py_var(vm, "y"), py_var(vm, "123"));
|
||||
PyObject* obj = py_var(vm, std::move(d));
|
||||
```
|
||||
|
||||
Get native types from python objects
|
||||
|
||||
```cpp
|
||||
PyObject* obj;
|
||||
i64 a = py_cast<i64>(vm, obj);
|
||||
f64 b = py_cast<f64>(vm, obj);
|
||||
Str& c = py_cast<Str&>(vm, obj); // reference cast
|
||||
bool d = py_cast<bool>(vm, obj);
|
||||
|
||||
Tuple& e = py_cast<Tuple&>(vm, obj); // reference cast
|
||||
List& f = py_cast<List&>(vm, obj); // reference cast
|
||||
Dict& g = py_cast<Dict&>(vm, obj); // reference cast
|
||||
```
|
||||
|
||||
Get native types without type checking
|
||||
|
||||
```cpp
|
||||
// unsafe version 1 (for int and float you must use `_py_cast`)
|
||||
i64 a = _py_cast<i64>(vm, obj);
|
||||
f64 b = _py_cast<f64>(vm, obj);
|
||||
Tuple& c = _py_cast<Tuple&>(vm, obj);
|
||||
// unsafe version 2 (for others, you can use both versions)
|
||||
Str& a_ = PK_OBJ_GET(Str, obj);
|
||||
List& b_ = PK_OBJ_GET(List, obj);
|
||||
Tuple& c_ = PK_OBJ_GET(Tuple, obj);
|
||||
```
|
||||
|
||||
## Access python types
|
||||
|
||||
Access built-in python types
|
||||
|
||||
```cpp
|
||||
PyObject* int_t = vm->_t(vm->tp_int);
|
||||
PyObject* float_t = vm->_t(vm->tp_float);
|
||||
PyObject* object_t = vm->_t(vm->tp_object);
|
||||
PyObject* tuple_t = vm->_t(vm->tp_tuple);
|
||||
PyObject* list_t = vm->_t(vm->tp_list);
|
||||
```
|
||||
|
||||
Access extended python types
|
||||
|
||||
```cpp
|
||||
// VoidP was defined by `PY_CLASS` macro
|
||||
PyObject* voidp_t = VoidP::_type(vm);
|
||||
```
|
||||
|
||||
Check if an object is a python type
|
||||
|
||||
```cpp
|
||||
PyObject* obj;
|
||||
bool ok = is_type(obj, vm->tp_int); // check if obj is an int
|
||||
```
|
||||
|
||||
Get the type of a python object
|
||||
|
||||
```cpp
|
||||
PyObject* obj = py_var(vm, 1);
|
||||
PyObject* t = vm->_t(obj); // <class 'int'>
|
||||
```
|
||||
|
||||
Convert a type object into a type index
|
||||
|
||||
```cpp
|
||||
PyObject* int_t = vm->_t(vm->tp_int);
|
||||
Type t = PK_OBJ_GET(Type, int_t);
|
||||
// t == vm->tp_int
|
||||
```
|
||||
|
||||
## Access attributes
|
||||
|
||||
Check an object supports attribute access
|
||||
|
||||
```cpp
|
||||
PyObject* obj;
|
||||
bool ok = !is_tagged(obj) && obj->is_attr_valid();
|
||||
```
|
||||
|
||||
```python
|
||||
class MyClass:
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def sum(self):
|
||||
return self.x + self.y
|
||||
```
|
||||
|
||||
Get and set attributes
|
||||
|
||||
```cpp
|
||||
PyObject* obj = vm->exec("MyClass(1, 2)");
|
||||
PyObject* x = vm->getattr(obj, "x"); // obj.x
|
||||
vm->setattr(obj, "x", py_var(vm, 3)); // obj.x = 3
|
||||
```
|
||||
|
||||
## Call python functions
|
||||
|
||||
```python
|
||||
def add(a, b):
|
||||
return a + b
|
||||
```
|
||||
|
||||
Call a function
|
||||
|
||||
```cpp
|
||||
PyObject* f_add = vm->eval("add");
|
||||
PyObject* ret = vm->call(f_add, py_var(vm, 1), py_var(vm, 2));
|
||||
std::cout << py_cast<int>(vm, ret); // 3
|
||||
```
|
||||
|
||||
Call a method
|
||||
|
||||
```cpp
|
||||
PyObject* obj = vm->exec("MyClass(1, 2)");
|
||||
PyObject* ret = vm->call_method(obj, "sum");
|
||||
std::cout << CAST(i64, ret); // 3
|
||||
```
|
||||
|
||||
Cache the name of a function or method to avoid string-based lookup
|
||||
|
||||
```cpp
|
||||
// cache the name "add" to avoid string-based lookup
|
||||
const static StrName m_sum("sum");
|
||||
PyObject* ret = vm->call_method(obj, m_sum);
|
||||
```
|
||||
|
||||
## Special operations
|
||||
|
||||
Compare two python objects
|
||||
|
||||
```cpp
|
||||
PyObject* obj1 = py_var(vm, 1);
|
||||
PyObject* obj2 = py_var(vm, 2);
|
||||
bool ok = vm->py_eq(obj1, obj2);
|
||||
```
|
||||
|
||||
Convert a python object to string
|
||||
|
||||
```cpp
|
||||
PyObject* obj = py_var(vm, 123);
|
||||
PyObject* s = vm->py_str(obj); // 123
|
||||
```
|
||||
|
||||
Get the string representation of a python object
|
||||
|
||||
```cpp
|
||||
PyObject* obj = py_var(vm, "123");
|
||||
std::cout << vm->py_repr(obj); // '123'
|
||||
```
|
||||
|
||||
Get the JSON representation of a python object
|
||||
|
||||
```cpp
|
||||
PyObject* obj = py_var(vm, 123);
|
||||
std::cout << vm->py_json(obj); // "123"
|
||||
```
|
||||
|
||||
Get the hash value of a python object
|
||||
|
||||
```cpp
|
||||
PyObject* obj = py_var(vm, 1);
|
||||
i64 h = vm->py_hash(obj); // 1
|
||||
```
|
||||
|
||||
Get the iterator of a python object
|
||||
|
||||
```cpp
|
||||
PyObject* obj = vm->eval("range(3)");
|
||||
PyObject* iter = vm->py_iter(obj);
|
||||
```
|
||||
|
||||
Get the next item of an iterator
|
||||
|
||||
```cpp
|
||||
PyObject* obj = vm->py_next(iter);
|
||||
if(obj == vm->StopIteration){
|
||||
// end of iteration
|
||||
}
|
||||
```
|
||||
|
||||
Convert a python iterable to a list
|
||||
|
||||
```cpp
|
||||
PyObject* obj = vm->eval("range(3)");
|
||||
PyObject* list = vm->py_list(obj);
|
||||
```
|
||||
|
||||
## Bindings
|
||||
|
||||
Bind a native function
|
||||
|
||||
```cpp
|
||||
vm->bind(obj, "add(a: int, b: int) -> int", [](VM* vm, ArgsView args){
|
||||
int a = py_cast<int>(vm, args[0]);
|
||||
int b = py_cast<int>(vm, args[1]);
|
||||
return py_var(vm, a + b);
|
||||
});
|
||||
|
||||
// Bind a native function with docstring
|
||||
|
||||
vm->bind(obj,
|
||||
"add(a: int, b: int) -> int",
|
||||
"add two integers", [](VM* vm, ArgsView args){
|
||||
int a = py_cast<int>(vm, args[0]);
|
||||
int b = py_cast<int>(vm, args[1]);
|
||||
return py_var(vm, a + b);
|
||||
});
|
||||
```
|
||||
|
||||
Bind a property
|
||||
|
||||
```cpp
|
||||
// getter and setter of property `x`
|
||||
vm->bind_property(type, "x: int",
|
||||
[](VM* vm, ArgsView args){
|
||||
Point& self = PK_OBJ_GET(Point, args[0]);
|
||||
return VAR(self.x);
|
||||
},
|
||||
[](VM* vm, ArgsView args){
|
||||
Point& self = PK_OBJ_GET(Point, args[0]);
|
||||
self.x = py_cast<int>(vm, args[1]);
|
||||
return vm->None;
|
||||
});
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
Create a source module
|
||||
|
||||
```cpp
|
||||
vm->_lazy_modules["test"] = "pi = 3.14";
|
||||
// import test
|
||||
// print(test.pi) # 3.14
|
||||
```
|
||||
|
||||
Create a native module
|
||||
|
||||
```cpp
|
||||
PyObject* mod = vm->new_module("test");
|
||||
vm->setattr(mod, "pi", py_var(vm, 3.14));
|
||||
```
|
||||
|
||||
106
dependencies/pocketpy/docs/coding_style_guide.md
vendored
Normal file
106
dependencies/pocketpy/docs/coding_style_guide.md
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
---
|
||||
icon: book
|
||||
order: -5
|
||||
label: Coding Style Guide
|
||||
---
|
||||
|
||||
# Coding Style Guide
|
||||
|
||||
|
||||
## For Python
|
||||
|
||||
Use [PEP-8](https://www.python.org/dev/peps/pep-0008/) as the coding style guide.
|
||||
|
||||
## For C++
|
||||
|
||||
### Naming rules
|
||||
|
||||
For class names, always use **PascalCase**
|
||||
|
||||
```cpp
|
||||
// Correct
|
||||
class FooBar {};
|
||||
|
||||
// Wrong
|
||||
class fooBar {};
|
||||
class foo_bar {};
|
||||
```
|
||||
|
||||
For function and methods, use **snake_case**
|
||||
|
||||
```cpp
|
||||
// Correct
|
||||
int test_func(int x) { return x+1; }
|
||||
|
||||
// Wrong
|
||||
int TestFunc(int x) { return x+1; }
|
||||
int testFunc(int x) { return x+1; }
|
||||
```
|
||||
|
||||
For special python objects, use the same name as in python.
|
||||
|
||||
```cpp
|
||||
auto x = vm->None;
|
||||
vm->SyntaxError(...);
|
||||
vm->TypeError(...);
|
||||
vm->call(obj, __repr__);
|
||||
```
|
||||
|
||||
For global constants, use **k** prefix with **PascalCase**
|
||||
|
||||
```cpp
|
||||
const int kMaxCount = 10;
|
||||
const float kMinValue = 1.0;
|
||||
```
|
||||
|
||||
For macros, use **SNAKE_CASE**
|
||||
|
||||
```cpp
|
||||
#define FOO_BAR 1
|
||||
#define TEST(x) x+1
|
||||
```
|
||||
|
||||
### Access control
|
||||
|
||||
Please use python style access control.
|
||||
|
||||
We do not recommend to use C++ keywords such as `private` or `public` to achieve access control. Also do not write any trivial setter/getter.
|
||||
|
||||
Use a single `_` as prefix to indicate a function or variable is for internal use.
|
||||
|
||||
```cpp
|
||||
class FooBar {
|
||||
public:
|
||||
int _count;
|
||||
int inc() { _count+=1; }
|
||||
void _clear() { _count=0; }
|
||||
}
|
||||
```
|
||||
|
||||
`_` prefix is just a warning to remind you to use such members carefully.
|
||||
|
||||
It does not forbid users to access internal members.
|
||||
|
||||
### Use compact style
|
||||
|
||||
Try to make the code compact if it does not affect readability.
|
||||
|
||||
```cpp
|
||||
// Correct
|
||||
if(x == 1) break;
|
||||
|
||||
// Wrong
|
||||
if(x == 1){
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
### For `std::shared_ptr<T>`
|
||||
|
||||
Use a `_` suffix to indicate a type is a shared pointer.
|
||||
|
||||
```cpp
|
||||
using CodeObject_ = std::shared_ptr<CodeObject>;
|
||||
CodeObject_ co = std::make_shared<CodeObject>();
|
||||
```
|
||||
|
||||
92
dependencies/pocketpy/docs/features/basic.md
vendored
Normal file
92
dependencies/pocketpy/docs/features/basic.md
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Basic Features
|
||||
order: 100
|
||||
---
|
||||
|
||||
Check this [Cheatsheet](https://reference.pocketpy.dev/python.html)
|
||||
for a quick overview of the supported features.
|
||||
|
||||
The following table shows the basic features of pkpy with respect to [cpython](https://github.com/python/cpython).
|
||||
The features marked with `YES` are supported, and the features marked with `NO` are not supported.
|
||||
|
||||
| Name | Example | Supported |
|
||||
| --------------- | ------------------------------- | --------- |
|
||||
| If Else | `if..else..elif` | YES |
|
||||
| Loop | `for/while/break/continue` | YES |
|
||||
| Function | `def f(x,*args,y=1):` | YES |
|
||||
| Subclass | `class A(B):` | YES |
|
||||
| List | `[1, 2, 'a']` | YES |
|
||||
| ListComp | `[i for i in range(5)]` | YES |
|
||||
| Slice | `a[1:2], a[:2], a[1:]` | YES |
|
||||
| Tuple | `(1, 2, 'a')` | YES |
|
||||
| Dict | `{'a': 1, 'b': 2}` | YES |
|
||||
| F-String | `f'value is {x}'` | YES |
|
||||
| Unpacking | `a, b = 1, 2` | YES |
|
||||
| Star Unpacking | `a, *b = [1, 2, 3]` | YES |
|
||||
| Exception | `raise/try..catch..finally` | YES |
|
||||
| Dynamic Code | `eval()/exec()` | YES |
|
||||
| Reflection | `hasattr()/getattr()/setattr()` | YES |
|
||||
| Import | `import/from..import` | YES |
|
||||
| Context Block | `with <expr> as <id>:` | YES |
|
||||
| Type Annotation | `def f(a:int, b:float=1)` | YES |
|
||||
| Generator | `yield i` | YES |
|
||||
| Decorator | `@cache` | YES |
|
||||
|
||||
## Supported magic methods
|
||||
|
||||
#### Unary operators
|
||||
|
||||
+ `__repr__`
|
||||
+ `__str__`
|
||||
+ `__hash__`
|
||||
+ `__len__`
|
||||
+ `__iter__`
|
||||
+ `__next__`
|
||||
+ `__neg__`
|
||||
|
||||
#### Logical operators
|
||||
|
||||
+ `__eq__`
|
||||
+ `__lt__`
|
||||
+ `__le__`
|
||||
+ `__gt__`
|
||||
+ `__ge__`
|
||||
+ `__contains__`
|
||||
|
||||
#### Binary operators
|
||||
|
||||
+ `__add__`
|
||||
+ `__radd__`
|
||||
+ `__sub__`
|
||||
+ `__rsub__`
|
||||
+ `__mul__`
|
||||
+ `__rmul__`
|
||||
+ `__truediv__`
|
||||
+ `__floordiv__`
|
||||
+ `__mod__`
|
||||
+ `__pow__`
|
||||
+ `__matmul__`
|
||||
+ `__lshift__`
|
||||
+ `__rshift__`
|
||||
+ `__and__`
|
||||
+ `__or__`
|
||||
+ `__xor__`
|
||||
+ `__invert__`
|
||||
|
||||
#### Indexer
|
||||
|
||||
+ `__getitem__`
|
||||
+ `__setitem__`
|
||||
+ `__delitem__`
|
||||
|
||||
#### Specials
|
||||
|
||||
+ `__new__`
|
||||
+ `__init__`
|
||||
+ `__call__`
|
||||
+ `__divmod__`
|
||||
+ `__enter__`
|
||||
+ `__exit__`
|
||||
+ `__name__`
|
||||
+ `__all__`
|
||||
24
dependencies/pocketpy/docs/features/debugging.md
vendored
Normal file
24
dependencies/pocketpy/docs/features/debugging.md
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Debugging
|
||||
---
|
||||
|
||||
!!!
|
||||
This feature is available in `v1.4.5` or higher.
|
||||
!!!
|
||||
|
||||
You can invoke `breakpoint()` in your python code to start a PDB-like session.
|
||||
|
||||
The following commands are supported:
|
||||
|
||||
+ `h, help`: show this help message
|
||||
+ `q, quit`: exit the debugger
|
||||
+ `n, next`: execute next line
|
||||
+ `s, step`: step into
|
||||
+ `w, where`: show current stack frame
|
||||
+ `c, continue`: continue execution
|
||||
+ `a, args`: show local variables
|
||||
+ `l, list`: show lines around current line
|
||||
+ `ll, longlist`: show all lines
|
||||
+ `p, print <expr>`: evaluate expression
|
||||
+ `!, execute statement`: execute statement
|
||||
42
dependencies/pocketpy/docs/features/differences.md
vendored
Normal file
42
dependencies/pocketpy/docs/features/differences.md
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Comparison with CPython
|
||||
order: 99
|
||||
---
|
||||
|
||||
[cpython](https://github.com/python/cpython) is the reference implementation of the Python programming language. It is written in C and is the most widely used implementation of Python.
|
||||
|
||||
## The design goal
|
||||
|
||||
**pkpy aims to be an alternative to lua for
|
||||
game scripting, not cpython for general purpose programming.**
|
||||
|
||||
+ For syntax and semantics, pkpy is designed to be as close to cpython as possible.
|
||||
+ For ecosystem and others, pkpy is not compatible with cpython.
|
||||
|
||||
pkpy supports most of the syntax and semantics of python.
|
||||
For performance and simplicity, some features are not implemented, or behave differently.
|
||||
The easiest way to test a feature is to [try it on your browser](https://pocketpy.dev/static/web/).
|
||||
|
||||
## Unimplemented features
|
||||
|
||||
1. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
|
||||
2. `__slots__` in class definition.
|
||||
3. `else` clause in try..except.
|
||||
4. Inplace methods like `__iadd__` and `__imul__`.
|
||||
5. `__del__` in class definition.
|
||||
6. Multiple inheritance.
|
||||
|
||||
## Different behaviors
|
||||
|
||||
1. positional and keyword arguments are strictly evaluated.
|
||||
2. `++i` and `--j` is an increment/decrement statement, not an expression.
|
||||
3. `int` does not derive from `bool`.
|
||||
4. `int` is 64-bit. You can use `long` type explicitly for arbitrary sized integers.
|
||||
5. `__ne__` is not required. Define `__eq__` is enough.
|
||||
6. Raw string cannot have boundary quotes in it, even escaped. See [#55](https://github.com/pocketpy/pocketpy/issues/55).
|
||||
7. In a starred unpacked assignment, e.g. `a, b, *c = x`, the starred variable can only be presented in the last position. `a, *b, c = x` is not supported.
|
||||
8. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
|
||||
9. `%`, `&`, `//`, `^` and `|` for `int` behave the same as C, not python.
|
||||
10. `str.split` and `str.splitlines` will remove all empty entries.
|
||||
11. `__getattr__`, `__setattr__` and `__delattr__` can only be set in cpp.
|
||||
30
dependencies/pocketpy/docs/features/goto.md
vendored
Normal file
30
dependencies/pocketpy/docs/features/goto.md
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Goto Statement
|
||||
---
|
||||
|
||||
pkpy supports goto/label just like C. You are allowed to **change the control flow unconditionally**.
|
||||
|
||||
## Define a label
|
||||
|
||||
```
|
||||
== <identifier> ==
|
||||
```
|
||||
|
||||
## Goto a label
|
||||
|
||||
```
|
||||
-> <identifier>
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```python
|
||||
for i in range(10):
|
||||
for j in range(10):
|
||||
for k in range(10):
|
||||
-> exit
|
||||
|
||||
== exit ==
|
||||
print('exit')
|
||||
```
|
||||
23
dependencies/pocketpy/docs/features/incdec.md
vendored
Normal file
23
dependencies/pocketpy/docs/features/incdec.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Increment Statement
|
||||
---
|
||||
|
||||
pkpy provides `++i` and `--j` statements to operate a simple named `int` variable.
|
||||
|
||||
+ `++i` is equivalent to `i+=1`, but much faster
|
||||
+ `--j` is equivalent to `j-=1`, but much faster
|
||||
|
||||
## Example
|
||||
|
||||
```python
|
||||
a = 1
|
||||
++a
|
||||
assert a == 2
|
||||
|
||||
def f(a):
|
||||
--a
|
||||
return a
|
||||
|
||||
assert f(3) == 2
|
||||
```
|
||||
3
dependencies/pocketpy/docs/features/index.yml
vendored
Normal file
3
dependencies/pocketpy/docs/features/index.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
icon: star
|
||||
order: 16
|
||||
label: "Features"
|
||||
27
dependencies/pocketpy/docs/features/long.md
vendored
Normal file
27
dependencies/pocketpy/docs/features/long.md
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Arbitrary Sized Integers
|
||||
---
|
||||
|
||||
Unlike cpython, pkpy's `int` is of limited precision (64-bit).
|
||||
|
||||
For arbitrary sized integers, we provide a builtin `long` type, just like python2's `long`.
|
||||
`long` is implemented via pure python in [_long.py](https://github.com/pocketpy/pocketpy/blob/main/python/_long.py).
|
||||
|
||||
### Create a long object
|
||||
|
||||
You can use `L` suffix to create a `long` literal from a decimal literal.
|
||||
Also, you can use `long()` function to create a `long` object from a `int` object or a `str` object.
|
||||
|
||||
```python
|
||||
a = 1000L
|
||||
b = long(1000)
|
||||
c = long('1000')
|
||||
assert a == b == c
|
||||
```
|
||||
|
||||
```python
|
||||
a = 2L # use `L` suffix to create a `long` object
|
||||
print(a ** 1000)
|
||||
# 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376L
|
||||
```
|
||||
145
dependencies/pocketpy/docs/features/precompile.md
vendored
Normal file
145
dependencies/pocketpy/docs/features/precompile.md
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Precompiling
|
||||
---
|
||||
|
||||
pkpy allows you to precompile python code into two special forms, which can be executed later.
|
||||
|
||||
### In-memory precompilation
|
||||
|
||||
You can use `vm->compile` to compile your source code into a `CodeObject_` object.
|
||||
This object can be executed later by `vm->_exec`.
|
||||
|
||||
```cpp
|
||||
CodeObject_ code = vm->compile("print('Hello, world!')", "<string>", EXEC_MODE);
|
||||
vm->_exec(code); // Hello, world!
|
||||
```
|
||||
|
||||
This `CodeObject_` object is a very non-generic form of the compiled code,
|
||||
which is an in-memory form. Very efficient, but not portable.
|
||||
You are not able to save it to a file or load it from a file.
|
||||
|
||||
|
||||
### String precompilation
|
||||
|
||||
In order to save the compiled code to a file, you need to use `vm->precompile`.
|
||||
It does some basic preprocessing and outputs the result as a human-readable string.
|
||||
|
||||
```cpp
|
||||
// precompile the source code into a string
|
||||
Str source = vm->precompile("print('Hello, world!')", "<string>", EXEC_MODE);
|
||||
|
||||
CodeObject code = vm->compile(source, "<string>", EXEC_MODE);
|
||||
vm->_exec(code); // Hello, world!
|
||||
```
|
||||
|
||||
You can also use python's `compile` function to achieve the same effect.
|
||||
|
||||
```python
|
||||
code = compile("print('Hello, world!')", "<string>", "exec")
|
||||
exec(code) # Hello, world!
|
||||
```
|
||||
|
||||
Let's take a look at the precompiled string.
|
||||
```python
|
||||
print(code)
|
||||
```
|
||||
|
||||
```txt
|
||||
pkpy:1.4.5
|
||||
0
|
||||
=1
|
||||
print
|
||||
=6
|
||||
5,1,0,
|
||||
6,0,,,
|
||||
42,,1,
|
||||
8,,,S48656c6c6f2c20776f726c6421
|
||||
43,,0,
|
||||
3,,,
|
||||
|
||||
```
|
||||
|
||||
Comparing with **In-memory precompilation**,
|
||||
**String precompilation** drops most of the information of the original source code.
|
||||
It has an encryption effect, which can protect your source code from being stolen.
|
||||
This also means there is no source line information when an error occurs.
|
||||
|
||||
```python
|
||||
src = """
|
||||
def f(a, b):
|
||||
return g(a, b)
|
||||
|
||||
def g(a, b):
|
||||
c = f(a, b)
|
||||
d = g(a, b)
|
||||
return c + d
|
||||
"""
|
||||
|
||||
code = compile(src, "<exec>", "exec")
|
||||
exec(code)
|
||||
f(1, 2)
|
||||
```
|
||||
|
||||
You will get this (without source line information):
|
||||
```txt
|
||||
Traceback (most recent call last):
|
||||
File "<exec>", line 3, in f
|
||||
File "<exec>", line 6, in g
|
||||
File "<exec>", line 3, in f
|
||||
File "<exec>", line 6, in g
|
||||
File "<exec>", line 3, in f
|
||||
File "<exec>", line 6, in g
|
||||
File "<exec>", line 3, in f
|
||||
StackOverflowError
|
||||
```
|
||||
|
||||
instead of this (with source line information):
|
||||
|
||||
```txt
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 2, in f
|
||||
return g(a, b)
|
||||
File "<stdin>", line 2, in g
|
||||
c = f(a, b)
|
||||
File "<stdin>", line 2, in f
|
||||
return g(a, b)
|
||||
File "<stdin>", line 2, in g
|
||||
c = f(a, b)
|
||||
File "<stdin>", line 2, in f
|
||||
return g(a, b)
|
||||
File "<stdin>", line 2, in g
|
||||
c = f(a, b)
|
||||
File "<stdin>", line 2, in f
|
||||
return g(a, b)
|
||||
StackOverflowError
|
||||
```
|
||||
|
||||
!!!
|
||||
String compilation has no guarantee of compatibility between different versions of pkpy.
|
||||
!!!
|
||||
|
||||
You can use this snnipet to convert every python file in a directory into precompiled strings.
|
||||
|
||||
```python
|
||||
# precompile.py
|
||||
import sys, os
|
||||
|
||||
def precompile(filepath: str):
|
||||
"""Precompile a python file inplace"""
|
||||
print(filepath)
|
||||
with open(filepath, 'r') as f:
|
||||
source = f.read()
|
||||
source = compile(source, filepath, 'exec')
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(source)
|
||||
|
||||
def traverse(root: str):
|
||||
"""Traverse a directory and precompile every python file"""
|
||||
for entry in os.listdir(root):
|
||||
entrypath = os.path.join(root, entry)
|
||||
if os.path.isdir(entrypath):
|
||||
traverse(entrypath)
|
||||
elif entrypath.endswith(".py"):
|
||||
precompile(entrypath)
|
||||
```
|
||||
12
dependencies/pocketpy/docs/features/ub.md
vendored
Normal file
12
dependencies/pocketpy/docs/features/ub.md
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Undefined Behaviour
|
||||
---
|
||||
|
||||
These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined if you do the following things.
|
||||
|
||||
1. Delete a builtin object. For example, `del int.__add__`.
|
||||
2. Call an unbound method with the wrong type of `self`. For example, `int.__add__('1', 2)`.
|
||||
3. Type `T`'s `__new__` returns an object that is not an instance of `T`.
|
||||
4. Call `__new__` with a type that is not a subclass of `type`.
|
||||
5. `__eq__`, `__lt__` or `__contains__`, etc.. returns a value that is not a boolean.
|
||||
58
dependencies/pocketpy/docs/gsoc/guide.md
vendored
Normal file
58
dependencies/pocketpy/docs/gsoc/guide.md
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
icon: rocket
|
||||
order: 10
|
||||
label: "Application Guide"
|
||||
---
|
||||
|
||||
Before starting, please read the [Ideas](ideas.md) page and choose a project you are interested in.
|
||||
Set up a C++ compiler, clone pocketpy sources from github and try to build.
|
||||
This helps you confirm that your skills and experience match the requirements of the project.
|
||||
|
||||
### Build guide for beginners
|
||||
|
||||
First, you need to install these tools:
|
||||
|
||||
1. Python(>= 3.8), I am sure you already have it.
|
||||
2. A C++ compiler, such as GCC, Clang or MSVC. If you are on Linux, `gcc` and `g++` are already installed. If you are on Windows, you can install Visual Studio with C++ development tools.
|
||||
3. CMake(>= 3.10), a cross-platform build tool. You can use `pip install cmake` to install it.
|
||||
|
||||
Then, clone pocketpy sources from github and try to build:
|
||||
```bash
|
||||
git clone https://github.com/pocketpy/pocketpy
|
||||
cd pocketpy
|
||||
|
||||
python cmake_build.py
|
||||
```
|
||||
|
||||
If everything goes well, you will get a `main` executable (`main.exe` on Windows) in the root directory of pocketpy.
|
||||
Simply run it and you will enter pocketpy's REPL.
|
||||
```txt
|
||||
pocketpy 1.4.0 (Jan 24 2024, 12:39:13) [32 bit] on emscripten
|
||||
https://github.com/pocketpy/pocketpy
|
||||
Type "exit()" to exit.
|
||||
>>>
|
||||
>>> "Hello, world"
|
||||
'Hello, world'
|
||||
```
|
||||
|
||||
### Application guide
|
||||
|
||||
**Your need to send an email to `blueloveth@foxmail.com` with the following information:**
|
||||
|
||||
1. A brief introduction about yourself, including the most related open sourced project you have worked on before. It is highly recommended to attach your Github profile link.
|
||||
2. A technical proposal for the project you are interested in working on, including:
|
||||
+ Your understanding of the project.
|
||||
+ The technical approach/architecture you will adopt.
|
||||
+ The challenges you might face and how you will overcome them.
|
||||
3. A timeline for the project, including the milestones and deliverables.
|
||||
4. Other information required by the Google Summer of Code program.
|
||||
|
||||
### Coding style guide
|
||||
|
||||
See [Coding Style Guide](../coding_style_guide.md).
|
||||
|
||||
### Contact us
|
||||
|
||||
If you have any questions, you can join our [Discord](https://discord.gg/WWaq72GzXv)
|
||||
or contact me via email.
|
||||
We are glad to help you with your application.
|
||||
40
dependencies/pocketpy/docs/gsoc/ideas.md
vendored
Normal file
40
dependencies/pocketpy/docs/gsoc/ideas.md
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
icon: light-bulb
|
||||
order: 0
|
||||
label: "Project Ideas"
|
||||
---
|
||||
|
||||
### Implement pybind11 for bindings
|
||||
|
||||
+ Difficulty Level: 5/5 (Hard)
|
||||
+ Skill: Advanced C++ with metaprogramming; Python
|
||||
+ Project Length: Medium (175 hours)
|
||||
|
||||
pocketpy has provided a low-level API for creating bindings. It is fast, lightweight and easy to debug.
|
||||
However, it still requires a lot of boilerplate code to create bindings for complex C++ classes.
|
||||
The community has long expected a high-level API for creating bindings.
|
||||
|
||||
[pybind11](https://github.com/pybind/pybind11)
|
||||
is the most popular C++ library for creating Python bindings for CPython. A bunch of Python libraries are using it. pybind11 adopts a template metaprogramming approach to automatically generate bindings for C++ classes.
|
||||
|
||||
Our goal is to introduce a pybind11 compatible solution to pocketpy as an alternative way to create bindings
|
||||
for functions and classes.
|
||||
You can use C\+\+17 features to implement it, instead of C++11 used in pybind11.
|
||||
|
||||
See https://github.com/pocketpy/pocketpy/issues/216 for more details.
|
||||
|
||||
### Add `numpy` module
|
||||
|
||||
+ Difficulty Level: 4/5 (Intermediate)
|
||||
+ Skill: Intermediate C++; Python; Linear Algebra
|
||||
+ Project Length: Medium (175 hours)
|
||||
|
||||
Though pocketpy is designed for game scripting,
|
||||
some people are using it for scientific computing.
|
||||
It would be nice to have a `numpy` module in pocketpy.
|
||||
|
||||
`numpy` is a huge project.
|
||||
Our goal is to implement a most commonly used subset of `numpy` in pocketpy.
|
||||
You can mix C++ and Python code to simplify the overall workloads.
|
||||
|
||||
See https://github.com/pocketpy/pocketpy/issues/202 for more details.
|
||||
2
dependencies/pocketpy/docs/gsoc/index.yml
vendored
Normal file
2
dependencies/pocketpy/docs/gsoc/index.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
order: 19
|
||||
label: "GSoC"
|
||||
55
dependencies/pocketpy/docs/index.md
vendored
Normal file
55
dependencies/pocketpy/docs/index.md
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
icon: home
|
||||
label: Welcome
|
||||
---
|
||||
|
||||
# Welcome to pocketpy
|
||||
|
||||
pkpy is a lightweight(~15K LOC) Python interpreter for game scripting, built on C++17 with STL.
|
||||
|
||||
It aims to be an alternative to lua for game scripting, with elegant syntax, powerful features and competitive performance.
|
||||
pkpy is extremely easy to embed via a single header file `pocketpy.h`, without external dependencies.
|
||||
|
||||
> **Caution**: pocketpy should not be your first C++ project. Please learn C++ programming, compiling, linking, and debugging before working with pocketpy. There are many resources for this on the net.
|
||||
|
||||
## What it looks like
|
||||
|
||||
```python
|
||||
def is_prime(x):
|
||||
if x < 2:
|
||||
return False
|
||||
for i in range(2, x):
|
||||
if x % i == 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
primes = [i for i in range(2, 20) if is_prime(i)]
|
||||
print(primes)
|
||||
# [2, 3, 5, 7, 11, 13, 17, 19]
|
||||
```
|
||||
|
||||
## Supported platforms
|
||||
|
||||
pkpy should work on any platform with a C++17 compiler.
|
||||
These platforms are officially tested.
|
||||
|
||||
+ Windows 64-bit
|
||||
+ Linux 64-bit / 32-bit
|
||||
+ macOS 64-bit
|
||||
+ Android 64-bit / 32-bit
|
||||
+ iOS 64-bit
|
||||
+ Emscripten 32-bit
|
||||
+ Raspberry Pi OS 64-bit
|
||||
|
||||
## Star the repo
|
||||
|
||||
If you find pkpy useful, consider [star this repository](https://github.com/blueloveth/pocketpy) (●'◡'●)
|
||||
|
||||
## Sponsor this project
|
||||
|
||||
You can sponsor this project via these ways.
|
||||
|
||||
+ [Github Sponsors](https://github.com/sponsors/blueloveTH)
|
||||
+ [Buy me a coffee](https://www.buymeacoffee.com/blueloveth)
|
||||
|
||||
Your sponsorship will help us develop pkpy continuously.
|
||||
33
dependencies/pocketpy/docs/license.md
vendored
Normal file
33
dependencies/pocketpy/docs/license.md
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
icon: verified
|
||||
order: -15
|
||||
label: License
|
||||
---
|
||||
|
||||
# License
|
||||
|
||||
pkpy is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 blueloveTH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
19
dependencies/pocketpy/docs/modules/array2d.md
vendored
Normal file
19
dependencies/pocketpy/docs/modules/array2d.md
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
icon: package
|
||||
label: array2d
|
||||
---
|
||||
|
||||
Efficient general-purpose 2D array.
|
||||
|
||||
https://github.com/pocketpy/pocketpy/blob/main/include/typings/array2d.pyi
|
||||
|
||||
## Example
|
||||
|
||||
```python
|
||||
from array2d import array2d
|
||||
|
||||
a = array2d(3, 4, default=0)
|
||||
|
||||
a[1, 2] = 5
|
||||
print(a[1, 2]) # 5
|
||||
```
|
||||
13
dependencies/pocketpy/docs/modules/base64.md
vendored
Normal file
13
dependencies/pocketpy/docs/modules/base64.md
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
icon: package
|
||||
label: base64
|
||||
---
|
||||
|
||||
### `base64.b64encode(b: bytes) -> bytes`
|
||||
|
||||
Encode bytes-like object `b` using the standard Base64 alphabet.
|
||||
|
||||
### `base64.b64decode(b: bytes) -> bytes`
|
||||
|
||||
Decode Base64 encoded bytes-like object `b`.
|
||||
|
||||
24
dependencies/pocketpy/docs/modules/bisect.md
vendored
Normal file
24
dependencies/pocketpy/docs/modules/bisect.md
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
icon: package
|
||||
label: bisect
|
||||
---
|
||||
|
||||
### `bisect.bisect_left(a, x)`
|
||||
|
||||
Return the index where to insert item `x` in list `a`, assuming `a` is sorted.
|
||||
|
||||
### `bisect.bisect_right(a, x)`
|
||||
|
||||
Return the index where to insert item `x` in list `a`, assuming `a` is sorted.
|
||||
|
||||
### `bisect.insort_left(a, x)`
|
||||
|
||||
Insert item `x` in list `a`, and keep it sorted assuming `a` is sorted.
|
||||
|
||||
If x is already in a, insert it to the left of the leftmost x.
|
||||
|
||||
### `bisect.insort_right(a, x)`
|
||||
|
||||
Insert item `x` in list `a`, and keep it sorted assuming `a` is sorted.
|
||||
|
||||
If x is already in a, insert it to the right of the rightmost x.
|
||||
8
dependencies/pocketpy/docs/modules/c.md
vendored
Normal file
8
dependencies/pocketpy/docs/modules/c.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
icon: package
|
||||
label: c
|
||||
---
|
||||
|
||||
Interop with pointers and C structs.
|
||||
|
||||
https://github.com/pocketpy/pocketpy/blob/main/include/typings/c.pyi
|
||||
12
dependencies/pocketpy/docs/modules/cmath.md
vendored
Normal file
12
dependencies/pocketpy/docs/modules/cmath.md
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
icon: package
|
||||
label: cmath
|
||||
---
|
||||
|
||||
!!!
|
||||
This module is experimental and may have bugs or other issues.
|
||||
!!!
|
||||
|
||||
Mathematical functions for complex numbers.
|
||||
|
||||
https://docs.python.org/3/library/cmath.html
|
||||
17
dependencies/pocketpy/docs/modules/collections.md
vendored
Normal file
17
dependencies/pocketpy/docs/modules/collections.md
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
icon: package
|
||||
label: collections
|
||||
---
|
||||
|
||||
|
||||
### `collections.Counter(iterable)`
|
||||
|
||||
Return a `dict` containing the counts of each element in `iterable`.
|
||||
|
||||
### `collections.deque`
|
||||
|
||||
A double-ended queue.
|
||||
|
||||
### `collections.defaultdict`
|
||||
|
||||
A dictionary that returns a default value when a key is not found.
|
||||
8
dependencies/pocketpy/docs/modules/colorsys.md
vendored
Normal file
8
dependencies/pocketpy/docs/modules/colorsys.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
icon: package
|
||||
label: colorsys
|
||||
---
|
||||
|
||||
The same as the standard library module `colorsys` in python 3.11.
|
||||
|
||||
https://github.com/python/cpython/blob/3.11/Lib/colorsys.py
|
||||
33
dependencies/pocketpy/docs/modules/csv.md
vendored
Normal file
33
dependencies/pocketpy/docs/modules/csv.md
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
icon: package
|
||||
label: csv
|
||||
---
|
||||
|
||||
### `csv.reader(csvfile: list[str]) -> list[list]`
|
||||
|
||||
Parse a CSV file into a list of lists.
|
||||
|
||||
### `csv.DictReader(csvfile: list[str]) -> list[dict]`
|
||||
|
||||
Parse a CSV file into a list of dictionaries.
|
||||
|
||||
## Example
|
||||
|
||||
```python
|
||||
import csv
|
||||
|
||||
data = """a,b,c
|
||||
1,2,3
|
||||
"""
|
||||
|
||||
print(csv.reader(data.splitlines()))
|
||||
# [
|
||||
# ['a', 'b', 'c'],
|
||||
# ['1', '2', '3']
|
||||
# ]
|
||||
|
||||
print(csv.DictReader(data.splitlines()))
|
||||
# [
|
||||
# {'a': '1', 'b': '2', 'c': '3'}
|
||||
# ]
|
||||
```
|
||||
14
dependencies/pocketpy/docs/modules/dataclasses.md
vendored
Normal file
14
dependencies/pocketpy/docs/modules/dataclasses.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
icon: package
|
||||
label: dataclasses
|
||||
---
|
||||
|
||||
### `dataclasses.dataclass`
|
||||
|
||||
A decorator that is used to add generated special method to classes, including `__init__`, `__repr__` and `__eq__`.
|
||||
|
||||
### `dataclasses.asdict(obj) -> dict`
|
||||
|
||||
Convert a dataclass instance to a dictionary.
|
||||
|
||||
|
||||
12
dependencies/pocketpy/docs/modules/datetime.md
vendored
Normal file
12
dependencies/pocketpy/docs/modules/datetime.md
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
icon: package
|
||||
label: datetime
|
||||
---
|
||||
|
||||
### `datetime.now()`
|
||||
|
||||
Returns the current date and time as a `datetime` object.
|
||||
|
||||
### `date.today()`
|
||||
|
||||
Returns the current local date as a `date` object.
|
||||
38
dependencies/pocketpy/docs/modules/easing.md
vendored
Normal file
38
dependencies/pocketpy/docs/modules/easing.md
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
icon: package
|
||||
label: easing
|
||||
---
|
||||
|
||||
Python wrapper for [easing functions](https://easings.net/).
|
||||
|
||||
+ `easing.Linear(t: float) -> float`
|
||||
+ `easing.InSine(t: float) -> float`
|
||||
+ `easing.OutSine(t: float) -> float`
|
||||
+ `easing.InOutSine(t: float) -> float`
|
||||
+ `easing.InQuad(t: float) -> float`
|
||||
+ `easing.OutQuad(t: float) -> float`
|
||||
+ `easing.InOutQuad(t: float) -> float`
|
||||
+ `easing.InCubic(t: float) -> float`
|
||||
+ `easing.OutCubic(t: float) -> float`
|
||||
+ `easing.InOutCubic(t: float) -> float`
|
||||
+ `easing.InQuart(t: float) -> float`
|
||||
+ `easing.OutQuart(t: float) -> float`
|
||||
+ `easing.InOutQuart(t: float) -> float`
|
||||
+ `easing.InQuint(t: float) -> float`
|
||||
+ `easing.OutQuint(t: float) -> float`
|
||||
+ `easing.InOutQuint(t: float) -> float`
|
||||
+ `easing.InExpo(t: float) -> float`
|
||||
+ `easing.OutExpo(t: float) -> float`
|
||||
+ `easing.InOutExpo(t: float) -> float`
|
||||
+ `easing.InCirc(t: float) -> float`
|
||||
+ `easing.OutCirc(t: float) -> float`
|
||||
+ `easing.InOutCirc(t: float) -> float`
|
||||
+ `easing.InBack(t: float) -> float`
|
||||
+ `easing.OutBack(t: float) -> float`
|
||||
+ `easing.InOutBack(t: float) -> float`
|
||||
+ `easing.InElastic(t: float) -> float`
|
||||
+ `easing.OutElastic(t: float) -> float`
|
||||
+ `easing.InOutElastic(t: float) -> float`
|
||||
+ `easing.InBounce(t: float) -> float`
|
||||
+ `easing.OutBounce(t: float) -> float`
|
||||
+ `easing.InOutBounce(t: float) -> float`
|
||||
24
dependencies/pocketpy/docs/modules/enum.md
vendored
Normal file
24
dependencies/pocketpy/docs/modules/enum.md
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
icon: package
|
||||
label: enum
|
||||
---
|
||||
|
||||
### `enum.Enum`
|
||||
|
||||
Base class for creating enumerated constants.
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
from enum import Enum
|
||||
|
||||
class Color(Enum):
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
BLUE = 3
|
||||
|
||||
print(Color.RED) # Color.RED
|
||||
print(Color.RED.name) # 'RED'
|
||||
print(Color.RED.value) # 1
|
||||
```
|
||||
|
||||
16
dependencies/pocketpy/docs/modules/functools.md
vendored
Normal file
16
dependencies/pocketpy/docs/modules/functools.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
icon: package
|
||||
label: functools
|
||||
---
|
||||
|
||||
### `functools.cache`
|
||||
|
||||
A decorator that caches a function's return value each time it is called. If called later with the same arguments, the cached value is returned, and not re-evaluated.
|
||||
|
||||
### `functools.reduce(function, sequence, initial=...)`
|
||||
|
||||
Apply a function of two arguments cumulatively to the items of a sequence, from left to right, so as to reduce the sequence to a single value. For example, `functools.reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])` calculates `((((1+2)+3)+4)+5)`. The left argument, `x`, is the accumulated value and the right argument, `y`, is the update value from the sequence. If the optional `initial` is present, it is placed before the items of the sequence in the calculation, and serves as a default when the sequence is empty.
|
||||
|
||||
### `functools.partial(f, *args, **kwargs)`
|
||||
|
||||
Return a new partial object which when called will behave like `f` called with the positional arguments `args` and keyword arguments `kwargs`. If more arguments are supplied to the call, they are appended to `args`. If additional keyword arguments are supplied, they extend and override `kwargs`.
|
||||
9
dependencies/pocketpy/docs/modules/gc.md
vendored
Normal file
9
dependencies/pocketpy/docs/modules/gc.md
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
icon: package
|
||||
label: gc
|
||||
---
|
||||
|
||||
|
||||
### `gc.collect()`
|
||||
|
||||
Invoke the garbage collector.
|
||||
24
dependencies/pocketpy/docs/modules/heapq.md
vendored
Normal file
24
dependencies/pocketpy/docs/modules/heapq.md
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
icon: package
|
||||
label: heapq
|
||||
---
|
||||
|
||||
### `heapq.heappush(heap, item)`
|
||||
|
||||
Push the value `item` onto the heap, maintaining the heap invariant.
|
||||
|
||||
### `heapq.heappop(heap)`
|
||||
|
||||
Pop and return the smallest item from the heap, maintaining the heap invariant. If the heap is empty, IndexError is raised. To access the smallest item without popping it, use `heap[0]`.
|
||||
|
||||
### `heapq.heapify(x)`
|
||||
|
||||
Transform list `x` into a heap, in-place, in linear time.
|
||||
|
||||
### `heapq.heappushpop(heap, item)`
|
||||
|
||||
Push `item` on the heap, then pop and return the smallest item from the heap. The combined action runs more efficiently than `heappush()` followed by a separate `heappop()`.
|
||||
|
||||
### `heapq.heapreplace(heap, item)`
|
||||
|
||||
Pop and return the smallest item from the heap, and also push the new item. The heap size doesn’t change. If the heap is empty, IndexError is raised.
|
||||
2
dependencies/pocketpy/docs/modules/index.yml
vendored
Normal file
2
dependencies/pocketpy/docs/modules/index.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
icon: package
|
||||
order: 10
|
||||
42
dependencies/pocketpy/docs/modules/io.md
vendored
Normal file
42
dependencies/pocketpy/docs/modules/io.md
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
---
|
||||
icon: package-dependencies
|
||||
label: io
|
||||
---
|
||||
|
||||
!!!
|
||||
This module is optional. Set `PK_ENABLE_OS` to `1` to enable it.
|
||||
!!!
|
||||
|
||||
### `io.FileIO.read(size=-1) -> bytes | str`
|
||||
|
||||
Read up to `size` bytes from the file. If `size` is negative or omitted, read until EOF.
|
||||
|
||||
### `io.FileIO.write(data: bytes | str)`
|
||||
|
||||
Write the given data to the file.
|
||||
|
||||
### `io.FileIO.seek(offset, whence=0) -> int`
|
||||
|
||||
Change the file position to the given offset. The `whence` argument is optional and defaults to `0` (absolute file positioning); other values are `1` (seek relative to the current position) and `2` (seek relative to the file's end).
|
||||
|
||||
### `io.FileIO.tell() -> int`
|
||||
|
||||
Return the current file position.
|
||||
|
||||
### `io.FileIO.close()`
|
||||
|
||||
Close the file.
|
||||
|
||||
|
||||
### `io.SEEK_SET`
|
||||
|
||||
Seek from the beginning of the file.
|
||||
|
||||
### `io.SEEK_CUR`
|
||||
|
||||
Seek from the current position.
|
||||
|
||||
### `io.SEEK_END`
|
||||
|
||||
Seek from the end of the file.
|
||||
|
||||
8
dependencies/pocketpy/docs/modules/itertools.md
vendored
Normal file
8
dependencies/pocketpy/docs/modules/itertools.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
icon: package
|
||||
label: itertools
|
||||
---
|
||||
|
||||
### `itertools.zip_longest(a, b)`
|
||||
|
||||
Returns an iterator that aggregates elements from the input iterables. If the input iterables are of different lengths, missing values are filled-in with `None`.
|
||||
19
dependencies/pocketpy/docs/modules/json.md
vendored
Normal file
19
dependencies/pocketpy/docs/modules/json.md
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
icon: package
|
||||
label: json
|
||||
---
|
||||
|
||||
pkpy has two JSON modules.
|
||||
1. The built-in JSON module is always available and can be imported via `import json`.
|
||||
2. After `v1.2.7`, you can set `PK_USE_CJSON` to `ON` in CMakeLists.txt to enable an alternative JSON module `cjson`.
|
||||
|
||||
**Their interfaces are the same.** `cjson` is faster while the built-in `json` is more stable since it was developed earlier.
|
||||
|
||||
### `json.loads(data: str | bytes)`
|
||||
|
||||
Decode a JSON string into a python object.
|
||||
|
||||
### `json.dumps(obj) -> str`
|
||||
|
||||
Encode a python object into a JSON string.
|
||||
|
||||
178
dependencies/pocketpy/docs/modules/linalg.md
vendored
Normal file
178
dependencies/pocketpy/docs/modules/linalg.md
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
---
|
||||
icon: package
|
||||
label: linalg
|
||||
---
|
||||
|
||||
Provide `mat3x3`, `vec2`, `vec3` and `vec4` types.
|
||||
|
||||
This classes adopt `torch`'s naming convention. Methods with `_` suffix will modify the instance itself.
|
||||
|
||||
https://github.com/pocketpy/pocketpy/blob/main/include/typings/linalg.pyi
|
||||
|
||||
```python
|
||||
from typing import overload
|
||||
from c import _StructLike, float_p
|
||||
|
||||
class vec2(_StructLike['vec2']):
|
||||
x: float
|
||||
y: float
|
||||
|
||||
def __init__(self, x: float, y: float) -> None: ...
|
||||
def __add__(self, other: vec2) -> vec2: ...
|
||||
def __sub__(self, other: vec2) -> vec2: ...
|
||||
|
||||
@overload
|
||||
def __mul__(self, other: float) -> vec2: ...
|
||||
@overload
|
||||
def __mul__(self, other: vec2) -> vec2: ...
|
||||
|
||||
def __rmul__(self, other: float) -> vec2: ...
|
||||
def __truediv__(self, other: float) -> vec2: ...
|
||||
def dot(self, other: vec2) -> float: ...
|
||||
def cross(self, other: vec2) -> float: ...
|
||||
def length(self) -> float: ...
|
||||
def length_squared(self) -> float: ...
|
||||
def normalize(self) -> vec2: ...
|
||||
def rotate(self, radians: float) -> vec2: ...
|
||||
|
||||
def copy_(self, other: vec2) -> None: ...
|
||||
def normalize_(self) -> None: ...
|
||||
def rotate_(self, radians: float) -> None: ...
|
||||
|
||||
@staticmethod
|
||||
def angle(__from: vec2, __to: vec2) -> float:
|
||||
"""Returns the angle in radians between vectors `from` and `to`.
|
||||
|
||||
The result range is `[-pi, pi]`.
|
||||
|
||||
+ if y axis is top to bottom, positive value means clockwise
|
||||
+ if y axis is bottom to top, positive value means counter-clockwise
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2:
|
||||
...
|
||||
|
||||
class vec3(_StructLike['vec3']):
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
|
||||
def __init__(self, x: float, y: float, z: float) -> None: ...
|
||||
def __add__(self, other: vec3) -> vec3: ...
|
||||
def __sub__(self, other: vec3) -> vec3: ...
|
||||
|
||||
@overload
|
||||
def __mul__(self, other: float) -> vec3: ...
|
||||
@overload
|
||||
def __mul__(self, other: vec3) -> vec3: ...
|
||||
|
||||
def __rmul__(self, other: float) -> vec3: ...
|
||||
def __truediv__(self, other: float) -> vec3: ...
|
||||
def dot(self, other: vec3) -> float: ...
|
||||
def cross(self, other: vec3) -> float: ...
|
||||
def length(self) -> float: ...
|
||||
def length_squared(self) -> float: ...
|
||||
def normalize(self) -> vec3: ...
|
||||
|
||||
def copy_(self, other: vec3) -> None: ...
|
||||
def normalize_(self) -> None: ...
|
||||
|
||||
class vec4(_StructLike['vec4']):
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
w: float
|
||||
|
||||
def __init__(self, x: float, y: float, z: float, w: float) -> None: ...
|
||||
def __add__(self, other: vec4) -> vec4: ...
|
||||
def __sub__(self, other: vec4) -> vec4: ...
|
||||
|
||||
@overload
|
||||
def __mul__(self, other: float) -> vec4: ...
|
||||
@overload
|
||||
def __mul__(self, other: vec4) -> vec4: ...
|
||||
|
||||
def __rmul__(self, other: float) -> vec4: ...
|
||||
def __truediv__(self, other: float) -> vec4: ...
|
||||
def dot(self, other: vec4) -> float: ...
|
||||
def length(self) -> float: ...
|
||||
def length_squared(self) -> float: ...
|
||||
def normalize(self) -> vec4: ...
|
||||
|
||||
def copy_(self, other: vec4) -> None: ...
|
||||
def normalize_(self) -> None: ...
|
||||
|
||||
class mat3x3(_StructLike['mat3x3']):
|
||||
_11: float
|
||||
_12: float
|
||||
_13: float
|
||||
_21: float
|
||||
_22: float
|
||||
_23: float
|
||||
_31: float
|
||||
_32: float
|
||||
_33: float
|
||||
|
||||
@overload
|
||||
def __init__(self) -> None: ...
|
||||
@overload
|
||||
def __init__(self, _11, _12, _13, _21, _22, _23, _31, _32, _33) -> None: ...
|
||||
@overload
|
||||
def __init__(self, a: list[float]): ...
|
||||
|
||||
def determinant(self) -> float: ...
|
||||
def invert(self) -> mat3x3: ...
|
||||
def transpose(self) -> mat3x3: ...
|
||||
|
||||
def __getitem__(self, index: tuple[int, int]) -> float: ...
|
||||
def __setitem__(self, index: tuple[int, int], value: float) -> None: ...
|
||||
def __add__(self, other: mat3x3) -> mat3x3: ...
|
||||
def __sub__(self, other: mat3x3) -> mat3x3: ...
|
||||
def __mul__(self, other: float) -> mat3x3: ...
|
||||
def __rmul__(self, other: float) -> mat3x3: ...
|
||||
def __truediv__(self, other: float) -> mat3x3: ...
|
||||
|
||||
def __invert__(self) -> mat3x3: ...
|
||||
@overload
|
||||
def __matmul__(self, other: mat3x3) -> mat3x3: ...
|
||||
@overload
|
||||
def __matmul__(self, other: vec3) -> vec3: ...
|
||||
|
||||
def matmul(self, other: mat3x3, out: mat3x3 = None) -> mat3x3 | None: ...
|
||||
|
||||
def copy_(self, other: mat3x3) -> None: ...
|
||||
def invert_(self) -> None: ...
|
||||
def transpose_(self) -> None: ...
|
||||
|
||||
@staticmethod
|
||||
def zeros() -> mat3x3: ...
|
||||
@staticmethod
|
||||
def ones() -> mat3x3: ...
|
||||
@staticmethod
|
||||
def identity() -> mat3x3: ...
|
||||
|
||||
# affine transformations
|
||||
@staticmethod
|
||||
def trs(t: vec2, r: float, s: vec2) -> mat3x3: ...
|
||||
|
||||
def copy_trs_(self, t: vec2, r: float, s: vec2) -> None: ...
|
||||
def copy_t_(self, t: vec2) -> None: ...
|
||||
def copy_r_(self, r: float) -> None: ...
|
||||
def copy_s_(self, s: vec2) -> None: ...
|
||||
|
||||
def _t(self) -> vec2: ...
|
||||
def _r(self) -> float: ...
|
||||
def _s(self) -> vec2: ...
|
||||
|
||||
def is_affine(self) -> bool: ...
|
||||
|
||||
def transform_point(self, p: vec2) -> vec2: ...
|
||||
def transform_vector(self, v: vec2) -> vec2: ...
|
||||
|
||||
vec2_p = float_p
|
||||
vec3_p = float_p
|
||||
vec4_p = float_p
|
||||
mat3x3_p = float_p
|
||||
|
||||
```
|
||||
39
dependencies/pocketpy/docs/modules/line_profiler.md
vendored
Normal file
39
dependencies/pocketpy/docs/modules/line_profiler.md
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
icon: package
|
||||
label: line_profiler
|
||||
---
|
||||
|
||||
Line-by-line profiler for Python.
|
||||
|
||||
## Example
|
||||
|
||||
```python
|
||||
from line_profiler import LineProfiler
|
||||
|
||||
def my_func():
|
||||
a = 0
|
||||
for i in range(1000000):
|
||||
a += i
|
||||
return a
|
||||
|
||||
lp = LineProfiler()
|
||||
|
||||
lp.add_function(my_func)
|
||||
|
||||
lp.runcall(my_func)
|
||||
|
||||
lp.print_stats()
|
||||
```
|
||||
|
||||
```txt
|
||||
Total time: 0.243s
|
||||
File: 84_line_profiler.py
|
||||
Function: my_func at line 3
|
||||
Line # Hits Time Per Hit % Time Line Contents
|
||||
==============================================================
|
||||
3 def my_func():
|
||||
4 1 0 0 0.0 a = 0
|
||||
5 1000001 69 0 28.4 for i in range(1000000):
|
||||
6 1000001 174 0 71.6 a += i
|
||||
7 1 0 0 0.0 return a
|
||||
```
|
||||
133
dependencies/pocketpy/docs/modules/math.md
vendored
Normal file
133
dependencies/pocketpy/docs/modules/math.md
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
---
|
||||
icon: package
|
||||
label: math
|
||||
---
|
||||
|
||||
### `math.pi`
|
||||
|
||||
3.141592653589793
|
||||
|
||||
### `math.e`
|
||||
|
||||
2.718281828459045
|
||||
|
||||
### `math.inf`
|
||||
|
||||
The `inf`.
|
||||
|
||||
### `math.nan`
|
||||
|
||||
The `nan`.
|
||||
|
||||
### `math.ceil(x)`
|
||||
|
||||
Return the ceiling of `x` as a float, the smallest integer value greater than or equal to `x`.
|
||||
|
||||
### `math.fabs(x)`
|
||||
|
||||
Return the absolute value of `x`.
|
||||
|
||||
### `math.floor(x)`
|
||||
|
||||
Return the floor of `x` as a float, the largest integer value less than or equal to `x`.
|
||||
|
||||
### `math.fsum(iterable)`
|
||||
|
||||
Return an accurate floating point sum of values in the iterable. Avoids loss of precision by tracking multiple intermediate partial sums:
|
||||
|
||||
```
|
||||
>>> sum([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
|
||||
0.9999999999999999
|
||||
>>> fsum([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
|
||||
1.0
|
||||
```
|
||||
|
||||
### `math.gcd(a, b)`
|
||||
|
||||
Return the greatest common divisor of the integers `a` and `b`.
|
||||
|
||||
|
||||
### `math.isfinite(x)`
|
||||
|
||||
Return `True` if `x` is neither an infinity nor a NaN, and `False` otherwise.
|
||||
|
||||
### `math.isinf(x)`
|
||||
|
||||
Return `True` if `x` is a positive or negative infinity, and `False` otherwise.
|
||||
|
||||
### `math.isnan(x)`
|
||||
|
||||
Return `True` if `x` is a NaN (not a number), and `False` otherwise.
|
||||
|
||||
### `math.isclose(a, b)`
|
||||
|
||||
Return `True` if the values `a` and `b` are close to each other and `False` otherwise.
|
||||
|
||||
### `math.exp(x)`
|
||||
|
||||
Return `e` raised to the power of `x`.
|
||||
|
||||
### `math.log(x)`
|
||||
|
||||
Return the natural logarithm of `x` (to base `e`).
|
||||
|
||||
### `math.log2(x)`
|
||||
|
||||
Return the base-2 logarithm of `x`. This is usually more accurate than `log(x, 2)`.
|
||||
|
||||
### `math.log10(x)`
|
||||
|
||||
Return the base-10 logarithm of `x`. This is usually more accurate than `log(x, 10)`.
|
||||
|
||||
### `math.pow(x, y)`
|
||||
|
||||
Return `x` raised to the power `y`.
|
||||
|
||||
### `math.sqrt(x)`
|
||||
|
||||
Return the square root of `x`.
|
||||
|
||||
### `math.acos(x)`
|
||||
|
||||
Return the arc cosine of `x`, in radians.
|
||||
|
||||
### `math.asin(x)`
|
||||
|
||||
Return the arc sine of `x`, in radians.
|
||||
|
||||
### `math.atan(x)`
|
||||
|
||||
Return the arc tangent of `x`, in radians.
|
||||
|
||||
### `math.atan2(y, x)`
|
||||
|
||||
Return `atan(y / x)`, in radians. The result is between `-pi` and `pi`. The vector in the plane from the origin to point `(x, y)` makes this angle with the positive X axis. The point of `atan2()` is that the signs of both inputs are known to it, so it can compute the correct quadrant for the angle. For example, `atan(1)` and `atan2(1, 1)` are both `pi/4`, but `atan2(-1, -1)` is `-3*pi/4`.
|
||||
|
||||
### `math.cos(x)`
|
||||
|
||||
Return the cosine of `x` radians.
|
||||
|
||||
### `math.sin(x)`
|
||||
|
||||
Return the sine of `x` radians.
|
||||
|
||||
### `math.tan(x)`
|
||||
|
||||
Return the tangent of `x` radians.
|
||||
|
||||
### `math.degrees(x)`
|
||||
|
||||
Convert angle `x` from radians to degrees.
|
||||
|
||||
### `math.radians(x)`
|
||||
|
||||
Convert angle `x` from degrees to radians.
|
||||
|
||||
|
||||
### `math.modf(x)`
|
||||
|
||||
Return the fractional and integer parts of `x`. Both results carry the sign of `x` and are floats.
|
||||
|
||||
### `math.factorial(x)`
|
||||
|
||||
Return `x` factorial as an integer.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user