mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
Merge branch 'pocketpy:main' into gsoc-2025-debugger
This commit is contained in:
commit
7251257e44
8
.github/workflows/main.yml
vendored
8
.github/workflows/main.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p output/x86_64
|
||||
python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON
|
||||
python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON -DPK_BUILD_MODULE_CUTE_PNG=ON
|
||||
cp main.exe output/x86_64
|
||||
cp pocketpy.dll output/x86_64
|
||||
- uses: actions/upload-artifact@v4
|
||||
@ -76,7 +76,7 @@ jobs:
|
||||
run: |
|
||||
python scripts/check_pragma_once.py include
|
||||
mkdir -p output/x86_64
|
||||
python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON
|
||||
python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON -DPK_BUILD_MODULE_CUTE_PNG=ON
|
||||
python scripts/run_tests.py
|
||||
cp main output/x86_64
|
||||
cp libpocketpy.so output/x86_64
|
||||
@ -96,7 +96,7 @@ jobs:
|
||||
submodules: recursive
|
||||
- name: Compile and Test
|
||||
run: |
|
||||
python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON
|
||||
python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON -DPK_BUILD_MODULE_CUTE_PNG=ON
|
||||
python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
@ -162,7 +162,7 @@ jobs:
|
||||
uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
packages: gcc g++ make cmake libc-dev linux-headers python3
|
||||
packages: gcc g++ make cmake libc-dev linux-headers python3 git
|
||||
- name: Build and Test
|
||||
run: |
|
||||
echo "Building for architecture: ${{ matrix.arch }}"
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -40,3 +40,4 @@ docs/C-API/functions.md
|
||||
|
||||
|
||||
cmake-build-*
|
||||
tmp/
|
12
3rd/cute_png/CMakeLists.txt
Normal file
12
3rd/cute_png/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(cute_png)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC src/cute_png.c)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/include
|
||||
)
|
1852
3rd/cute_png/include/cute_png.h
Normal file
1852
3rd/cute_png/include/cute_png.h
Normal file
File diff suppressed because it is too large
Load Diff
56
3rd/cute_png/src/cute_png.c
Normal file
56
3rd/cute_png/src/cute_png.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include "pocketpy.h"
|
||||
|
||||
#define CUTE_PNG_IMPLEMENTATION
|
||||
#include "cute_png.h"
|
||||
|
||||
static bool cute_png_loads(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_bytes);
|
||||
int size;
|
||||
unsigned char* data = py_tobytes(argv, &size);
|
||||
cp_image_t image = cp_load_png_mem(data, size);
|
||||
if(image.pix == NULL) return ValueError("cute_png: %s", cp_error_reason);
|
||||
py_newarray2d(py_retval(), image.w, image.h);
|
||||
for(int y = 0; y < image.h; y++) {
|
||||
for(int x = 0; x < image.w; x++) {
|
||||
cp_pixel_t pixel = image.pix[y * image.w + x];
|
||||
py_ObjectRef slot = py_array2d_getitem(py_retval(), x, y);
|
||||
c11_color32 color;
|
||||
color.r = pixel.r;
|
||||
color.g = pixel.g;
|
||||
color.b = pixel.b;
|
||||
color.a = pixel.a;
|
||||
py_newcolor32(slot, color);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cute_png_dumps(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_array2d);
|
||||
int width = py_array2d_getwidth(argv);
|
||||
int height = py_array2d_getheight(argv);
|
||||
cp_image_t image = cp_load_blank(width, height);
|
||||
for(int y = 0; y < height; y++) {
|
||||
for(int x = 0; x < width; x++) {
|
||||
py_ObjectRef slot = py_array2d_getitem(argv, x, y);
|
||||
if(!py_checktype(slot, tp_color32)) return false;
|
||||
c11_color32 color = py_tocolor32(slot);
|
||||
cp_pixel_t pixel = cp_make_pixel_a(color.r, color.g, color.b, color.a);
|
||||
image.pix[y * width + x] = pixel;
|
||||
}
|
||||
}
|
||||
cp_saved_png_t saved_image = cp_save_png_to_memory(&image);
|
||||
assert(saved_image.data != NULL);
|
||||
unsigned char* data = py_newbytes(py_retval(), saved_image.size);
|
||||
memcpy(data, saved_image.data, saved_image.size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk__add_module_cute_png() {
|
||||
py_GlobalRef mod = py_newmodule("cute_png");
|
||||
|
||||
py_bindfunc(mod, "loads", cute_png_loads);
|
||||
py_bindfunc(mod, "dumps", cute_png_dumps);
|
||||
}
|
@ -2,8 +2,6 @@ cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(libhv_bindings)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
@ -5,12 +5,12 @@ project(lz4)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
add_library(lz4 STATIC lz4/lib/lz4.c)
|
||||
add_library(${PROJECT_NAME} STATIC lz4/lib/lz4.c)
|
||||
|
||||
target_include_directories(lz4 PRIVATE
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/lz4/lib
|
||||
)
|
||||
|
||||
target_include_directories(lz4 INTERFACE
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(pocketpy)
|
||||
|
||||
if(PK_BUILD_SHARED_LIB OR NOT PK_BUILD_STATIC_MAIN)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
@ -13,8 +17,7 @@ endif()
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8 /jumptablerdata")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /experimental:c11atomics")
|
||||
add_compile_options(/wd4267 /wd4244 /wd4146)
|
||||
add_compile_options(/wd4267 /wd4244 /wd4146 /experimental:c11atomics)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ox")
|
||||
@ -47,19 +50,57 @@ file(GLOB_RECURSE POCKETPY_SRC ${CMAKE_CURRENT_LIST_DIR}/src/*.c)
|
||||
|
||||
if(PK_ENABLE_OS)
|
||||
add_definitions(-DPK_ENABLE_OS=1)
|
||||
else()
|
||||
add_definitions(-DPK_ENABLE_OS=0)
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_THREADS)
|
||||
add_definitions(-DPK_ENABLE_THREADS=1)
|
||||
else()
|
||||
add_definitions(-DPK_ENABLE_THREADS=0)
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_DETERMINISM)
|
||||
add_subdirectory(3rd/dmath/dmath)
|
||||
add_definitions(-DPK_ENABLE_DETERMINISM=1)
|
||||
else()
|
||||
add_definitions(-DPK_ENABLE_DETERMINISM=0)
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_WATCHDOG)
|
||||
add_definitions(-DPK_ENABLE_WATCHDOG=1)
|
||||
else()
|
||||
add_definitions(-DPK_ENABLE_WATCHDOG=0)
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_CUSTOM_SNAME)
|
||||
add_definitions(-DPK_ENABLE_CUSTOM_SNAME=1)
|
||||
else()
|
||||
add_definitions(-DPK_ENABLE_CUSTOM_SNAME=0)
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_MIMALLOC)
|
||||
message(">> Fetching mimalloc")
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
mimalloc
|
||||
GIT_REPOSITORY https://github.com/microsoft/mimalloc.git
|
||||
GIT_TAG v3.1.5
|
||||
)
|
||||
|
||||
set(MI_OVERRIDE OFF CACHE BOOL "" FORCE)
|
||||
set(MI_NO_USE_CXX ON CACHE BOOL "" FORCE)
|
||||
set(MI_BUILD_SHARED OFF CACHE BOOL "" FORCE)
|
||||
set(MI_BUILD_OBJECT OFF CACHE BOOL "" FORCE)
|
||||
set(MI_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
||||
set(MI_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(mimalloc)
|
||||
include_directories(${mimalloc_SOURCE_DIR}/include)
|
||||
|
||||
add_definitions(-DPK_ENABLE_MIMALLOC=1)
|
||||
else()
|
||||
add_definitions(-DPK_ENABLE_MIMALLOC=0)
|
||||
endif()
|
||||
|
||||
|
||||
@ -73,6 +114,12 @@ if(PK_BUILD_MODULE_LIBHV)
|
||||
add_definitions(-DPK_BUILD_MODULE_LIBHV)
|
||||
endif()
|
||||
|
||||
if(PK_BUILD_MODULE_CUTE_PNG)
|
||||
add_subdirectory(3rd/cute_png)
|
||||
add_definitions(-DPK_BUILD_MODULE_CUTE_PNG)
|
||||
endif()
|
||||
|
||||
|
||||
if(PK_BUILD_SHARED_LIB)
|
||||
message(">> Building shared library")
|
||||
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
|
||||
@ -104,8 +151,10 @@ if(PK_ENABLE_DETERMINISM)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} Threads::Threads)
|
||||
if(PK_ENABLE_THREADS)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} Threads::Threads)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(NOT PK_ENABLE_DETERMINISM)
|
||||
@ -133,4 +182,13 @@ endif()
|
||||
|
||||
if(PK_BUILD_MODULE_LIBHV)
|
||||
target_link_libraries(${PROJECT_NAME} libhv_bindings)
|
||||
endif()
|
||||
|
||||
if(PK_BUILD_MODULE_CUTE_PNG)
|
||||
target_link_libraries(${PROJECT_NAME} cute_png)
|
||||
endif()
|
||||
|
||||
|
||||
if(PK_ENABLE_MIMALLOC)
|
||||
target_link_libraries(${PROJECT_NAME} mimalloc-static)
|
||||
endif()
|
@ -6,15 +6,17 @@ else()
|
||||
endif()
|
||||
|
||||
# system features
|
||||
option(PK_ENABLE_OS "" OFF)
|
||||
option(PK_ENABLE_OS "" ON)
|
||||
option(PK_ENABLE_THREADS "" ON)
|
||||
option(PK_ENABLE_DETERMINISM "" OFF)
|
||||
option(PK_ENABLE_WATCHDOG "" OFF)
|
||||
option(PK_ENABLE_CUSTOM_SNAME "" OFF)
|
||||
option(PK_ENABLE_MIMALLOC "" OFF)
|
||||
|
||||
# modules
|
||||
option(PK_BUILD_MODULE_LZ4 "" OFF)
|
||||
option(PK_BUILD_MODULE_LIBHV "" OFF)
|
||||
|
||||
option(PK_BUILD_MODULE_CUTE_PNG "" OFF)
|
||||
|
||||
# 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).
|
||||
|
@ -31,6 +31,7 @@ Developers are able to write Python bindings via C-API or pybind11 compatible in
|
||||
Please see https://pocketpy.dev for details and try the following resources.
|
||||
+ [Live Python Demo](https://pocketpy.dev/static/web/): Run Python code in your browser
|
||||
+ [Live C Examples](https://pocketpy.github.io/examples/): Explore C-APIs in your browser
|
||||
+ [Godot Extension](https://github.com/pocketpy/godot-pocketpy): Use pocketpy in Godot Engine
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
@ -186,6 +187,7 @@ And these are the results of the primes benchmark on Intel i5-12400F, WSL (Ubunt
|
||||
|
||||
| | Description |
|
||||
|-----------------------------------------------------------------|--------------------------------------------------------------------------|
|
||||
| [godot-pocketpy](https://github.com/pocketpy/godot-pocketpy) | Godot extension for using pocketpy in Godot Engine. |
|
||||
| [TIC-80](https://github.com/nesbox/TIC-80) | TIC-80 is a fantasy computer for making, playing and sharing tiny games. |
|
||||
| [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. |
|
||||
|
@ -16,6 +16,7 @@ cmake \
|
||||
-DPK_BUILD_SHARED_LIB=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DPK_BUILD_MODULE_LZ4=ON \
|
||||
-DPK_BUILD_MODULE_LIBHV=ON
|
||||
-DPK_BUILD_MODULE_LIBHV=ON \
|
||||
-DPK_BUILD_CUTE_PNG=ON
|
||||
|
||||
cmake --build . --config Release
|
||||
|
@ -20,7 +20,7 @@ assert config in ['Debug', 'Release', 'RelWithDebInfo']
|
||||
|
||||
os.chdir("build")
|
||||
|
||||
code = os.system(f"cmake .. -DPK_ENABLE_OS=ON -DPK_ENABLE_DETERMINISM=ON -DCMAKE_BUILD_TYPE={config} {extra_flags}")
|
||||
code = os.system(f"cmake .. -DPK_ENABLE_MIMALLOC=ON -DPK_ENABLE_DETERMINISM=ON -DCMAKE_BUILD_TYPE={config} {extra_flags}")
|
||||
assert code == 0
|
||||
code = os.system(f"cmake --build . --config {config} -j 4")
|
||||
assert code == 0
|
||||
|
@ -4,4 +4,5 @@
|
||||
-std=c11
|
||||
-Iinclude/
|
||||
-I3rd/lz4/
|
||||
-I3rd/libhv/include/
|
||||
-I3rd/libhv/include/
|
||||
-I3rd/cute_headers/include/
|
@ -12,6 +12,8 @@ Developers are able to write Python bindings via C-API or pybind11 compatible in
|
||||
|
||||
+ [Live Python Demo](https://pocketpy.dev/static/web/): Run Python code in your browser
|
||||
+ [Live C Examples](https://pocketpy.github.io/examples/): Explore C-APIs in your browser
|
||||
+ [Godot Extension](https://github.com/pocketpy/godot-pocketpy): Use pocketpy in Godot Engine
|
||||
+ [Flutter Plugin](https://pub.dev/packages/pocketpy): Use pocketpy in Flutter apps
|
||||
|
||||
## What it looks like
|
||||
|
||||
|
14
docs/modules/cute_png.md
Normal file
14
docs/modules/cute_png.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
icon: package
|
||||
label: cute_png
|
||||
---
|
||||
|
||||
!!!
|
||||
This module is optional. Set option `PK_BUILD_MODULE_CUTE_PNG` to `ON` in your `CMakeLists.txt` to enable it.
|
||||
!!!
|
||||
|
||||
Wraps [cute_png.h](https://github.com/RandyGaul/cute_headers/blob/master/cute_png.h) for PNG image loading and saving.
|
||||
|
||||
#### Source code
|
||||
|
||||
:::code source="../../include/typings/cute_png.pyi" :::
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
|
||||
typedef struct c11_chunkedvector_chunk {
|
||||
int length;
|
||||
int capacity;
|
||||
|
@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/config.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if PK_ENABLE_OS
|
||||
|
||||
typedef void* c11_socket_handler;
|
||||
|
||||
enum c11_address_family { C11_AF_INET = 2 };
|
||||
@ -23,3 +26,5 @@ int c11_socket_close(c11_socket_handler socket);
|
||||
int c11_socket_set_block(c11_socket_handler socket, int flag);
|
||||
c11_socket_handler c11_socket_invalid_socket_handler();
|
||||
int c11_socket_get_last_error();
|
||||
|
||||
#endif // PK_ENABLE_OS
|
@ -67,6 +67,7 @@ c11_string* c11_sv__replace2(c11_sv self, c11_sv old, c11_sv new_);
|
||||
|
||||
c11_vector /* T=c11_sv */ c11_sv__split(c11_sv self, char sep);
|
||||
c11_vector /* T=c11_sv */ c11_sv__split2(c11_sv self, c11_sv sep);
|
||||
c11_vector /* T=c11_sv */ c11_sv__splitwhitespace(c11_sv self);
|
||||
|
||||
// misc
|
||||
int c11__unicode_index_to_byte(const char* data, int i);
|
||||
|
@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/config.h"
|
||||
|
||||
#if PK_ENABLE_THREADS
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -17,3 +21,5 @@ typedef int c11_thrd_retval_t;
|
||||
|
||||
bool c11_thrd_create(c11_thrd_t* thrd, c11_thrd_retval_t (*func)(void*), void* arg);
|
||||
void c11_thrd_yield();
|
||||
|
||||
#endif
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define PK_REGION(name) 1
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -23,6 +21,7 @@ void* c11_vector__emplace(c11_vector* self);
|
||||
bool c11_vector__contains(const c11_vector* self, void* elem);
|
||||
void* c11_vector__submit(c11_vector* self, int* length);
|
||||
void c11_vector__swap(c11_vector* self, c11_vector* other);
|
||||
int c11_vector__nextcap(c11_vector* self);
|
||||
|
||||
#define c11__getitem(T, self, index) (((T*)(self)->data)[index])
|
||||
#define c11__setitem(T, self, index, value) ((T*)(self)->data)[index] = value;
|
||||
@ -30,7 +29,9 @@ void c11_vector__swap(c11_vector* self, c11_vector* other);
|
||||
|
||||
#define c11_vector__push(T, self, elem) \
|
||||
do { \
|
||||
if((self)->length == (self)->capacity) c11_vector__reserve((self), (self)->capacity * 2); \
|
||||
if((self)->length == (self)->capacity) { \
|
||||
c11_vector__reserve((self), c11_vector__nextcap((self))); \
|
||||
} \
|
||||
((T*)(self)->data)[(self)->length] = (elem); \
|
||||
(self)->length++; \
|
||||
} while(0)
|
||||
@ -42,15 +43,19 @@ void c11_vector__swap(c11_vector* self, c11_vector* other);
|
||||
#define c11_vector__extend(T, self, p, size) \
|
||||
do { \
|
||||
int min_capacity = (self)->length + (size); \
|
||||
if((self)->capacity < min_capacity) \
|
||||
c11_vector__reserve((self), c11__max((self)->capacity * 2, min_capacity)); \
|
||||
if((self)->capacity < min_capacity) { \
|
||||
int nextcap = c11_vector__nextcap(self); \
|
||||
c11_vector__reserve((self), c11__max(nextcap, min_capacity)); \
|
||||
} \
|
||||
memcpy((T*)(self)->data + (self)->length, (p), (size) * sizeof(T)); \
|
||||
(self)->length += (size); \
|
||||
} while(0)
|
||||
|
||||
#define c11_vector__insert(T, self, index, elem) \
|
||||
do { \
|
||||
if((self)->length == (self)->capacity) c11_vector__reserve((self), (self)->capacity * 2); \
|
||||
if((self)->length == (self)->capacity) { \
|
||||
c11_vector__reserve((self), c11_vector__nextcap(self)); \
|
||||
} \
|
||||
T* p = (T*)(self)->data + (index); \
|
||||
memmove(p + 1, p, ((self)->length - (index)) * sizeof(T)); \
|
||||
*p = (elem); \
|
||||
|
@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
#define PK_VERSION "2.1.0"
|
||||
#define PK_VERSION "2.1.1"
|
||||
#define PK_VERSION_MAJOR 2
|
||||
#define PK_VERSION_MINOR 1
|
||||
#define PK_VERSION_PATCH 0
|
||||
#define PK_VERSION_PATCH 1
|
||||
|
||||
/*************** feature settings ***************/
|
||||
// Whether to compile os-related modules or not
|
||||
#ifndef PK_ENABLE_OS // can be overridden by cmake
|
||||
#define PK_ENABLE_OS 1
|
||||
#endif
|
||||
|
||||
#ifndef PK_ENABLE_THREADS // can be overridden by cmake
|
||||
#define PK_ENABLE_THREADS 1
|
||||
#endif
|
||||
|
||||
#ifndef PK_ENABLE_DETERMINISM // must be enabled from cmake
|
||||
#define PK_ENABLE_DETERMINISM 0
|
||||
#endif
|
||||
@ -24,24 +27,15 @@
|
||||
#define PK_ENABLE_CUSTOM_SNAME 0
|
||||
#endif
|
||||
|
||||
#ifndef PK_ENABLE_MIMALLOC // can be overridden by cmake
|
||||
#define PK_ENABLE_MIMALLOC 0
|
||||
#endif
|
||||
|
||||
// GC min threshold
|
||||
#ifndef PK_GC_MIN_THRESHOLD // can be overridden by cmake
|
||||
#define PK_GC_MIN_THRESHOLD 32768
|
||||
#endif
|
||||
|
||||
// Memory allocation functions
|
||||
#ifndef PK_MALLOC
|
||||
#ifndef __cplusplus
|
||||
#define PK_MALLOC(size) malloc(size)
|
||||
#define PK_REALLOC(ptr, size) realloc(ptr, size)
|
||||
#define PK_FREE(ptr) free(ptr)
|
||||
#else
|
||||
#define PK_MALLOC(size) std::malloc(size)
|
||||
#define PK_REALLOC(ptr, size) std::realloc(ptr, size)
|
||||
#define PK_FREE(ptr) std::free(ptr)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This is the maximum size of the value stack in py_TValue units
|
||||
// The actual size in bytes equals `sizeof(py_TValue) * PK_VM_STACK_SIZE`
|
||||
#ifndef PK_VM_STACK_SIZE // can be overridden by cmake
|
||||
@ -81,3 +75,31 @@
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PK_ENABLE_THREADS
|
||||
#define PK_THREAD_LOCAL _Thread_local
|
||||
#else
|
||||
#define PK_THREAD_LOCAL
|
||||
#endif
|
||||
|
||||
// Memory allocation functions
|
||||
#ifndef PK_MALLOC
|
||||
#if PK_ENABLE_MIMALLOC
|
||||
#include "mimalloc.h"
|
||||
#define PK_MALLOC(size) mi_malloc(size)
|
||||
#define PK_REALLOC(ptr, size) mi_realloc(ptr, size)
|
||||
#define PK_FREE(ptr) mi_free(ptr)
|
||||
#else
|
||||
#ifndef __cplusplus
|
||||
#include <stdlib.h>
|
||||
#define PK_MALLOC(size) malloc(size)
|
||||
#define PK_REALLOC(ptr, size) realloc(ptr, size)
|
||||
#define PK_FREE(ptr) free(ptr)
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#define PK_MALLOC(size) std::malloc(size)
|
||||
#define PK_REALLOC(ptr, size) std::realloc(ptr, size)
|
||||
#define PK_FREE(ptr) std::free(ptr)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -60,4 +60,16 @@
|
||||
#define PK_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
#define PK_DEPRECATED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#if defined(__GNUC__)
|
||||
#define PK_INLINE __attribute__((always_inline)) inline
|
||||
#elif defined(_MSC_VER)
|
||||
#define PK_INLINE __forceinline
|
||||
#else
|
||||
#define PK_INLINE inline
|
||||
#endif
|
||||
#else
|
||||
#define PK_INLINE
|
||||
#endif
|
||||
|
@ -31,7 +31,7 @@ typedef struct c11_array2d_view {
|
||||
c11_vec2i origin;
|
||||
} c11_array2d_view;
|
||||
|
||||
c11_array2d* py_newarray2d(py_OutRef out, int n_cols, int n_rows);
|
||||
c11_array2d* c11_newarray2d(py_OutRef out, int n_cols, int n_rows);
|
||||
|
||||
/* chunked_array2d */
|
||||
#define SMALLMAP_T__HEADER
|
||||
|
11
include/pocketpy/interpreter/bindings.h
Normal file
11
include/pocketpy/interpreter/bindings.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
bool generator__next__(int argc, py_Ref argv);
|
||||
bool array2d_like_iterator__next__(int argc, py_Ref argv);
|
||||
bool list_iterator__next__(int argc, py_Ref argv);
|
||||
bool tuple_iterator__next__(int argc, py_Ref argv);
|
||||
bool dict_items__next__(int argc, py_Ref argv);
|
||||
bool range_iterator__next__(int argc, py_Ref argv);
|
||||
bool str_iterator__next__(int argc, py_Ref argv);
|
@ -31,4 +31,10 @@ void pk__add_module_pkpy();
|
||||
void pk__add_module_libhv();
|
||||
#else
|
||||
#define pk__add_module_libhv()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PK_BUILD_MODULE_CUTE_PNG
|
||||
void pk__add_module_cute_png();
|
||||
#else
|
||||
#define pk__add_module_cute_png()
|
||||
#endif
|
||||
|
@ -5,14 +5,19 @@
|
||||
|
||||
#define kPoolArenaSize (120 * 1024)
|
||||
#define kMultiPoolCount 5
|
||||
#define kPoolMaxBlockSize (32*kMultiPoolCount)
|
||||
#define kPoolMaxBlockSize (32 * kMultiPoolCount)
|
||||
|
||||
typedef struct PoolArena {
|
||||
int block_size;
|
||||
int block_count;
|
||||
int unused_length;
|
||||
int* unused;
|
||||
char data[kPoolArenaSize];
|
||||
|
||||
union {
|
||||
char data[kPoolArenaSize];
|
||||
int64_t _align64;
|
||||
};
|
||||
|
||||
int unused[];
|
||||
} PoolArena;
|
||||
|
||||
typedef struct Pool {
|
||||
|
@ -14,7 +14,12 @@ typedef struct py_TypeInfo {
|
||||
py_GlobalRef module;
|
||||
|
||||
bool is_python; // is it a python class? (not derived from c object)
|
||||
bool is_sealed; // can it be subclassed?
|
||||
bool is_final; // can it be subclassed?
|
||||
|
||||
bool (*getattribute)(py_Ref self, py_Name name) PY_RAISE PY_RETURN;
|
||||
bool (*setattribute)(py_Ref self, py_Name name, py_Ref val) PY_RAISE PY_RETURN;
|
||||
bool (*delattribute)(py_Ref self, py_Name name) PY_RAISE;
|
||||
bool (*getunboundmethod)(py_Ref self, py_Name name) PY_RETURN;
|
||||
|
||||
py_TValue annotations;
|
||||
py_Dtor dtor; // destructor for this type, NULL if no dtor
|
||||
@ -30,7 +35,7 @@ py_Type pk_newtype(const char* name,
|
||||
const py_GlobalRef module,
|
||||
void (*dtor)(void*),
|
||||
bool is_python,
|
||||
bool is_sealed);
|
||||
bool is_final);
|
||||
|
||||
|
||||
py_Type pk_newtypewithmode(py_Name name,
|
||||
@ -38,4 +43,4 @@ py_Type pk_newtypewithmode(py_Name name,
|
||||
const py_GlobalRef module,
|
||||
void (*dtor)(void*),
|
||||
bool is_python,
|
||||
bool is_sealed, enum py_CompileMode mode);
|
||||
bool is_final, enum py_CompileMode mode);
|
@ -3,26 +3,22 @@
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
#define PK_DICT_MAX_COLLISION 4
|
||||
|
||||
typedef struct {
|
||||
uint64_t hash;
|
||||
py_TValue key;
|
||||
py_TValue val;
|
||||
} DictEntry;
|
||||
|
||||
typedef struct {
|
||||
int _[PK_DICT_MAX_COLLISION];
|
||||
} DictIndex;
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
uint32_t capacity;
|
||||
DictIndex* indices;
|
||||
uint32_t null_index_value;
|
||||
bool index_is_short;
|
||||
void* indices;
|
||||
c11_vector /*T=DictEntry*/ entries;
|
||||
} Dict;
|
||||
|
||||
typedef c11_vector List;
|
||||
|
||||
void c11_chunked_array2d__mark(void* ud, c11_vector* p_stack);
|
||||
void function__gc_mark(void* ud, c11_vector* p_stack);
|
||||
void function__gc_mark(void* ud, c11_vector* p_stack);
|
||||
|
@ -67,7 +67,7 @@ typedef struct VM {
|
||||
NameDict compile_time_funcs;
|
||||
|
||||
py_StackRef curr_class;
|
||||
py_StackRef curr_decl_based_function;
|
||||
py_StackRef curr_decl_based_function; // this is for get current function without frame
|
||||
TraceInfo trace_info;
|
||||
WatchdogInfo watchdog_info;
|
||||
LineProfiler line_profiler;
|
||||
@ -92,7 +92,6 @@ bool pk__parse_int_slice(py_Ref slice,
|
||||
bool pk__normalize_index(int* index, int length);
|
||||
|
||||
bool pk__object_new(int argc, py_Ref argv);
|
||||
py_TypeInfo* pk_typeinfo(py_Type type);
|
||||
|
||||
bool pk_wrapper__self(int argc, py_Ref argv);
|
||||
|
||||
@ -113,7 +112,6 @@ const char* pk_opname(Opcode op);
|
||||
|
||||
int pk_arrayview(py_Ref self, py_TValue** p);
|
||||
bool pk_wrapper__arrayequal(py_Type type, int argc, py_Ref argv);
|
||||
bool pk_arrayiter(py_Ref val);
|
||||
bool pk_arraycontains(py_Ref self, py_Ref val);
|
||||
|
||||
bool pk_loadmethod(py_StackRef self, py_Name name);
|
||||
@ -139,7 +137,8 @@ py_Type pk_dict__register();
|
||||
py_Type pk_dict_items__register();
|
||||
py_Type pk_list__register();
|
||||
py_Type pk_tuple__register();
|
||||
py_Type pk_array_iterator__register();
|
||||
py_Type pk_list_iterator__register();
|
||||
py_Type pk_tuple_iterator__register();
|
||||
py_Type pk_slice__register();
|
||||
py_Type pk_function__register();
|
||||
py_Type pk_nativefunc__register();
|
||||
|
@ -19,8 +19,10 @@ typedef struct py_TValue {
|
||||
PyObject* _obj;
|
||||
c11_vec2 _vec2;
|
||||
c11_vec2i _vec2i;
|
||||
c11_vec3 _vec3;
|
||||
c11_vec3i _vec3i;
|
||||
c11_color32 _color32;
|
||||
void* _ptr;
|
||||
char _chars[8];
|
||||
char _chars[16];
|
||||
};
|
||||
} py_TValue;
|
||||
|
15
include/pocketpy/objects/iterator.h
Normal file
15
include/pocketpy/objects/iterator.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
|
||||
typedef struct tuple_iterator {
|
||||
py_TValue* p;
|
||||
int length;
|
||||
int index;
|
||||
} tuple_iterator;
|
||||
|
||||
typedef struct list_iterator {
|
||||
c11_vector* vec;
|
||||
int index;
|
||||
} list_iterator;
|
@ -30,7 +30,14 @@ typedef void (*py_Dtor)(void*);
|
||||
|
||||
#ifdef PK_IS_PUBLIC_INCLUDE
|
||||
typedef struct py_TValue {
|
||||
int64_t _[2];
|
||||
py_Type type;
|
||||
bool is_ptr;
|
||||
int extra;
|
||||
|
||||
union {
|
||||
int64_t _i64;
|
||||
char _chars[16];
|
||||
};
|
||||
} py_TValue;
|
||||
#endif
|
||||
|
||||
@ -70,8 +77,10 @@ typedef void (*py_TraceFunc)(py_Frame* frame, enum py_TraceEvent);
|
||||
|
||||
/// A struct contains the callbacks of the VM.
|
||||
typedef struct py_Callbacks {
|
||||
/// Used by `__import__` to load source code of a module.
|
||||
/// Used by `__import__` to load a source module.
|
||||
char* (*importfile)(const char*);
|
||||
/// Called before `importfile` to lazy-import a C module.
|
||||
py_GlobalRef (*lazyimport)(const char*);
|
||||
/// Used by `print` to output a string.
|
||||
void (*print)(const char*);
|
||||
/// Flush the output buffer of `print`.
|
||||
@ -124,6 +133,13 @@ PK_API int py_gc_collect();
|
||||
/// Setup the callbacks for the current VM.
|
||||
PK_API py_Callbacks* py_callbacks();
|
||||
|
||||
/// Wrapper for `PK_MALLOC(size)`.
|
||||
PK_API void* py_malloc(size_t size);
|
||||
/// Wrapper for `PK_REALLOC(ptr, size)`.
|
||||
PK_API void* py_realloc(void* ptr, size_t size);
|
||||
/// Wrapper for `PK_FREE(ptr)`.
|
||||
PK_API void py_free(void* ptr);
|
||||
|
||||
/// Begin the watchdog with `timeout` in milliseconds.
|
||||
/// `PK_ENABLE_WATCHDOG` must be defined to `1` to use this feature.
|
||||
/// You need to call `py_watchdog_end()` later.
|
||||
@ -201,6 +217,8 @@ PK_API py_GlobalRef py_NIL();
|
||||
|
||||
/// Create an `int` object.
|
||||
PK_API void py_newint(py_OutRef, py_i64);
|
||||
/// Create a trivial value object.
|
||||
PK_API void py_newtrivial(py_OutRef out, py_Type type, void* data, int size);
|
||||
/// Create a `float` object.
|
||||
PK_API void py_newfloat(py_OutRef, py_f64);
|
||||
/// Create a `bool` object.
|
||||
@ -282,6 +300,8 @@ PK_API void* py_newobject(py_OutRef out, py_Type type, int slots, int udsize);
|
||||
|
||||
/// Convert an `int` object in python to `int64_t`.
|
||||
PK_API py_i64 py_toint(py_Ref);
|
||||
/// Get the address of the trivial value object.
|
||||
PK_API void* py_totrivial(py_Ref);
|
||||
/// Convert a `float` object in python to `double`.
|
||||
PK_API py_f64 py_tofloat(py_Ref);
|
||||
/// Cast a `int` or `float` object in python to `double`.
|
||||
@ -350,6 +370,15 @@ PK_API py_GlobalRef py_tpobject(py_Type type);
|
||||
PK_API const char* py_tpname(py_Type type);
|
||||
/// Call a type to create a new instance.
|
||||
PK_API bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE PY_RETURN;
|
||||
/// Disable the type for subclassing.
|
||||
PK_API void py_tpsetfinal(py_Type type);
|
||||
/// Set attribute hooks for the given type.
|
||||
PK_API void py_tphookattributes(py_Type type,
|
||||
bool (*getattribute)(py_Ref self, py_Name name) PY_RAISE PY_RETURN,
|
||||
bool (*setattribute)(py_Ref self, py_Name name, py_Ref val)
|
||||
PY_RAISE PY_RETURN,
|
||||
bool (*delattribute)(py_Ref self, py_Name name) PY_RAISE,
|
||||
bool (*getunboundmethod)(py_Ref self, py_Name name) PY_RETURN);
|
||||
|
||||
/// Check if the object is an instance of the given type exactly.
|
||||
/// Raise `TypeError` if the check fails.
|
||||
@ -389,6 +418,7 @@ PK_API void py_setglobal(py_Name name, py_Ref val);
|
||||
PK_API py_ItemRef py_getbuiltin(py_Name name);
|
||||
|
||||
/// Get the last return value.
|
||||
/// Please note that `py_retval()` cannot be used as input argument.
|
||||
PK_API py_GlobalRef py_retval();
|
||||
|
||||
/// Get an item from the object's `__dict__`.
|
||||
@ -715,19 +745,33 @@ PK_API bool
|
||||
/// noexcept
|
||||
PK_API int py_dict_len(py_Ref self);
|
||||
|
||||
/************* random module *************/
|
||||
PK_API void py_newRandom(py_OutRef out);
|
||||
PK_API void py_Random_seed(py_Ref self, py_i64 seed);
|
||||
PK_API py_f64 py_Random_random(py_Ref self);
|
||||
PK_API py_f64 py_Random_uniform(py_Ref self, py_f64 a, py_f64 b);
|
||||
PK_API py_i64 py_Random_randint(py_Ref self, py_i64 a, py_i64 b);
|
||||
|
||||
/************* array2d module *************/
|
||||
PK_API void py_newarray2d(py_OutRef out, int width, int height);
|
||||
PK_API int py_array2d_getwidth(py_Ref self);
|
||||
PK_API int py_array2d_getheight(py_Ref self);
|
||||
PK_API py_ObjectRef py_array2d_getitem(py_Ref self, int x, int y);
|
||||
PK_API void py_array2d_setitem(py_Ref self, int x, int y, py_Ref val);
|
||||
|
||||
/************* vmath module *************/
|
||||
void py_newvec2(py_OutRef out, c11_vec2);
|
||||
void py_newvec3(py_OutRef out, c11_vec3);
|
||||
void py_newvec2i(py_OutRef out, c11_vec2i);
|
||||
void py_newvec3i(py_OutRef out, c11_vec3i);
|
||||
void py_newcolor32(py_OutRef out, c11_color32);
|
||||
c11_mat3x3* py_newmat3x3(py_OutRef out);
|
||||
c11_vec2 py_tovec2(py_Ref self);
|
||||
c11_vec3 py_tovec3(py_Ref self);
|
||||
c11_vec2i py_tovec2i(py_Ref self);
|
||||
c11_vec3i py_tovec3i(py_Ref self);
|
||||
c11_mat3x3* py_tomat3x3(py_Ref self);
|
||||
c11_color32 py_tocolor32(py_Ref self);
|
||||
PK_API void py_newvec2(py_OutRef out, c11_vec2);
|
||||
PK_API void py_newvec3(py_OutRef out, c11_vec3);
|
||||
PK_API void py_newvec2i(py_OutRef out, c11_vec2i);
|
||||
PK_API void py_newvec3i(py_OutRef out, c11_vec3i);
|
||||
PK_API void py_newcolor32(py_OutRef out, c11_color32);
|
||||
PK_API c11_mat3x3* py_newmat3x3(py_OutRef out);
|
||||
PK_API c11_vec2 py_tovec2(py_Ref self);
|
||||
PK_API c11_vec3 py_tovec3(py_Ref self);
|
||||
PK_API c11_vec2i py_tovec2i(py_Ref self);
|
||||
PK_API c11_vec3i py_tovec3i(py_Ref self);
|
||||
PK_API c11_mat3x3* py_tomat3x3(py_Ref self);
|
||||
PK_API c11_color32 py_tocolor32(py_Ref self);
|
||||
|
||||
/************* Others *************/
|
||||
|
||||
@ -755,10 +799,11 @@ enum py_PredefinedType {
|
||||
tp_bool,
|
||||
tp_str,
|
||||
tp_str_iterator,
|
||||
tp_list, // c11_vector
|
||||
tp_tuple, // N slots
|
||||
tp_array_iterator,
|
||||
tp_slice, // 3 slots (start, stop, step)
|
||||
tp_list, // c11_vector
|
||||
tp_tuple, // N slots
|
||||
tp_list_iterator, // 1 slot
|
||||
tp_tuple_iterator, // 1 slot
|
||||
tp_slice, // 3 slots (start, stop, step)
|
||||
tp_range,
|
||||
tp_range_iterator,
|
||||
tp_module,
|
||||
|
@ -124,3 +124,4 @@ bool METHOD(contains)(NAME* self, K key) {
|
||||
#undef less
|
||||
#undef partial_less
|
||||
#undef equal
|
||||
#undef hash
|
||||
|
@ -14,7 +14,7 @@ public:
|
||||
// get the python exception object
|
||||
object& exception() { return m_exception; }
|
||||
|
||||
~python_error() { std::free(m_what); }
|
||||
~python_error() { py_free(m_what); }
|
||||
|
||||
bool match(py_Type type) const { return py_isinstance(m_exception.ptr(), type); }
|
||||
|
||||
|
5
include/typings/cute_png.pyi
Normal file
5
include/typings/cute_png.pyi
Normal file
@ -0,0 +1,5 @@
|
||||
from array2d import array2d
|
||||
from vmath import color32
|
||||
|
||||
def loads(data: bytes) -> array2d[color32]: ...
|
||||
def dumps(image: array2d[color32]) -> bytes: ...
|
@ -186,6 +186,7 @@ class color32:
|
||||
def __eq__(self, other: object) -> bool: ...
|
||||
def __ne__(self, other: object) -> bool: ...
|
||||
def __repr__(self) -> str: ...
|
||||
def __hash__(self) -> int: ...
|
||||
|
||||
@property
|
||||
def r(self) -> int: ...
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "pocketpy/common/algorithm.h"
|
||||
#include "pocketpy/config.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static bool _stable_sort_merge(char* a,
|
||||
char* a_end,
|
||||
|
@ -1,15 +1,12 @@
|
||||
#include "pocketpy/common/chunkedvector.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/config.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
inline static int c11_bit_length(unsigned long x) {
|
||||
PK_INLINE static int c11__bit_length(unsigned long x) {
|
||||
#if(defined(__clang__) || defined(__GNUC__))
|
||||
return x == 0 ? 0 : (int)sizeof(unsigned long) * 8 - __builtin_clzl(x);
|
||||
#elif defined(_MSC_VER)
|
||||
@ -39,7 +36,6 @@ void c11_chunkedvector__ctor(c11_chunkedvector* self, int elem_size, int initial
|
||||
self->initial_chunks = initial_chunks;
|
||||
void* chunks_data = PK_MALLOC(elem_size * ((1U << (unsigned int)initial_chunks) - 1));
|
||||
for(int i = 0; i < initial_chunks; i++) {
|
||||
// TODO: optimize?
|
||||
c11_chunkedvector_chunk chunk = {.length = 0,
|
||||
.capacity = 1U << i,
|
||||
.data = (char*)chunks_data + elem_size * ((1U << i) - 1U)};
|
||||
@ -59,10 +55,11 @@ void c11_chunkedvector__dtor(c11_chunkedvector* self) {
|
||||
|
||||
void* c11_chunkedvector__emplace(c11_chunkedvector* self) {
|
||||
if(self->length == self->capacity) {
|
||||
#ifndef NDEBUG
|
||||
c11_chunkedvector_chunk last_chunk = c11_vector__back(c11_chunkedvector_chunk, &self->chunks);
|
||||
assert(last_chunk.capacity == last_chunk.length);
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
c11_chunkedvector_chunk last_chunk =
|
||||
c11_vector__back(c11_chunkedvector_chunk, &self->chunks);
|
||||
assert(last_chunk.capacity == last_chunk.length);
|
||||
#endif
|
||||
c11_chunkedvector_chunk chunk = {
|
||||
.length = 0,
|
||||
.capacity = 1U << (unsigned int)self->chunks.length,
|
||||
@ -70,9 +67,14 @@ void* c11_chunkedvector__emplace(c11_chunkedvector* self) {
|
||||
self->capacity += chunk.capacity;
|
||||
c11_vector__push(c11_chunkedvector_chunk, &self->chunks, chunk);
|
||||
}
|
||||
int last_chunk_index = c11_bit_length(self->length + 1) - 1;
|
||||
#if 1
|
||||
int last_chunk_index = c11__bit_length(self->length + 1) - 1;
|
||||
c11_chunkedvector_chunk* last_chunk =
|
||||
c11__at(c11_chunkedvector_chunk, &self->chunks, last_chunk_index);
|
||||
#else
|
||||
// This is not correct, because there is some pre-allocated chunks
|
||||
c11_chunkedvector_chunk* last_chunk = &c11_vector__back(c11_chunkedvector_chunk, &self->chunks);
|
||||
#endif
|
||||
void* p = (char*)last_chunk->data + self->elem_size * last_chunk->length;
|
||||
last_chunk->length++;
|
||||
self->length++;
|
||||
@ -80,7 +82,7 @@ void* c11_chunkedvector__emplace(c11_chunkedvector* self) {
|
||||
}
|
||||
|
||||
void* c11_chunkedvector__at(c11_chunkedvector* self, int index) {
|
||||
int chunk_index = c11_bit_length(index + 1) - 1;
|
||||
int chunk_index = c11__bit_length(index + 1) - 1;
|
||||
c11_chunkedvector_chunk* chunk = c11__at(c11_chunkedvector_chunk, &self->chunks, chunk_index);
|
||||
return (char*)chunk->data + (index + 1 - (1U << (unsigned int)chunk_index)) * self->elem_size;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount) {
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
#include "pocketpy/common/name.h"
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/threads.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdatomic.h>
|
||||
#include "pocketpy/common/threads.h"
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct NameBucket NameBucket;
|
||||
|
||||
@ -17,7 +17,9 @@ typedef struct NameBucket {
|
||||
|
||||
static struct {
|
||||
NameBucket* table[0x10000];
|
||||
#if PK_ENABLE_THREADS
|
||||
atomic_flag lock;
|
||||
#endif
|
||||
} pk_string_table;
|
||||
|
||||
#define MAGIC_METHOD(x) py_Name x;
|
||||
@ -43,9 +45,11 @@ void pk_names_finalize() {
|
||||
}
|
||||
|
||||
py_Name py_namev(c11_sv name) {
|
||||
#if PK_ENABLE_THREADS
|
||||
while(atomic_flag_test_and_set(&pk_string_table.lock)) {
|
||||
c11_thrd_yield();
|
||||
}
|
||||
#endif
|
||||
uint64_t hash = c11_sv__hash(name);
|
||||
int index = hash & 0xFFFF;
|
||||
NameBucket* p = pk_string_table.table[index];
|
||||
@ -61,7 +65,9 @@ py_Name py_namev(c11_sv name) {
|
||||
p = p->next;
|
||||
}
|
||||
if(found) {
|
||||
#if PK_ENABLE_THREADS
|
||||
atomic_flag_clear(&pk_string_table.lock);
|
||||
#endif
|
||||
return (py_Name)p;
|
||||
}
|
||||
|
||||
@ -78,7 +84,9 @@ py_Name py_namev(c11_sv name) {
|
||||
assert(prev->next == NULL);
|
||||
prev->next = bucket;
|
||||
}
|
||||
#if PK_ENABLE_THREADS
|
||||
atomic_flag_clear(&pk_string_table.lock);
|
||||
#endif
|
||||
return (py_Name)bucket;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "pocketpy/common/socket.h"
|
||||
|
||||
#if PK_ENABLE_OS
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined (_WIN32) || defined (_WIN64)
|
||||
@ -120,3 +122,5 @@ int c11_socket_get_last_error(){
|
||||
|
||||
#undef SOCKET_HANDLERTOFD
|
||||
#undef SOCKET_FDTOHANDLER
|
||||
|
||||
#endif // PK_ENABLE_OS
|
@ -1,7 +1,6 @@
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void SourceData__ctor(struct SourceData* self,
|
||||
@ -25,6 +24,16 @@ static void SourceData__ctor(struct SourceData* self,
|
||||
source++;
|
||||
}
|
||||
self->source = c11_sbuf__submit(&ss);
|
||||
// remove trailing newline
|
||||
int last_index = self->source->size - 1;
|
||||
while(last_index >= 0 && isspace(self->source->data[last_index])) {
|
||||
last_index--;
|
||||
}
|
||||
if(last_index >= 0) {
|
||||
self->source->size = last_index + 1;
|
||||
self->source->data[last_index + 1] = '\0';
|
||||
}
|
||||
|
||||
self->is_dynamic = is_dynamic;
|
||||
c11_vector__push(const char*, &self->line_starts, self->source->data);
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
|
@ -2,11 +2,10 @@
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
c11_string* c11_string__new(const char* data) { return c11_string__new2(data, strlen(data)); }
|
||||
|
||||
@ -190,6 +189,26 @@ uint64_t c11_sv__hash(c11_sv self) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
c11_vector /* T=c11_sv */ c11_sv__splitwhitespace(c11_sv self) {
|
||||
c11_vector retval;
|
||||
c11_vector__ctor(&retval, sizeof(c11_sv));
|
||||
const char* data = self.data;
|
||||
int i = 0;
|
||||
for(int j = 0; j < self.size; j++) {
|
||||
if(isspace(data[j])) {
|
||||
assert(j >= i);
|
||||
c11_sv tmp = {data + i, j - i};
|
||||
c11_vector__push(c11_sv, &retval, tmp);
|
||||
i = j + 1;
|
||||
}
|
||||
}
|
||||
if(i <= self.size) {
|
||||
c11_sv tmp = {data + i, self.size - i};
|
||||
c11_vector__push(c11_sv, &retval, tmp);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
c11_vector /* T=c11_sv */ c11_sv__split(c11_sv self, char sep) {
|
||||
c11_vector retval;
|
||||
c11_vector__ctor(&retval, sizeof(c11_sv));
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "pocketpy/export.h"
|
||||
#include "pocketpy/common/threads.h"
|
||||
|
||||
#if PK_ENABLE_THREADS
|
||||
|
||||
#if PK_USE_PTHREADS
|
||||
|
||||
bool c11_thrd_create(c11_thrd_t* thrd, c11_thrd_retval_t (*func)(void*), void* arg) {
|
||||
@ -19,4 +20,6 @@ bool c11_thrd_create(c11_thrd_t* thrd, c11_thrd_retval_t (*func)(void*), void* a
|
||||
|
||||
void c11_thrd_yield() { thrd_yield(); }
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // PK_ENABLE_THREADS
|
@ -1,6 +1,5 @@
|
||||
#include "pocketpy/common/vector.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/config.h"
|
||||
@ -40,7 +39,7 @@ void c11_vector__reserve(c11_vector* self, int capacity) {
|
||||
void c11_vector__clear(c11_vector* self) { self->length = 0; }
|
||||
|
||||
void* c11_vector__emplace(c11_vector* self) {
|
||||
if(self->length == self->capacity) c11_vector__reserve(self, self->capacity * 2);
|
||||
if(self->length == self->capacity) { c11_vector__reserve(self, c11_vector__nextcap(self)); }
|
||||
void* p = (char*)self->data + (size_t)self->elem_size * (size_t)self->length;
|
||||
self->length++;
|
||||
return p;
|
||||
@ -63,8 +62,17 @@ void* c11_vector__submit(c11_vector* self, int* length) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
void c11_vector__swap(c11_vector *self, c11_vector *other){
|
||||
void c11_vector__swap(c11_vector* self, c11_vector* other) {
|
||||
c11_vector tmp = *self;
|
||||
*self = *other;
|
||||
*other = tmp;
|
||||
}
|
||||
|
||||
int c11_vector__nextcap(c11_vector* self) {
|
||||
if(self->capacity < 1024) {
|
||||
return self->capacity * 2;
|
||||
} else {
|
||||
// increase by 25%
|
||||
return self->capacity + (self->capacity >> 2);
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ typedef struct ExprVt {
|
||||
bool is_subscr; // SubscrExpr
|
||||
bool is_starred; // StarredExpr
|
||||
bool is_binary; // BinaryExpr
|
||||
bool is_ternary; // TernaryExpr
|
||||
void (*dtor)(Expr*);
|
||||
} ExprVt;
|
||||
|
||||
@ -873,7 +874,11 @@ void TernaryExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
}
|
||||
|
||||
TernaryExpr* TernaryExpr__new(int line) {
|
||||
const static ExprVt Vt = {.dtor = TernaryExpr__dtor, .emit_ = TernaryExpr__emit_};
|
||||
const static ExprVt Vt = {
|
||||
.dtor = TernaryExpr__dtor,
|
||||
.emit_ = TernaryExpr__emit_,
|
||||
.is_ternary = true,
|
||||
};
|
||||
TernaryExpr* self = PK_MALLOC(sizeof(TernaryExpr));
|
||||
self->vt = &Vt;
|
||||
self->line = line;
|
||||
@ -1681,6 +1686,10 @@ static Error* exprTernary(Compiler* self) {
|
||||
e->cond = Ctx__s_popx(ctx());
|
||||
e->true_expr = Ctx__s_popx(ctx());
|
||||
Ctx__s_push(ctx(), (Expr*)e);
|
||||
|
||||
if(e->cond->vt->is_ternary || e->false_expr->vt->is_ternary || e->true_expr->vt->is_ternary) {
|
||||
return SyntaxError(self, "nested ternary expressions without `()` are ambiguous");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -2856,13 +2865,14 @@ static Error* compile_stmt(Compiler* self) {
|
||||
|
||||
bool is_typed_name = false; // e.g. x: int
|
||||
// eat variable's type hint if it is a single name
|
||||
if(Ctx__s_top(ctx())->vt->is_name) {
|
||||
const ExprVt* top_vt = Ctx__s_top(ctx())->vt;
|
||||
if(top_vt->is_name || top_vt->is_attrib) {
|
||||
if(match(TK_COLON)) {
|
||||
c11_sv type_hint;
|
||||
check(consume_type_hints_sv(self, &type_hint));
|
||||
is_typed_name = true;
|
||||
|
||||
if(ctx()->is_compiling_class) {
|
||||
if(ctx()->is_compiling_class && top_vt->is_name) {
|
||||
NameExpr* ne = (NameExpr*)Ctx__s_top(ctx());
|
||||
int index = Ctx__add_const_string(ctx(), type_hint);
|
||||
Ctx__emit_(ctx(), OP_LOAD_CONST, index, BC_KEEPLINE);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
void ValueStack__ctor(ValueStack* self) {
|
||||
self->sp = self->begin;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
void pk_newgenerator(py_Ref out, py_Frame* frame, py_TValue* begin, py_TValue* end) {
|
||||
Generator* ud = py_newobject(out, tp_generator, 1, sizeof(Generator));
|
||||
@ -20,7 +21,7 @@ void Generator__dtor(Generator* ud) {
|
||||
if(ud->frame) Frame__delete(ud->frame);
|
||||
}
|
||||
|
||||
static bool generator__next__(int argc, py_Ref argv) {
|
||||
bool generator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
Generator* ud = py_touserdata(argv);
|
||||
py_StackRef p0 = py_peek(0);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "pocketpy/interpreter/objectpool.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <assert.h>
|
||||
|
||||
void ManagedHeap__ctor(ManagedHeap* self) {
|
||||
MultiPool__ctor(&self->small_objects);
|
||||
@ -33,25 +34,26 @@ void ManagedHeap__dtor(ManagedHeap* self) {
|
||||
void ManagedHeap__collect_if_needed(ManagedHeap* self) {
|
||||
if(!self->gc_enabled) return;
|
||||
if(self->gc_counter < self->gc_threshold) return;
|
||||
self->gc_counter = 0;
|
||||
int freed = ManagedHeap__collect(self);
|
||||
// adjust `gc_threshold` based on `freed_ma`
|
||||
self->freed_ma[0] = self->freed_ma[1];
|
||||
self->freed_ma[1] = self->freed_ma[2];
|
||||
self->freed_ma[2] = freed;
|
||||
int avg_freed = (self->freed_ma[0] + self->freed_ma[1] + self->freed_ma[2]) / 3;
|
||||
const int upper = PK_GC_MIN_THRESHOLD * 8;
|
||||
const int upper = PK_GC_MIN_THRESHOLD * 16;
|
||||
const int lower = PK_GC_MIN_THRESHOLD / 2;
|
||||
float free_ratio = (float)avg_freed / self->gc_threshold;
|
||||
int new_threshold = self->gc_threshold * (1 / free_ratio);
|
||||
int new_threshold = self->gc_threshold * (1.5f / free_ratio);
|
||||
// printf("gc_threshold=%d, avg_freed=%d, new_threshold=%d\n", self->gc_threshold, avg_freed,
|
||||
// new_threshold);
|
||||
self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper);
|
||||
}
|
||||
|
||||
int ManagedHeap__collect(ManagedHeap* self) {
|
||||
self->gc_counter = 0;
|
||||
ManagedHeap__mark(self);
|
||||
int freed = ManagedHeap__sweep(self);
|
||||
// printf("GC: collected %d objects\n", freed);
|
||||
return freed;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/line_profiler.h"
|
||||
#include <assert.h>
|
||||
|
||||
void LineProfiler__ctor(LineProfiler* self) {
|
||||
c11_smallmap_p2i__ctor(&self->records);
|
||||
|
@ -1,12 +1,10 @@
|
||||
#include "pocketpy/interpreter/objectpool.h"
|
||||
|
||||
#include "pocketpy/config.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static PoolArena* PoolArena__new(int block_size) {
|
||||
@ -16,7 +14,6 @@ static PoolArena* PoolArena__new(int block_size) {
|
||||
self->block_size = block_size;
|
||||
self->block_count = block_count;
|
||||
self->unused_length = block_count;
|
||||
self->unused = PK_MALLOC(sizeof(int) * block_count);
|
||||
for(int i = 0; i < block_count; i++) {
|
||||
self->unused[i] = i;
|
||||
}
|
||||
@ -29,7 +26,6 @@ static void PoolArena__delete(PoolArena* self) {
|
||||
PyObject* obj = (PyObject*)(self->data + i * self->block_size);
|
||||
if(obj->type != 0) PyObject__dtor(obj);
|
||||
}
|
||||
PK_FREE(self->unused);
|
||||
PK_FREE(self);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include <assert.h>
|
||||
|
||||
py_ItemRef pk_tpfindname(py_TypeInfo* ti, py_Name name) {
|
||||
assert(ti != NULL);
|
||||
@ -10,17 +11,17 @@ py_ItemRef pk_tpfindname(py_TypeInfo* ti, py_Name name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
py_ItemRef py_tpfindname(py_Type type, py_Name name) {
|
||||
PK_INLINE py_ItemRef py_tpfindname(py_Type type, py_Name name) {
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
return pk_tpfindname(ti, name);
|
||||
}
|
||||
|
||||
py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
PK_INLINE py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
// assert(py_ismagicname(name));
|
||||
return py_tpfindname(t, name);
|
||||
}
|
||||
|
||||
py_Type py_tpbase(py_Type t) {
|
||||
PK_INLINE py_Type py_tpbase(py_Type t) {
|
||||
assert(t);
|
||||
py_TypeInfo* ti = pk_typeinfo(t);
|
||||
return ti->base;
|
||||
@ -44,7 +45,7 @@ const char* py_tpname(py_Type type) {
|
||||
return py_name2str(name);
|
||||
}
|
||||
|
||||
py_TypeInfo* pk_typeinfo(py_Type type) {
|
||||
PK_INLINE py_TypeInfo* pk_typeinfo(py_Type type) {
|
||||
#ifndef NDEBUG
|
||||
int length = pk_current_vm->types.length;
|
||||
if(type < 0 || type >= length) {
|
||||
@ -60,11 +61,11 @@ static void py_TypeInfo__common_init(py_Name name,
|
||||
const py_GlobalRef module,
|
||||
void (*dtor)(void*),
|
||||
bool is_python,
|
||||
bool is_sealed,
|
||||
bool is_final,
|
||||
py_TypeInfo* self,
|
||||
py_TValue* typeobject) {
|
||||
py_TypeInfo* base_ti = base ? pk_typeinfo(base) : NULL;
|
||||
if(base_ti && base_ti->is_sealed) {
|
||||
if(base_ti && base_ti->is_final) {
|
||||
c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name));
|
||||
}
|
||||
|
||||
@ -78,7 +79,12 @@ static void py_TypeInfo__common_init(py_Name name,
|
||||
|
||||
if(!dtor && base) dtor = base_ti->dtor;
|
||||
self->is_python = is_python;
|
||||
self->is_sealed = is_sealed;
|
||||
self->is_final = is_final;
|
||||
|
||||
self->getattribute = NULL;
|
||||
self->setattribute = NULL;
|
||||
self->delattribute = NULL;
|
||||
self->getunboundmethod = NULL;
|
||||
|
||||
self->annotations = *py_NIL();
|
||||
self->dtor = dtor;
|
||||
@ -90,7 +96,7 @@ py_Type pk_newtype(const char* name,
|
||||
const py_GlobalRef module,
|
||||
void (*dtor)(void*),
|
||||
bool is_python,
|
||||
bool is_sealed) {
|
||||
bool is_final) {
|
||||
py_Type index = pk_current_vm->types.length;
|
||||
py_TypeInfo* self = py_newobject(py_retval(), tp_type, -1, sizeof(py_TypeInfo));
|
||||
py_TypeInfo__common_init(py_name(name),
|
||||
@ -99,7 +105,7 @@ py_Type pk_newtype(const char* name,
|
||||
module,
|
||||
dtor,
|
||||
is_python,
|
||||
is_sealed,
|
||||
is_final,
|
||||
self,
|
||||
py_retval());
|
||||
TypePointer* pointer = c11_vector__emplace(&pk_current_vm->types);
|
||||
@ -113,7 +119,7 @@ py_Type pk_newtypewithmode(py_Name name,
|
||||
const py_GlobalRef module,
|
||||
void (*dtor)(void*),
|
||||
bool is_python,
|
||||
bool is_sealed,
|
||||
bool is_final,
|
||||
enum py_CompileMode mode) {
|
||||
if(mode == RELOAD_MODE && module != NULL) {
|
||||
py_ItemRef old_class = py_getdict(module, name);
|
||||
@ -131,7 +137,7 @@ py_Type pk_newtypewithmode(py_Name name,
|
||||
module,
|
||||
dtor,
|
||||
is_python,
|
||||
is_sealed,
|
||||
is_final,
|
||||
self,
|
||||
&self->self);
|
||||
TypePointer* pointer = c11__at(TypePointer, &pk_current_vm->types, index);
|
||||
@ -141,7 +147,7 @@ py_Type pk_newtypewithmode(py_Name name,
|
||||
}
|
||||
}
|
||||
|
||||
return pk_newtype(py_name2str(name), base, module, dtor, is_python, is_sealed);
|
||||
return pk_newtype(py_name2str(name), base, module, dtor, is_python, is_final);
|
||||
}
|
||||
|
||||
py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, void (*dtor)(void*)) {
|
||||
@ -149,4 +155,23 @@ py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, vo
|
||||
py_Type type = pk_newtype(name, base, module, dtor, false, false);
|
||||
if(module) py_setdict(module, py_name(name), py_tpobject(type));
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
void py_tpsetfinal(py_Type type) {
|
||||
assert(type);
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
ti->is_final = true;
|
||||
}
|
||||
|
||||
void py_tphookattributes(py_Type type,
|
||||
bool (*getattribute)(py_Ref self, py_Name name),
|
||||
bool (*setattribute)(py_Ref self, py_Name name, py_Ref val),
|
||||
bool (*delattribute)(py_Ref self, py_Name name),
|
||||
bool (*getunboundmethod)(py_Ref self, py_Name name)) {
|
||||
assert(type);
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
ti->getattribute = getattribute;
|
||||
ti->setattribute = setattribute;
|
||||
ti->delattribute = delattribute;
|
||||
ti->getunboundmethod = getunboundmethod;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/interpreter/generator.h"
|
||||
#include "pocketpy/interpreter/modules.h"
|
||||
@ -10,6 +9,7 @@
|
||||
#include "pocketpy/common/_generated.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
static char* pk_default_importfile(const char* path) {
|
||||
#if PK_ENABLE_OS
|
||||
@ -59,6 +59,7 @@ void VM__ctor(VM* self) {
|
||||
self->main = NULL;
|
||||
|
||||
self->callbacks.importfile = pk_default_importfile;
|
||||
self->callbacks.lazyimport = NULL;
|
||||
self->callbacks.print = pk_default_print;
|
||||
self->callbacks.flush = pk_default_flush;
|
||||
self->callbacks.getchr = pk_default_getchr;
|
||||
@ -109,7 +110,8 @@ void VM__ctor(VM* self) {
|
||||
|
||||
validate(tp_list, pk_list__register());
|
||||
validate(tp_tuple, pk_tuple__register());
|
||||
validate(tp_array_iterator, pk_array_iterator__register());
|
||||
validate(tp_list_iterator, pk_list_iterator__register());
|
||||
validate(tp_tuple_iterator, pk_tuple_iterator__register());
|
||||
|
||||
validate(tp_slice, pk_slice__register());
|
||||
validate(tp_range, pk_range__register());
|
||||
@ -234,6 +236,7 @@ void VM__ctor(VM* self) {
|
||||
pk__add_module_conio();
|
||||
pk__add_module_lz4(); // optional
|
||||
pk__add_module_libhv(); // optional
|
||||
pk__add_module_cute_png(); // optional
|
||||
pk__add_module_pkpy();
|
||||
|
||||
// add python builtins
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include <assert.h>
|
||||
|
||||
void pk_print_stack(VM* self, py_Frame* frame, Bytecode byte) {
|
||||
return;
|
||||
@ -123,5 +124,8 @@ py_Ref py_name2ref(py_Name name) {
|
||||
void PyObject__dtor(PyObject* self) {
|
||||
py_Dtor dtor = c11__getitem(TypePointer, &pk_current_vm->types, self->type).dtor;
|
||||
if(dtor) dtor(PyObject__userdata(self));
|
||||
if(self->slots == -1) NameDict__dtor(PyObject__dict(self));
|
||||
if(self->slots == -1) {
|
||||
NameDict* dict = PyObject__dict(self);
|
||||
NameDict__dtor(dict);
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ static bool c11_array2d__set(c11_array2d* self, int col, int row, py_Ref value)
|
||||
return true;
|
||||
}
|
||||
|
||||
c11_array2d* py_newarray2d(py_OutRef out, int n_cols, int n_rows) {
|
||||
c11_array2d* c11_newarray2d(py_OutRef out, int n_cols, int n_rows) {
|
||||
int numel = n_cols * n_rows;
|
||||
c11_array2d* ud = py_newobject(out, tp_array2d, numel, sizeof(c11_array2d));
|
||||
ud->header.n_cols = n_cols;
|
||||
@ -112,7 +112,10 @@ static bool array2d_like_index(int argc, py_Ref argv) {
|
||||
int code = py_equal(item, value);
|
||||
if(code == -1) return false;
|
||||
if(code == 1) {
|
||||
py_newvec2i(py_retval(), (c11_vec2i){{i, j}});
|
||||
py_newvec2i(py_retval(),
|
||||
(c11_vec2i){
|
||||
{i, j}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -176,7 +179,7 @@ static bool array2d_like_map(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
c11_array2d_like* self = py_touserdata(argv);
|
||||
py_Ref f = py_arg(1);
|
||||
c11_array2d* res = py_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
c11_array2d* res = c11_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
for(int j = 0; j < self->n_rows; j++) {
|
||||
for(int i = 0; i < self->n_cols; i++) {
|
||||
py_Ref item = self->f_get(self, i, j);
|
||||
@ -228,7 +231,7 @@ static bool _array2d_like_broadcasted_zip_with(int argc, py_Ref argv, py_Name op
|
||||
} else {
|
||||
other = NULL;
|
||||
}
|
||||
c11_array2d* res = py_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
c11_array2d* res = c11_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
for(int j = 0; j < self->n_rows; j++) {
|
||||
for(int i = 0; i < self->n_cols; i++) {
|
||||
py_Ref lhs = self->f_get(self, i, j);
|
||||
@ -254,7 +257,7 @@ static bool array2d_like_zip_with(int argc, py_Ref argv) {
|
||||
c11_array2d_like* other = py_touserdata(py_arg(1));
|
||||
py_Ref f = py_arg(2);
|
||||
if(!_array2d_like_check_same_shape(self, other)) return false;
|
||||
c11_array2d* res = py_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
c11_array2d* res = c11_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
for(int j = 0; j < self->n_rows; j++) {
|
||||
for(int i = 0; i < self->n_cols; i++) {
|
||||
py_push(f);
|
||||
@ -299,7 +302,7 @@ DEF_ARRAY2D_LIKE__MAGIC_ZIP_WITH(__xor__, __xor__, 0)
|
||||
static bool array2d_like__invert__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_array2d_like* self = py_touserdata(argv);
|
||||
c11_array2d* res = py_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
c11_array2d* res = c11_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
for(int j = 0; j < self->n_rows; j++) {
|
||||
for(int i = 0; i < self->n_cols; i++) {
|
||||
py_Ref item = self->f_get(self, i, j);
|
||||
@ -316,7 +319,7 @@ static bool array2d_like_copy(int argc, py_Ref argv) {
|
||||
// def copy(self) -> 'array2d': ...
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_array2d_like* self = py_touserdata(argv);
|
||||
c11_array2d* res = py_newarray2d(py_retval(), self->n_cols, self->n_rows);
|
||||
c11_array2d* res = c11_newarray2d(py_retval(), self->n_cols, self->n_rows);
|
||||
for(int j = 0; j < self->n_rows; j++) {
|
||||
for(int i = 0; i < self->n_cols; i++) {
|
||||
py_Ref item = self->f_get(self, i, j);
|
||||
@ -637,7 +640,7 @@ static bool array2d_like_get_bounding_rect(int argc, py_Ref argv) {
|
||||
static bool array2d_like_count_neighbors(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(3);
|
||||
c11_array2d_like* self = py_touserdata(argv);
|
||||
c11_array2d* res = py_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
c11_array2d* res = c11_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
py_Ref value = py_arg(1);
|
||||
const char* neighborhood = py_tostr(py_arg(2));
|
||||
|
||||
@ -703,7 +706,7 @@ static bool array2d_like_convolve(int argc, py_Ref argv) {
|
||||
int ksize = kernel->n_cols;
|
||||
if(ksize % 2 == 0) return ValueError("kernel size must be odd");
|
||||
int ksize_half = ksize / 2;
|
||||
c11_array2d* res = py_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
c11_array2d* res = c11_newarray2d(py_pushtmp(), self->n_cols, self->n_rows);
|
||||
for(int j = 0; j < self->n_rows; j++) {
|
||||
for(int i = 0; i < self->n_cols; i++) {
|
||||
py_i64 sum = 0;
|
||||
@ -800,7 +803,7 @@ static void register_array2d_like(py_Ref mod) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool array2d_like_iterator__next__(int argc, py_Ref argv) {
|
||||
bool array2d_like_iterator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_array2d_like_iterator* self = py_touserdata(argv);
|
||||
if(self->j >= self->array->n_rows) return StopIteration();
|
||||
@ -834,7 +837,7 @@ static bool array2d__new__(int argc, py_Ref argv) {
|
||||
int n_cols = argv[1]._i64;
|
||||
int n_rows = argv[2]._i64;
|
||||
if(n_cols <= 0 || n_rows <= 0) return ValueError("array2d() expected positive dimensions");
|
||||
c11_array2d* ud = py_newarray2d(py_pushtmp(), n_cols, n_rows);
|
||||
c11_array2d* ud = c11_newarray2d(py_pushtmp(), n_cols, n_rows);
|
||||
// setup initial values
|
||||
if(py_callable(default_)) {
|
||||
for(int j = 0; j < n_rows; j++) {
|
||||
@ -876,7 +879,7 @@ static bool array2d_fromlist_STATIC(int argc, py_Ref argv) {
|
||||
return ValueError("fromlist() expected a list of lists with the same length");
|
||||
}
|
||||
}
|
||||
c11_array2d* res = py_newarray2d(py_retval(), n_cols, n_rows);
|
||||
c11_array2d* res = c11_newarray2d(py_retval(), n_cols, n_rows);
|
||||
for(int j = 0; j < n_rows; j++) {
|
||||
py_Ref row_j = py_list_getitem(argv, j);
|
||||
for(int i = 0; i < n_cols; i++) {
|
||||
@ -1359,4 +1362,30 @@ void pk__add_module_array2d() {
|
||||
register_array2d(mod);
|
||||
register_array2d_view(mod);
|
||||
register_chunked_array2d(mod);
|
||||
}
|
||||
|
||||
void py_newarray2d(py_OutRef out, int width, int height) { c11_newarray2d(out, width, height); }
|
||||
|
||||
int py_array2d_getwidth(py_Ref self) {
|
||||
assert(self->type == tp_array2d);
|
||||
c11_array2d* ud = py_touserdata(self);
|
||||
return ud->header.n_cols;
|
||||
}
|
||||
|
||||
int py_array2d_getheight(py_Ref self) {
|
||||
assert(self->type == tp_array2d);
|
||||
c11_array2d* ud = py_touserdata(self);
|
||||
return ud->header.n_rows;
|
||||
}
|
||||
|
||||
py_ObjectRef py_array2d_getitem(py_Ref self, int x, int y) {
|
||||
assert(self->type == tp_array2d);
|
||||
c11_array2d* ud = py_touserdata(self);
|
||||
return c11_array2d__get(ud, x, y);
|
||||
}
|
||||
|
||||
void py_array2d_setitem(py_Ref self, int x, int y, py_Ref value) {
|
||||
assert(self->type == tp_array2d);
|
||||
c11_array2d* ud = py_touserdata(self);
|
||||
c11_array2d__set(ud, x, y, value);
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#if PY_SYS_PLATFORM == 0
|
||||
|
||||
|
@ -16,7 +16,7 @@ static bool Enum__wrapper_field(py_Name name, py_Ref value, void* ctx) {
|
||||
}
|
||||
|
||||
static void Enum__on_end_subclass(py_TypeInfo* derived_ti) {
|
||||
derived_ti->is_sealed = true;
|
||||
derived_ti->is_final = true;
|
||||
py_applydict(&derived_ti->self, Enum__wrapper_field, &derived_ti->self);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
#ifdef PK_BUILD_MODULE_LZ4
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
@ -1,8 +1,4 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
#include <math.h>
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
#if PK_ENABLE_OS == 1
|
||||
#if PK_ENABLE_OS
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
@ -656,7 +656,7 @@ bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_
|
||||
case PKL_ARRAY2D: {
|
||||
int n_cols = pkl__read_int(&p);
|
||||
int n_rows = pkl__read_int(&p);
|
||||
c11_array2d* arr = py_newarray2d(py_pushtmp(), n_cols, n_rows);
|
||||
c11_array2d* arr = c11_newarray2d(py_pushtmp(), n_cols, n_rows);
|
||||
int total_size = arr->header.numel * sizeof(py_TValue);
|
||||
memcpy(arr->data, p, total_size);
|
||||
for(int i = 0; i < arr->header.numel; i++) {
|
||||
|
@ -106,6 +106,8 @@ static bool pkpy_watchdog_end(int argc, py_Ref argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PK_ENABLE_THREADS
|
||||
|
||||
typedef struct c11_ComputeThread c11_ComputeThread;
|
||||
|
||||
typedef struct {
|
||||
@ -456,6 +458,8 @@ static void pk_ComputeThread__register(py_Ref mod) {
|
||||
py_bindmethod(type, "eval", ComputeThread_eval);
|
||||
}
|
||||
|
||||
#endif // PK_ENABLE_THREADS
|
||||
|
||||
static void pkpy_configmacros_add(py_Ref dict, const char* key, int val) {
|
||||
assert(dict->type == tp_dict);
|
||||
py_TValue tmp;
|
||||
@ -508,11 +512,14 @@ void pk__add_module_pkpy() {
|
||||
py_bindfunc(mod, "watchdog_end", pkpy_watchdog_end);
|
||||
#endif
|
||||
|
||||
#if PK_ENABLE_THREADS
|
||||
pk_ComputeThread__register(mod);
|
||||
#endif
|
||||
|
||||
py_Ref configmacros = py_emplacedict(mod, py_name("configmacros"));
|
||||
py_newdict(configmacros);
|
||||
pkpy_configmacros_add(configmacros, "PK_ENABLE_OS", PK_ENABLE_OS);
|
||||
pkpy_configmacros_add(configmacros, "PK_ENABLE_THREADS", PK_ENABLE_THREADS);
|
||||
pkpy_configmacros_add(configmacros, "PK_ENABLE_DETERMINISM", PK_ENABLE_DETERMINISM);
|
||||
pkpy_configmacros_add(configmacros, "PK_ENABLE_WATCHDOG", PK_ENABLE_WATCHDOG);
|
||||
pkpy_configmacros_add(configmacros, "PK_GC_MIN_THRESHOLD", PK_GC_MIN_THRESHOLD);
|
||||
|
@ -145,7 +145,7 @@ static bool Random__init__(int argc, py_Ref argv) {
|
||||
// do nothing
|
||||
} else if(argc == 2) {
|
||||
mt19937* ud = py_touserdata(py_arg(0));
|
||||
if(!py_isnone(&argv[1])){
|
||||
if(!py_isnone(&argv[1])) {
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
py_i64 seed = py_toint(py_arg(1));
|
||||
mt19937__seed(ud, (uint32_t)seed);
|
||||
@ -328,4 +328,32 @@ __ERROR:
|
||||
#undef MATRIX_A
|
||||
#undef UPPER_MASK
|
||||
#undef LOWER_MASK
|
||||
#undef ADD_INST_BOUNDMETHOD
|
||||
#undef ADD_INST_BOUNDMETHOD
|
||||
|
||||
void py_newRandom(py_OutRef out) {
|
||||
py_Type type = py_gettype("random", py_name("Random"));
|
||||
assert(type != 0);
|
||||
mt19937* ud = py_newobject(out, type, 0, sizeof(mt19937));
|
||||
mt19937__ctor(ud);
|
||||
}
|
||||
|
||||
void py_Random_seed(py_Ref self, py_i64 seed) {
|
||||
mt19937* ud = py_touserdata(self);
|
||||
mt19937__seed(ud, (uint32_t)seed);
|
||||
}
|
||||
|
||||
py_f64 py_Random_random(py_Ref self) {
|
||||
mt19937* ud = py_touserdata(self);
|
||||
return mt19937__random(ud);
|
||||
}
|
||||
|
||||
py_f64 py_Random_uniform(py_Ref self, py_f64 a, py_f64 b) {
|
||||
mt19937* ud = py_touserdata(self);
|
||||
return mt19937__uniform(ud, a, b);
|
||||
}
|
||||
|
||||
py_i64 py_Random_randint(py_Ref self, py_i64 a, py_i64 b) {
|
||||
mt19937* ud = py_touserdata(self);
|
||||
if(a > b) { c11__abort("randint(a, b): a must be less than or equal to b"); }
|
||||
return mt19937__randint(ud, a, b);
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static bool traceback_format_exc(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
|
@ -58,25 +58,23 @@ c11_vec2i py_tovec2i(py_Ref self) {
|
||||
void py_newvec3(py_OutRef out, c11_vec3 v) {
|
||||
out->type = tp_vec3;
|
||||
out->is_ptr = false;
|
||||
c11_vec3* data = (c11_vec3*)(&out->extra);
|
||||
*data = v;
|
||||
out->_vec3 = v;
|
||||
}
|
||||
|
||||
c11_vec3 py_tovec3(py_Ref self) {
|
||||
assert(self->type == tp_vec3);
|
||||
return *(c11_vec3*)(&self->extra);
|
||||
return self->_vec3;
|
||||
}
|
||||
|
||||
void py_newvec3i(py_OutRef out, c11_vec3i v) {
|
||||
out->type = tp_vec3i;
|
||||
out->is_ptr = false;
|
||||
c11_vec3i* data = (c11_vec3i*)(&out->extra);
|
||||
*data = v;
|
||||
out->_vec3i = v;
|
||||
}
|
||||
|
||||
c11_vec3i py_tovec3i(py_Ref self) {
|
||||
assert(self->type == tp_vec3i);
|
||||
return *(c11_vec3i*)(&self->extra);
|
||||
return self->_vec3i;
|
||||
}
|
||||
|
||||
c11_mat3x3* py_newmat3x3(py_OutRef out) {
|
||||
@ -1013,6 +1011,14 @@ static bool color32__repr__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool color32__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_color32 color = py_tocolor32(argv);
|
||||
uint32_t* color_int = (uint32_t*)&color;
|
||||
py_newint(py_retval(), *color_int);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool color32_ansi_fg(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
c11_color32 color = py_tocolor32(argv);
|
||||
@ -1258,6 +1264,7 @@ void pk__add_module_vmath() {
|
||||
py_bindmagic(color32, __repr__, color32__repr__);
|
||||
py_bindmagic(color32, __eq__, color32__eq__);
|
||||
py_bindmagic(color32, __ne__, color32__ne__);
|
||||
py_bindmagic(color32, __hash__, color32__hash__);
|
||||
py_bindproperty(color32, "r", color32__r, NULL);
|
||||
py_bindproperty(color32, "g", color32__g, NULL);
|
||||
py_bindproperty(color32, "b", color32__b, NULL);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
void Bytecode__set_signed_arg(Bytecode* self, int arg) {
|
||||
self->arg = (int16_t)arg;
|
||||
|
@ -4,21 +4,30 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define HASH_PROBE_0(__k, ok, i) \
|
||||
ok = false; \
|
||||
i = (uintptr_t)(__k)&self->mask; \
|
||||
do { \
|
||||
if(self->items[i].key == (__k)) { \
|
||||
ok = true; \
|
||||
break; \
|
||||
} \
|
||||
if(self->items[i].key == NULL) break; \
|
||||
i = (5 * i + 1) & self->mask; \
|
||||
} while(true);
|
||||
|
||||
#define HASH_PROBE_1(__k, ok, i) \
|
||||
ok = false; \
|
||||
i = (uintptr_t)(__k) & self->mask; \
|
||||
i = (uintptr_t)(__k)&self->mask; \
|
||||
while(self->items[i].key != NULL) { \
|
||||
if(self->items[i].key == (__k)) { \
|
||||
ok = true; \
|
||||
break; \
|
||||
} \
|
||||
i = (i + 1) & self->mask; \
|
||||
i = (5 * i + 1) & self->mask; \
|
||||
}
|
||||
|
||||
#define HASH_PROBE_0 HASH_PROBE_1
|
||||
|
||||
static void NameDict__set_capacity_and_alloc_items(NameDict* self, int val) {
|
||||
self->capacity = val;
|
||||
self->critical_size = val * self->load_factor;
|
||||
@ -101,18 +110,24 @@ bool NameDict__del(NameDict* self, py_Name key) {
|
||||
self->items[i].key = NULL;
|
||||
self->items[i].value = *py_NIL();
|
||||
self->length--;
|
||||
// tidy
|
||||
uintptr_t pre_z = i;
|
||||
uintptr_t z = (i + 1) & self->mask;
|
||||
while(self->items[z].key != NULL) {
|
||||
uintptr_t h = (uintptr_t)self->items[z].key & self->mask;
|
||||
if(h != i) break;
|
||||
// std::swap(_items[pre_z], _items[z]);
|
||||
NameDict_KV tmp = self->items[pre_z];
|
||||
self->items[pre_z] = self->items[z];
|
||||
self->items[z] = tmp;
|
||||
pre_z = z;
|
||||
z = (z + 1) & self->mask;
|
||||
/* tidy */
|
||||
uint32_t posToRemove = i;
|
||||
uint32_t posToShift = posToRemove;
|
||||
while(true) {
|
||||
posToShift = (5 * posToShift + 1) & self->mask;
|
||||
if(self->items[posToShift].key == NULL) break;
|
||||
uintptr_t hash_z = (uintptr_t)self->items[posToShift].key;
|
||||
uintptr_t insertPos = hash_z & self->mask;
|
||||
bool cond1 = insertPos <= posToRemove;
|
||||
bool cond2 = posToRemove <= posToShift;
|
||||
if((cond1 && cond2) ||
|
||||
// chain wrapped around capacity
|
||||
(posToShift < insertPos && (cond1 || cond2))) {
|
||||
NameDict_KV tmp = self->items[posToRemove];
|
||||
self->items[posToRemove] = self->items[posToShift];
|
||||
self->items[posToShift] = tmp;
|
||||
posToRemove = posToShift;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2,14 +2,16 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <assert.h>
|
||||
|
||||
void* PyObject__userdata(PyObject* self) { return self->flex + PK_OBJ_SLOTS_SIZE(self->slots); }
|
||||
PK_INLINE void* PyObject__userdata(PyObject* self) {
|
||||
return self->flex + PK_OBJ_SLOTS_SIZE(self->slots);
|
||||
}
|
||||
|
||||
NameDict* PyObject__dict(PyObject* self) {
|
||||
PK_INLINE NameDict* PyObject__dict(PyObject* self) {
|
||||
assert(self->slots == -1);
|
||||
return (NameDict*)(self->flex);
|
||||
}
|
||||
|
||||
py_TValue* PyObject__slots(PyObject* self) {
|
||||
PK_INLINE py_TValue* PyObject__slots(PyObject* self) {
|
||||
assert(self->slots >= 0);
|
||||
return (py_TValue*)(self->flex);
|
||||
}
|
@ -9,6 +9,8 @@ int64_t py_toint(py_Ref self) {
|
||||
return self->_i64;
|
||||
}
|
||||
|
||||
void* py_totrivial(py_Ref self) { return &self->_chars; }
|
||||
|
||||
double py_tofloat(py_Ref self) {
|
||||
assert(self->type == tp_float);
|
||||
return self->_f64;
|
||||
|
@ -30,9 +30,7 @@ void py_initialize() {
|
||||
bool is_little_endian = *(char*)&x == 1;
|
||||
if(!is_little_endian) c11__abort("is_little_endian != true");
|
||||
|
||||
// check py_TValue; 16 bytes to make py_arg() macro work
|
||||
static_assert(sizeof(py_CFunction) <= 8, "sizeof(py_CFunction) > 8");
|
||||
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
|
||||
static_assert(sizeof(py_TValue) == 24, "sizeof(py_TValue) != 24");
|
||||
static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");
|
||||
|
||||
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
|
||||
@ -47,6 +45,12 @@ void py_initialize() {
|
||||
pk_initialized = true;
|
||||
}
|
||||
|
||||
void* py_malloc(size_t size) { return PK_MALLOC(size); }
|
||||
|
||||
void* py_realloc(void* ptr, size_t size) { return PK_REALLOC(ptr, size); }
|
||||
|
||||
void py_free(void* ptr) { PK_FREE(ptr); }
|
||||
|
||||
py_GlobalRef py_True() { return &_True; }
|
||||
|
||||
py_GlobalRef py_False() { return &_False; }
|
||||
@ -178,7 +182,7 @@ bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
||||
return VM__vectorcall(pk_current_vm, argc, kwargc, false) != RES_ERROR;
|
||||
}
|
||||
|
||||
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||
PK_INLINE py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||
|
||||
bool py_pushmethod(py_Name name) {
|
||||
bool ok = pk_loadmethod(py_peek(-1), name);
|
||||
@ -223,7 +227,21 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
|
||||
self_bak = *self;
|
||||
}
|
||||
|
||||
py_Ref cls_var = py_tpfindname(type, name);
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
|
||||
if(ti->getunboundmethod) {
|
||||
bool ok = ti->getunboundmethod(self, name);
|
||||
if(ok) {
|
||||
assert(py_retval()->type == tp_nativefunc || py_retval()->type == tp_function);
|
||||
self[0] = *py_retval();
|
||||
self[1] = self_bak;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
py_Ref cls_var = pk_tpfindname(ti, name);
|
||||
if(cls_var != NULL) {
|
||||
switch(cls_var->type) {
|
||||
case tp_function:
|
||||
@ -238,7 +256,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
|
||||
break;
|
||||
case tp_classmethod:
|
||||
self[0] = *py_getslot(cls_var, 0);
|
||||
self[1] = pk_typeinfo(type)->self;
|
||||
self[1] = ti->self;
|
||||
break;
|
||||
default: c11__unreachable();
|
||||
}
|
||||
|
@ -28,32 +28,8 @@ static void py_ModuleInfo__dtor(py_ModuleInfo* mi) {
|
||||
c11_string__delete(mi->path);
|
||||
}
|
||||
|
||||
static bool module__name__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_ModuleInfo* mi = py_touserdata(argv);
|
||||
py_newstrv(py_retval(), c11_string__sv(mi->name));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool module__package__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_ModuleInfo* mi = py_touserdata(argv);
|
||||
py_newstrv(py_retval(), c11_string__sv(mi->package));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool module__path__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_ModuleInfo* mi = py_touserdata(argv);
|
||||
py_newstrv(py_retval(), c11_string__sv(mi->path));
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_module__register() {
|
||||
py_Type type = pk_newtype("module", tp_object, NULL, (py_Dtor)py_ModuleInfo__dtor, false, true);
|
||||
py_bindproperty(type, "__name__", module__name__, NULL);
|
||||
py_bindproperty(type, "__package__", module__package__, NULL);
|
||||
py_bindproperty(type, "__path__", module__path__, NULL);
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -85,6 +61,13 @@ py_Ref py_newmodule(const char* path) {
|
||||
BinTree__set(&pk_current_vm->modules, (void*)path, py_retval());
|
||||
py_GlobalRef retval = py_getmodule(path);
|
||||
mi->self = retval;
|
||||
|
||||
// setup __name__
|
||||
py_newstrv(py_emplacedict(retval, __name__), c11_string__sv(mi->name));
|
||||
// setup __package__
|
||||
py_newstrv(py_emplacedict(retval, __package__), c11_string__sv(mi->package));
|
||||
// setup __path__
|
||||
py_newstrv(py_emplacedict(retval, __path__), c11_string__sv(mi->path));
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -146,6 +129,15 @@ int py_import(const char* path_cstr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(vm->callbacks.lazyimport) {
|
||||
py_GlobalRef lazymod = vm->callbacks.lazyimport(path_cstr);
|
||||
if(lazymod) {
|
||||
c11__rtassert(py_istype(lazymod, tp_module));
|
||||
py_assign(py_retval(), lazymod);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// try import
|
||||
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
|
||||
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
||||
|
@ -1,13 +1,8 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/objects/iterator.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
typedef struct array_iterator {
|
||||
py_TValue* p;
|
||||
int length;
|
||||
int index;
|
||||
} array_iterator;
|
||||
|
||||
int pk_arrayview(py_Ref self, py_TValue** p) {
|
||||
if(self->type == tp_list) {
|
||||
*p = py_list_data(self);
|
||||
@ -46,18 +41,6 @@ bool pk_wrapper__arrayequal(py_Type type, int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pk_arrayiter(py_Ref val) {
|
||||
py_TValue* p;
|
||||
int length = pk_arrayview(val, &p);
|
||||
if(length == -1) return TypeError("expected list or tuple, got %t", val->type);
|
||||
array_iterator* ud = py_newobject(py_retval(), tp_array_iterator, 1, sizeof(array_iterator));
|
||||
ud->p = p;
|
||||
ud->length = length;
|
||||
ud->index = 0;
|
||||
py_setslot(py_retval(), 0, val); // keep a reference to the object
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pk_arraycontains(py_Ref self, py_Ref val) {
|
||||
py_TValue* p;
|
||||
int length = pk_arrayview(self, &p);
|
||||
@ -74,25 +57,39 @@ bool pk_arraycontains(py_Ref self, py_Ref val) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool array_iterator__iter__(int argc, py_Ref argv) {
|
||||
bool list_iterator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
*py_retval() = *argv;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool array_iterator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
array_iterator* ud = py_touserdata(argv);
|
||||
if(ud->index < ud->length) {
|
||||
*py_retval() = ud->p[ud->index++];
|
||||
list_iterator* ud = py_touserdata(argv);
|
||||
if(ud->index < ud->vec->length) {
|
||||
py_TValue* res = c11__at(py_TValue, ud->vec, ud->index);
|
||||
py_assign(py_retval(), res);
|
||||
ud->index++;
|
||||
return true;
|
||||
}
|
||||
return StopIteration();
|
||||
}
|
||||
|
||||
py_Type pk_array_iterator__register() {
|
||||
py_Type type = pk_newtype("array_iterator", tp_object, NULL, NULL, false, true);
|
||||
py_bindmagic(type, __iter__, array_iterator__iter__);
|
||||
py_bindmagic(type, __next__, array_iterator__next__);
|
||||
bool tuple_iterator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
tuple_iterator* ud = py_touserdata(argv);
|
||||
if(ud->index < ud->length) {
|
||||
py_assign(py_retval(), ud->p + ud->index);
|
||||
ud->index++;
|
||||
return true;
|
||||
}
|
||||
return StopIteration();
|
||||
}
|
||||
|
||||
py_Type pk_list_iterator__register() {
|
||||
py_Type type = pk_newtype("list_iterator", tp_object, NULL, NULL, false, true);
|
||||
py_bindmagic(type, __iter__, pk_wrapper__self);
|
||||
py_bindmagic(type, __next__, list_iterator__next__);
|
||||
return type;
|
||||
}
|
||||
|
||||
py_Type pk_tuple_iterator__register() {
|
||||
py_Type type = pk_newtype("tuple_iterator", tp_object, NULL, NULL, false, true);
|
||||
py_bindmagic(type, __iter__, pk_wrapper__self);
|
||||
py_bindmagic(type, __next__, tuple_iterator__next__);
|
||||
return type;
|
||||
}
|
||||
|
@ -5,6 +5,16 @@
|
||||
#include "pocketpy/interpreter/types.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
typedef struct {
|
||||
Dict* dict; // weakref for slot 0
|
||||
Dict dict_backup;
|
||||
DictEntry* curr;
|
||||
DictEntry* end;
|
||||
int mode; // 0: keys, 1: values, 2: items
|
||||
} DictIterator;
|
||||
|
||||
#define Dict__step(x) ((x) < mask ? (x) + 1 : 0)
|
||||
|
||||
static uint32_t Dict__next_cap(uint32_t cap) {
|
||||
switch(cap) {
|
||||
case 7: return 17;
|
||||
@ -51,19 +61,36 @@ static uint32_t Dict__next_cap(uint32_t cap) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
DictEntry* curr;
|
||||
DictEntry* end;
|
||||
int mode; // 0: keys, 1: values, 2: items
|
||||
} DictIterator;
|
||||
static uint64_t Dict__hash_2nd(uint64_t key) {
|
||||
// https://gist.github.com/badboy/6267743
|
||||
key = (~key) + (key << 21); // key = (key << 21) - key - 1
|
||||
key = key ^ (key >> 24);
|
||||
key = (key + (key << 3)) + (key << 8); // key * 265
|
||||
key = key ^ (key >> 14);
|
||||
key = (key + (key << 2)) + (key << 4); // key * 21
|
||||
key = key ^ (key >> 28);
|
||||
key = key + (key << 31);
|
||||
return key;
|
||||
}
|
||||
|
||||
static void Dict__ctor(Dict* self, uint32_t capacity, int entries_capacity) {
|
||||
self->length = 0;
|
||||
self->capacity = capacity;
|
||||
self->indices = PK_MALLOC(self->capacity * sizeof(DictIndex));
|
||||
memset(self->indices, -1, self->capacity * sizeof(DictIndex));
|
||||
|
||||
size_t indices_size;
|
||||
if(self->capacity < UINT16_MAX) {
|
||||
self->index_is_short = true;
|
||||
indices_size = self->capacity * sizeof(uint16_t);
|
||||
self->null_index_value = UINT16_MAX;
|
||||
} else {
|
||||
self->index_is_short = false;
|
||||
indices_size = self->capacity * sizeof(uint32_t);
|
||||
self->null_index_value = UINT32_MAX;
|
||||
}
|
||||
|
||||
self->indices = PK_MALLOC(indices_size);
|
||||
memset(self->indices, -1, indices_size);
|
||||
|
||||
c11_vector__ctor(&self->entries, sizeof(DictEntry));
|
||||
c11_vector__reserve(&self->entries, entries_capacity);
|
||||
}
|
||||
@ -75,70 +102,118 @@ static void Dict__dtor(Dict* self) {
|
||||
c11_vector__dtor(&self->entries);
|
||||
}
|
||||
|
||||
static bool Dict__try_get(Dict* self, py_TValue* key, DictEntry** out) {
|
||||
py_i64 hash;
|
||||
if(!py_hash(key, &hash)) return false;
|
||||
int idx = (uint64_t)hash % self->capacity;
|
||||
for(int i = 0; i < PK_DICT_MAX_COLLISION; i++) {
|
||||
int idx2 = self->indices[idx]._[i];
|
||||
if(idx2 == -1) continue;
|
||||
static uint32_t Dict__get_index(Dict* self, uint32_t index) {
|
||||
if(self->index_is_short) {
|
||||
uint16_t* indices = self->indices;
|
||||
return indices[index];
|
||||
} else {
|
||||
uint32_t* indices = self->indices;
|
||||
return indices[index];
|
||||
}
|
||||
}
|
||||
|
||||
static void Dict__swap_null_index(Dict* self, uint32_t pre_z, uint32_t z) {
|
||||
if(self->index_is_short) {
|
||||
uint16_t* indices = self->indices;
|
||||
assert(indices[pre_z] == UINT16_MAX);
|
||||
indices[pre_z] = indices[z];
|
||||
indices[z] = UINT16_MAX;
|
||||
} else {
|
||||
uint32_t* indices = self->indices;
|
||||
assert(indices[pre_z] == UINT32_MAX);
|
||||
indices[pre_z] = indices[z];
|
||||
indices[z] = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static void Dict__set_index(Dict* self, uint32_t index, uint32_t value) {
|
||||
if(self->index_is_short) {
|
||||
uint16_t* indices = self->indices;
|
||||
indices[index] = (uint16_t)value;
|
||||
} else {
|
||||
uint32_t* indices = self->indices;
|
||||
indices[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static bool Dict__probe(Dict* self,
|
||||
py_TValue* key,
|
||||
uint64_t* p_hash,
|
||||
uint32_t* p_idx,
|
||||
DictEntry** p_entry) {
|
||||
py_i64 h_user;
|
||||
if(!py_hash(key, &h_user)) return false;
|
||||
if(py_isstr(key)) {
|
||||
*p_hash = (uint64_t)h_user;
|
||||
} else {
|
||||
*p_hash = Dict__hash_2nd((uint64_t)h_user);
|
||||
}
|
||||
uint32_t mask = self->capacity - 1;
|
||||
uint32_t idx = (*p_hash) % self->capacity;
|
||||
while(true) {
|
||||
uint32_t idx2 = Dict__get_index(self, idx);
|
||||
if(idx2 == self->null_index_value) break;
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, idx2);
|
||||
if(entry->hash == (uint64_t)hash) {
|
||||
if(entry->hash == (*p_hash)) {
|
||||
int res = py_equal(&entry->key, key);
|
||||
if(res == 1) {
|
||||
*out = entry;
|
||||
*p_idx = idx;
|
||||
*p_entry = entry;
|
||||
return true;
|
||||
}
|
||||
if(res == -1) return false; // error
|
||||
}
|
||||
// try next index
|
||||
idx = Dict__step(idx);
|
||||
}
|
||||
*out = NULL;
|
||||
// not found
|
||||
*p_idx = idx;
|
||||
*p_entry = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Dict__try_get(Dict* self, py_TValue* key, DictEntry** out) {
|
||||
uint64_t hash;
|
||||
uint32_t idx;
|
||||
return Dict__probe(self, key, &hash, &idx, out);
|
||||
}
|
||||
|
||||
static void Dict__clear(Dict* self) {
|
||||
memset(self->indices, -1, self->capacity * sizeof(DictIndex));
|
||||
size_t indices_size = self->index_is_short ? self->capacity * sizeof(uint16_t)
|
||||
: self->capacity * sizeof(uint32_t);
|
||||
memset(self->indices, -1, indices_size);
|
||||
c11_vector__clear(&self->entries);
|
||||
self->length = 0;
|
||||
}
|
||||
|
||||
static void Dict__rehash_2x(Dict* self) {
|
||||
Dict old_dict = *self;
|
||||
uint32_t new_capacity = self->capacity;
|
||||
|
||||
__RETRY:
|
||||
// use next capacity
|
||||
new_capacity = Dict__next_cap(new_capacity);
|
||||
uint32_t new_capacity = Dict__next_cap(old_dict.capacity);
|
||||
uint32_t mask = new_capacity - 1;
|
||||
// create a new dict with new capacity
|
||||
Dict__ctor(self, new_capacity, old_dict.entries.capacity);
|
||||
// move entries from old dict to new dict
|
||||
for(int i = 0; i < old_dict.entries.length; i++) {
|
||||
DictEntry* old_entry = c11__at(DictEntry, &old_dict.entries, i);
|
||||
if(py_isnil(&old_entry->key)) continue;
|
||||
int idx = old_entry->hash % new_capacity;
|
||||
bool success = false;
|
||||
for(int i = 0; i < PK_DICT_MAX_COLLISION; i++) {
|
||||
int idx2 = self->indices[idx]._[i];
|
||||
if(idx2 == -1) {
|
||||
// insert new entry (empty slot)
|
||||
if(py_isnil(&old_entry->key)) continue; // skip deleted
|
||||
uint32_t idx = old_entry->hash % new_capacity;
|
||||
while(true) {
|
||||
uint32_t idx2 = Dict__get_index(self, idx);
|
||||
if(idx2 == self->null_index_value) {
|
||||
c11_vector__push(DictEntry, &self->entries, *old_entry);
|
||||
self->indices[idx]._[i] = self->entries.length - 1;
|
||||
Dict__set_index(self, idx, self->entries.length - 1);
|
||||
self->length++;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!success) {
|
||||
Dict__dtor(self);
|
||||
goto __RETRY;
|
||||
// try next index
|
||||
idx = Dict__step(idx);
|
||||
}
|
||||
}
|
||||
// done
|
||||
Dict__dtor(&old_dict);
|
||||
}
|
||||
|
||||
static void Dict__compact_entries(Dict* self) {
|
||||
int* mappings = PK_MALLOC(self->entries.length * sizeof(int));
|
||||
uint32_t* mappings = PK_MALLOC(self->entries.length * sizeof(uint32_t));
|
||||
|
||||
int n = 0;
|
||||
for(int i = 0; i < self->entries.length; i++) {
|
||||
@ -153,96 +228,97 @@ static void Dict__compact_entries(Dict* self) {
|
||||
}
|
||||
self->entries.length = n;
|
||||
// update indices
|
||||
for(uint32_t i = 0; i < self->capacity; i++) {
|
||||
for(int j = 0; j < PK_DICT_MAX_COLLISION; j++) {
|
||||
int idx = self->indices[i]._[j];
|
||||
if(idx == -1) continue;
|
||||
self->indices[i]._[j] = mappings[idx];
|
||||
}
|
||||
for(uint32_t idx = 0; idx < self->capacity; idx++) {
|
||||
uint32_t idx2 = Dict__get_index(self, idx);
|
||||
if(idx2 == self->null_index_value) continue;
|
||||
Dict__set_index(self, idx, mappings[idx2]);
|
||||
}
|
||||
PK_FREE(mappings);
|
||||
}
|
||||
|
||||
static bool Dict__set(Dict* self, py_TValue* key, py_TValue* val) {
|
||||
py_i64 hash;
|
||||
if(!py_hash(key, &hash)) return false;
|
||||
int idx = (uint64_t)hash % self->capacity;
|
||||
int bad_hash_count = 0;
|
||||
for(int i = 0; i < PK_DICT_MAX_COLLISION; i++) {
|
||||
int idx2 = self->indices[idx]._[i];
|
||||
if(idx2 == -1) {
|
||||
// insert new entry
|
||||
DictEntry* new_entry = c11_vector__emplace(&self->entries);
|
||||
new_entry->hash = (uint64_t)hash;
|
||||
new_entry->key = *key;
|
||||
new_entry->val = *val;
|
||||
self->indices[idx]._[i] = self->entries.length - 1;
|
||||
self->length++;
|
||||
return true;
|
||||
}
|
||||
uint64_t hash;
|
||||
uint32_t idx;
|
||||
DictEntry* entry;
|
||||
if(!Dict__probe(self, key, &hash, &idx, &entry)) return false;
|
||||
if(entry) {
|
||||
// update existing entry
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, idx2);
|
||||
// check if they have the same hash
|
||||
if(entry->hash == (uint64_t)hash) {
|
||||
// check if they are equal
|
||||
int res = py_equal(&entry->key, key);
|
||||
if(res == 1) {
|
||||
entry->val = *val;
|
||||
return true;
|
||||
}
|
||||
if(res == -1) return false; // error
|
||||
// res == 0
|
||||
bad_hash_count++;
|
||||
}
|
||||
entry->val = *val;
|
||||
return true;
|
||||
}
|
||||
// no empty slot found
|
||||
if(bad_hash_count == PK_DICT_MAX_COLLISION) {
|
||||
// all `PK_DICT_MAX_COLLISION` slots have the same hash but different keys
|
||||
// we are unable to solve this collision via rehashing
|
||||
return RuntimeError("dict: %d/%d/%d: maximum collision reached (hash=%i)",
|
||||
self->entries.length,
|
||||
self->entries.capacity,
|
||||
self->capacity,
|
||||
hash);
|
||||
}
|
||||
|
||||
if(self->capacity >= (uint32_t)self->entries.length * 10) {
|
||||
return RuntimeError("dict: %d/%d/%d: minimum load factor reached",
|
||||
self->entries.length,
|
||||
self->entries.capacity,
|
||||
self->capacity);
|
||||
}
|
||||
Dict__rehash_2x(self);
|
||||
return Dict__set(self, key, val);
|
||||
// insert new entry
|
||||
DictEntry* new_entry = c11_vector__emplace(&self->entries);
|
||||
new_entry->hash = hash;
|
||||
new_entry->key = *key;
|
||||
new_entry->val = *val;
|
||||
Dict__set_index(self, idx, self->entries.length - 1);
|
||||
self->length++;
|
||||
// check if we need to rehash
|
||||
float load_factor = (float)self->length / self->capacity;
|
||||
if(load_factor > (self->index_is_short ? 0.3f : 0.4f)) Dict__rehash_2x(self);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Delete an entry from the dict.
|
||||
/// -1: error, 0: not found, 1: found and deleted
|
||||
static int Dict__pop(Dict* self, py_Ref key) {
|
||||
py_i64 hash;
|
||||
if(!py_hash(key, &hash)) return -1;
|
||||
int idx = (uint64_t)hash % self->capacity;
|
||||
for(int i = 0; i < PK_DICT_MAX_COLLISION; i++) {
|
||||
int idx2 = self->indices[idx]._[i];
|
||||
if(idx2 == -1) continue;
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, idx2);
|
||||
if(entry->hash == (uint64_t)hash) {
|
||||
int res = py_equal(&entry->key, key);
|
||||
if(res == 1) {
|
||||
*py_retval() = entry->val;
|
||||
py_newnil(&entry->key);
|
||||
self->indices[idx]._[i] = -1;
|
||||
self->length--;
|
||||
if(self->length < self->entries.length / 2) Dict__compact_entries(self);
|
||||
return 1;
|
||||
}
|
||||
if(res == -1) return -1; // error
|
||||
// Dict__log_index(self, "before pop");
|
||||
uint64_t hash;
|
||||
uint32_t idx;
|
||||
DictEntry* entry;
|
||||
if(!Dict__probe(self, key, &hash, &idx, &entry)) return -1;
|
||||
if(!entry) return 0; // not found
|
||||
|
||||
// found the entry, delete and return it
|
||||
py_assign(py_retval(), &entry->val);
|
||||
Dict__set_index(self, idx, self->null_index_value);
|
||||
py_newnil(&entry->key);
|
||||
py_newnil(&entry->val);
|
||||
self->length--;
|
||||
|
||||
/* tidy */
|
||||
// https://github.com/OpenHFT/Chronicle-Map/blob/820573a68471509ffc1b0584454f4a67c0be1b84/src/main/java/net/openhft/chronicle/hash/impl/CompactOffHeapLinearHashTable.java#L156
|
||||
uint32_t mask = self->capacity - 1;
|
||||
uint32_t posToRemove = idx;
|
||||
uint32_t posToShift = posToRemove;
|
||||
// int probe_count = 0;
|
||||
// int swap_count = 0;
|
||||
while(true) {
|
||||
posToShift = Dict__step(posToShift);
|
||||
uint32_t idx_z = Dict__get_index(self, posToShift);
|
||||
if(idx_z == self->null_index_value) break;
|
||||
uint64_t hash_z = c11__at(DictEntry, &self->entries, idx_z)->hash;
|
||||
uint32_t insertPos = (uint64_t)hash_z % self->capacity;
|
||||
// the following condition essentially means circular permutations
|
||||
// of three (r = posToRemove, s = posToShift, i = insertPos)
|
||||
// positions are accepted:
|
||||
// [...i..r...s.] or
|
||||
// [...r..s...i.] or
|
||||
// [...s..i...r.]
|
||||
bool cond1 = insertPos <= posToRemove;
|
||||
bool cond2 = posToRemove <= posToShift;
|
||||
if((cond1 && cond2) ||
|
||||
// chain wrapped around capacity
|
||||
(posToShift < insertPos && (cond1 || cond2))) {
|
||||
Dict__swap_null_index(self, posToRemove, posToShift);
|
||||
posToRemove = posToShift;
|
||||
// swap_count++;
|
||||
}
|
||||
// probe_count++;
|
||||
}
|
||||
return 0;
|
||||
// printf("Dict__pop: probe_count=%d, swap_count=%d\n", probe_count, swap_count);
|
||||
// compact entries if necessary
|
||||
if(self->entries.length > 16 && (self->length < self->entries.length >> 1)) {
|
||||
Dict__compact_entries(self); // compact entries
|
||||
}
|
||||
// Dict__log_index(self, "after pop");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void DictIterator__ctor(DictIterator* self, Dict* dict, int mode) {
|
||||
assert(mode >= 0 && mode <= 2);
|
||||
self->dict = dict;
|
||||
self->dict_backup = *dict; // backup the dict
|
||||
self->curr = dict->entries.data;
|
||||
self->end = self->curr + dict->entries.length;
|
||||
self->mode = mode;
|
||||
@ -257,18 +333,22 @@ static DictEntry* DictIterator__next(DictIterator* self) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool DictIterator__modified(DictIterator* self) {
|
||||
return memcmp(self->dict, &self->dict_backup, sizeof(Dict)) != 0;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
static bool dict__new__(int argc, py_Ref argv) {
|
||||
py_Type cls = py_totype(argv);
|
||||
int slots = cls == tp_dict ? 0 : -1;
|
||||
Dict* ud = py_newobject(py_retval(), cls, slots, sizeof(Dict));
|
||||
Dict__ctor(ud, 7, 8);
|
||||
Dict__ctor(ud, 17, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
void py_newdict(py_OutRef out) {
|
||||
Dict* ud = py_newobject(out, tp_dict, 0, sizeof(Dict));
|
||||
Dict__ctor(ud, 7, 8);
|
||||
Dict__ctor(ud, 17, 4);
|
||||
}
|
||||
|
||||
static bool dict__init__(int argc, py_Ref argv) {
|
||||
@ -426,12 +506,17 @@ static bool dict_copy(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
Dict* self = py_touserdata(argv);
|
||||
Dict* new_dict = py_newobject(py_retval(), tp_dict, 0, sizeof(Dict));
|
||||
new_dict->capacity = self->capacity;
|
||||
new_dict->length = self->length;
|
||||
new_dict->capacity = self->capacity;
|
||||
new_dict->null_index_value = self->null_index_value;
|
||||
new_dict->index_is_short = self->index_is_short;
|
||||
// copy entries
|
||||
new_dict->entries = c11_vector__copy(&self->entries);
|
||||
// copy indices
|
||||
new_dict->indices = PK_MALLOC(new_dict->capacity * sizeof(DictIndex));
|
||||
memcpy(new_dict->indices, self->indices, new_dict->capacity * sizeof(DictIndex));
|
||||
size_t indices_size = self->index_is_short ? self->capacity * sizeof(uint16_t)
|
||||
: self->capacity * sizeof(uint32_t);
|
||||
new_dict->indices = PK_MALLOC(indices_size);
|
||||
memcpy(new_dict->indices, self->indices, indices_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -525,9 +610,10 @@ py_Type pk_dict__register() {
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
static bool dict_items__next__(int argc, py_Ref argv) {
|
||||
bool dict_items__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
DictIterator* iter = py_touserdata(py_arg(0));
|
||||
if(DictIterator__modified(iter)) return RuntimeError("dictionary modified during iteration");
|
||||
DictEntry* entry = (DictIterator__next(iter));
|
||||
if(entry) {
|
||||
switch(iter->mode) {
|
||||
@ -641,4 +727,4 @@ bool py_dict_apply(py_Ref self, bool (*f)(py_Ref, py_Ref, void*), void* ctx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef PK_DICT_MAX_COLLISION
|
||||
#undef Dict__step
|
@ -3,6 +3,7 @@
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/interpreter/types.h"
|
||||
#include "pocketpy/objects/iterator.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
|
||||
void py_newlist(py_OutRef out) {
|
||||
@ -394,7 +395,11 @@ static bool list_sort(int argc, py_Ref argv) {
|
||||
|
||||
static bool list__iter__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
return pk_arrayiter(argv);
|
||||
list_iterator* ud = py_newobject(py_retval(), tp_list_iterator, 1, sizeof(list_iterator));
|
||||
ud->vec = py_touserdata(argv);
|
||||
ud->index = 0;
|
||||
py_setslot(py_retval(), 0, argv); // keep a reference to the object
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool list__contains__(int argc, py_Ref argv) {
|
||||
|
@ -175,6 +175,32 @@ static bool int__mod__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool float__mod__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
py_f64 lhs = py_tofloat(&argv[0]);
|
||||
py_f64 rhs;
|
||||
if(try_castfloat(&argv[1], &rhs)) {
|
||||
if(rhs == 0.0) return ZeroDivisionError("float modulo by zero");
|
||||
py_newfloat(py_retval(), fmod(lhs, rhs));
|
||||
return true;
|
||||
}
|
||||
py_newnotimplemented(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool float__rmod__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
py_f64 rhs = py_tofloat(&argv[0]);
|
||||
py_f64 lhs;
|
||||
if(try_castfloat(&argv[1], &lhs)) {
|
||||
if(rhs == 0.0) return ZeroDivisionError("float modulo by zero");
|
||||
py_newfloat(py_retval(), fmod(lhs, rhs));
|
||||
return true;
|
||||
}
|
||||
py_newnotimplemented(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool int__divmod__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
@ -245,24 +271,6 @@ static bool float__repr__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
union c11_8bytes {
|
||||
py_i64 _i64;
|
||||
py_f64 _f64;
|
||||
|
||||
union {
|
||||
uint32_t upper;
|
||||
uint32_t lower;
|
||||
} bits;
|
||||
};
|
||||
|
||||
static py_i64 c11_8bytes__hash(union c11_8bytes u) {
|
||||
// https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key
|
||||
const uint32_t C = 2654435761;
|
||||
u.bits.upper *= C;
|
||||
u.bits.lower *= C;
|
||||
return u._i64;
|
||||
}
|
||||
|
||||
static bool int__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_assign(py_retval(), argv);
|
||||
@ -272,8 +280,9 @@ static bool int__hash__(int argc, py_Ref argv) {
|
||||
static bool float__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_f64 val = py_tofloat(&argv[0]);
|
||||
union c11_8bytes u = {._f64 = val};
|
||||
py_newint(py_retval(), c11_8bytes__hash(u));
|
||||
py_i64 h_user;
|
||||
memcpy(&h_user, &val, sizeof(py_f64));
|
||||
py_newint(py_retval(), h_user);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -525,6 +534,10 @@ void pk_number__register() {
|
||||
py_bindmagic(tp_int, __mod__, int__mod__);
|
||||
py_bindmagic(tp_int, __divmod__, int__divmod__);
|
||||
|
||||
// fmod
|
||||
py_bindmagic(tp_float, __mod__, float__mod__);
|
||||
py_bindmagic(tp_float, __rmod__, float__rmod__);
|
||||
|
||||
// int.__invert__ & int.<BITWISE OP>
|
||||
py_bindmagic(tp_int, __invert__, int__invert__);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/typeinfo.h"
|
||||
#include "pocketpy/interpreter/bindings.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
@ -77,12 +78,39 @@ bool py_iter(py_Ref val) {
|
||||
|
||||
int py_next(py_Ref val) {
|
||||
VM* vm = pk_current_vm;
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __next__);
|
||||
if(!tmp) {
|
||||
TypeError("'%t' object is not an iterator", val->type);
|
||||
return -1;
|
||||
|
||||
switch(val->type) {
|
||||
case tp_generator:
|
||||
if(generator__next__(1, val)) return 1;
|
||||
break;
|
||||
case tp_array2d_like_iterator:
|
||||
if(array2d_like_iterator__next__(1, val)) return 1;
|
||||
break;
|
||||
case tp_list_iterator:
|
||||
if(list_iterator__next__(1, val)) return 1;
|
||||
break;
|
||||
case tp_tuple_iterator:
|
||||
if(tuple_iterator__next__(1, val)) return 1;
|
||||
break;
|
||||
case tp_dict_iterator:
|
||||
if(dict_items__next__(1, val)) return 1;
|
||||
break;
|
||||
case tp_range_iterator:
|
||||
if(range_iterator__next__(1, val)) return 1;
|
||||
break;
|
||||
case tp_str_iterator:
|
||||
if(str_iterator__next__(1, val)) return 1;
|
||||
break;
|
||||
default: {
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __next__);
|
||||
if(!tmp) {
|
||||
TypeError("'%t' object is not an iterator", val->type);
|
||||
return -1;
|
||||
}
|
||||
if(py_call(tmp, 1, val)) return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(py_call(tmp, 1, val)) return 1;
|
||||
if(vm->curr_exception.type == tp_StopIteration) {
|
||||
vm->last_retval = vm->curr_exception;
|
||||
py_clearexc(NULL);
|
||||
@ -94,6 +122,8 @@ int py_next(py_Ref val) {
|
||||
bool py_getattr(py_Ref self, py_Name name) {
|
||||
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
||||
py_TypeInfo* ti = pk_typeinfo(self->type);
|
||||
if(ti->getattribute) return ti->getattribute(self, name);
|
||||
|
||||
py_Ref cls_var = pk_tpfindname(ti, name);
|
||||
if(cls_var) {
|
||||
// handle descriptor
|
||||
@ -184,8 +214,10 @@ bool py_getattr(py_Ref self, py_Name name) {
|
||||
}
|
||||
|
||||
bool py_setattr(py_Ref self, py_Name name, py_Ref val) {
|
||||
py_Type type = self->type;
|
||||
py_Ref cls_var = py_tpfindname(type, name);
|
||||
py_TypeInfo* ti = pk_typeinfo(self->type);
|
||||
if(ti->setattribute) return ti->setattribute(self, name, val);
|
||||
|
||||
py_Ref cls_var = pk_tpfindname(ti, name);
|
||||
if(cls_var) {
|
||||
// handle descriptor
|
||||
if(py_istype(cls_var, tp_property)) {
|
||||
@ -211,6 +243,9 @@ bool py_setattr(py_Ref self, py_Name name, py_Ref val) {
|
||||
}
|
||||
|
||||
bool py_delattr(py_Ref self, py_Name name) {
|
||||
py_TypeInfo* ti = pk_typeinfo(self->type);
|
||||
if(ti->delattribute) return ti->delattribute(self, name);
|
||||
|
||||
if(self->is_ptr && self->_obj->slots == -1) {
|
||||
if(py_deldict(self, name)) return true;
|
||||
return AttributeError(self, name);
|
||||
|
@ -68,9 +68,9 @@ static bool range_iterator__new__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool range_iterator__next__(int argc, py_Ref argv) {
|
||||
bool range_iterator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
RangeIterator* ud = py_touserdata(py_arg(0));
|
||||
RangeIterator* ud = py_touserdata(argv);
|
||||
if(ud->range.step > 0) {
|
||||
if(ud->current >= ud->range.stop) return StopIteration();
|
||||
} else {
|
||||
|
@ -9,7 +9,7 @@
|
||||
void py_newstr(py_OutRef out, const char* data) { py_newstrv(out, (c11_sv){data, strlen(data)}); }
|
||||
|
||||
char* py_newstrn(py_OutRef out, int size) {
|
||||
if(size < 8) {
|
||||
if(size < 16) {
|
||||
out->type = tp_str;
|
||||
out->is_ptr = false;
|
||||
c11_string* ud = (c11_string*)(&out->extra);
|
||||
@ -327,7 +327,7 @@ static bool str_split(int argc, py_Ref argv) {
|
||||
if(argc > 2) return TypeError("split() takes at most 2 arguments");
|
||||
if(argc == 1) {
|
||||
// sep = None
|
||||
res = c11_sv__split(self, ' ');
|
||||
res = c11_sv__splitwhitespace(self);
|
||||
discard_empty = true;
|
||||
}
|
||||
if(argc == 2) {
|
||||
@ -513,7 +513,7 @@ py_Type pk_str__register() {
|
||||
return type;
|
||||
}
|
||||
|
||||
static bool str_iterator__next__(int argc, py_Ref argv) {
|
||||
bool str_iterator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int* ud = py_touserdata(&argv[0]);
|
||||
int size;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/objects/iterator.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
py_ObjectRef py_newtuple(py_OutRef out, int n) {
|
||||
@ -144,7 +145,12 @@ static bool tuple__lt__(int argc, py_Ref argv) {
|
||||
|
||||
static bool tuple__iter__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
return pk_arrayiter(argv);
|
||||
tuple_iterator* ud = py_newobject(py_retval(), tp_tuple_iterator, 1, sizeof(tuple_iterator));
|
||||
ud->p = py_tuple_data(argv);
|
||||
ud->length = py_tuple_len(argv);
|
||||
ud->index = 0;
|
||||
py_setslot(py_retval(), 0, argv); // keep a reference to the object
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool tuple__contains__(int argc, py_Ref argv) {
|
||||
|
@ -8,12 +8,12 @@ py_Ref py_getreg(int i) { return pk_current_vm->reg + i; }
|
||||
|
||||
void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; }
|
||||
|
||||
py_Ref py_getdict(py_Ref self, py_Name name) {
|
||||
PK_INLINE py_Ref py_getdict(py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
return NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
}
|
||||
|
||||
void py_setdict(py_Ref self, py_Name name, py_Ref val) {
|
||||
PK_INLINE void py_setdict(py_Ref self, py_Name name, py_Ref val) {
|
||||
assert(self && self->is_ptr);
|
||||
NameDict__set(PyObject__dict(self->_obj), name, val);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
bool py_istype(py_Ref self, py_Type type) { return self->type == type; }
|
||||
PK_INLINE bool py_istype(py_Ref self, py_Type type) { return self->type == type; }
|
||||
|
||||
bool py_checktype(py_Ref self, py_Type type) {
|
||||
if(self->type == type) return true;
|
||||
|
@ -13,6 +13,13 @@ void py_newint(py_OutRef out, py_i64 val) {
|
||||
out->_i64 = val;
|
||||
}
|
||||
|
||||
void py_newtrivial(py_OutRef out, py_Type type, void* data, int size) {
|
||||
out->type = type;
|
||||
out->is_ptr = false;
|
||||
assert(size <= 16);
|
||||
memcpy(&out->_chars, data, size);
|
||||
}
|
||||
|
||||
void py_newfloat(py_OutRef out, py_f64 val) {
|
||||
out->type = tp_float;
|
||||
out->is_ptr = false;
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -20,7 +19,7 @@ static char* read_file(const char* path) {
|
||||
fseek(file, 0, SEEK_END);
|
||||
long size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
char* buffer = malloc(size + 1);
|
||||
char* buffer = PK_MALLOC(size + 1);
|
||||
size = fread(buffer, 1, size, file);
|
||||
buffer[size] = 0;
|
||||
return buffer;
|
||||
@ -86,7 +85,7 @@ int main(int argc, char** argv) {
|
||||
char* source = read_file(filename);
|
||||
if(source) {
|
||||
if(!py_exec(source, filename, EXEC_MODE, NULL)) py_printexc();
|
||||
free(source);
|
||||
PK_FREE(source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,3 +109,8 @@ assert abs(0.0) == 0.0
|
||||
# exit(1)
|
||||
# except ValueError:
|
||||
# pass
|
||||
|
||||
assert eq(10 % 4, 2)
|
||||
assert eq(10.5 % 4, 2.5)
|
||||
assert eq(10 % 4.5, 1.0)
|
||||
assert eq(10.5 % 4.5, 1.5)
|
@ -57,6 +57,9 @@ assert 'aa bb cccc'.split('cc') == ['aa bb ', '', '']
|
||||
assert '.a.b.'.split('.') == ['', 'a', 'b', '']
|
||||
assert '.a...b.'.split('.') == ['', 'a', '', '', 'b', '']
|
||||
|
||||
# https://github.com/pocketpy/pocketpy/issues/378
|
||||
assert "a b \n c\td".split() == ['a', 'b', 'c', 'd']
|
||||
|
||||
try:
|
||||
'a'.split('')
|
||||
exit(1)
|
||||
@ -228,3 +231,7 @@ assert f"{(1, 2, 3)}" == "(1, 2, 3)"
|
||||
|
||||
# stack=[1,2,3,4]
|
||||
# assert f"{stack[2:]}" == '[3, 4]'
|
||||
|
||||
|
||||
assert id('1' * 16) is not None
|
||||
assert id('1' * 15) is None
|
@ -115,30 +115,7 @@ assert a.pop(1) == 2
|
||||
|
||||
assert a.pop(1, None) is None
|
||||
|
||||
n = 2 ** 17
|
||||
a = {}
|
||||
for i in range(n):
|
||||
a[str(i)] = i
|
||||
|
||||
for i in range(n):
|
||||
y = a[str(i)]
|
||||
|
||||
for i in range(n):
|
||||
del a[str(i)]
|
||||
|
||||
# namedict delete test
|
||||
# class A: pass
|
||||
# a = A()
|
||||
# b = ['0', '1']
|
||||
|
||||
# for i in range(len(data)):
|
||||
# z = data[i]
|
||||
# setattr(a, str(z), i)
|
||||
# b.append(z)
|
||||
# if i % 3 == 0:
|
||||
# y = b.pop()
|
||||
# delattr(a, y)
|
||||
|
||||
# test getitem
|
||||
d = {}
|
||||
for i in range(-1000, 1000):
|
||||
d[i] = i
|
||||
@ -155,3 +132,37 @@ assert list(d) == ['1', 222, '333']
|
||||
assert list(d.keys()) == ['1', 222, '333']
|
||||
assert list(d.values()) == [1, 2, 3]
|
||||
assert list(d.items()) == [('1', 1), (222, 2), ('333', 3)]
|
||||
|
||||
# test del
|
||||
n = 2 ** 17
|
||||
a = {}
|
||||
for i in range(n):
|
||||
a[str(i)] = i
|
||||
for i in range(n):
|
||||
del a[str(i)]
|
||||
assert len(a) == 0
|
||||
|
||||
# test del with int keys
|
||||
if 0:
|
||||
n = 2 ** 17
|
||||
a = {}
|
||||
for i in range(n):
|
||||
a[i] = i
|
||||
for i in range(n):
|
||||
del a[i]
|
||||
assert len(a) == 0
|
||||
|
||||
#######################
|
||||
|
||||
# namedict delete test
|
||||
class A: pass
|
||||
a = A()
|
||||
b = ['0', '1']
|
||||
|
||||
for i in range(len(data)):
|
||||
z = data[i]
|
||||
setattr(a, str(z), i)
|
||||
b.append(z)
|
||||
if i % 3 == 0:
|
||||
y = b.pop()
|
||||
delattr(a, y)
|
@ -126,7 +126,13 @@ class MyClass:
|
||||
b, c = 1, 2
|
||||
d = b + c
|
||||
|
||||
def __init__(self, m, n) -> None:
|
||||
self.m: int = m
|
||||
self.n: float = n
|
||||
|
||||
assert MyClass.a == (1, 2, 3)
|
||||
assert MyClass.b == 1
|
||||
assert MyClass.c == 2
|
||||
assert MyClass.d == 3
|
||||
|
||||
assert MyClass(1, 2).m == 1
|
@ -74,3 +74,5 @@ exec(code, {'x': 42, 'res': res})
|
||||
assert res == [42, 42]
|
||||
assert x == 33
|
||||
|
||||
# test removing trailing newlines
|
||||
assert eval('[1, 2, 3]\n \n') == [1, 2, 3]
|
@ -157,4 +157,16 @@ assert a == 5
|
||||
a, b, c = (1, 2, 3) if True else (4, 5, 6)
|
||||
assert a == 1
|
||||
assert b == 2
|
||||
assert c == 3
|
||||
assert c == 3
|
||||
|
||||
# https://github.com/pocketpy/pocketpy/issues/376
|
||||
xs = [0]
|
||||
res = []
|
||||
for x in xs:
|
||||
res.append(x)
|
||||
if x == 100:
|
||||
break
|
||||
xs.append(x+1)
|
||||
|
||||
assert res == list(range(101))
|
||||
assert xs == res
|
@ -1,4 +1,11 @@
|
||||
from pkpy import ComputeThread
|
||||
from pkpy import configmacros
|
||||
|
||||
if configmacros['PK_ENABLE_THREADS'] == 1:
|
||||
from pkpy import ComputeThread
|
||||
else:
|
||||
print('threads is not enabled, skipping test...')
|
||||
exit()
|
||||
|
||||
import time
|
||||
|
||||
thread_1 = ComputeThread(1)
|
||||
|
@ -103,9 +103,4 @@ class A:
|
||||
|
||||
bad_dict = {A(): 1, A(): 2, A(): 3, A(): 4}
|
||||
assert len(bad_dict) == 4
|
||||
try:
|
||||
bad_dict[A()] = 5 # error
|
||||
exit(1)
|
||||
except RuntimeError as e:
|
||||
assert 'maximum collision reached' in str(e)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user