Compare commits

...

4 Commits

Author SHA1 Message Date
blueloveTH
8c8c5f13cf add a new util script 2025-03-03 19:54:39 +08:00
blueloveTH
4434bfcf23 use unity build
Update build_ios.sh

update build scripts
2025-03-03 19:39:39 +08:00
blueloveTH
698a7b7f4f update flutter plugin 2025-03-03 18:04:04 +08:00
blueloveTH
5d428a8818 Create coding-style-guide.md
rename

fix doc link
2025-03-03 18:00:24 +08:00
10 changed files with 329 additions and 28 deletions

View File

@ -70,6 +70,7 @@ jobs:
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
- name: Compile and Test - name: Compile and Test
run: | run: |
python scripts/check_pragma_once.py include
mkdir -p output/x86_64 mkdir -p output/x86_64
python cmake_build.py python cmake_build.py
python scripts/run_tests.py python scripts/run_tests.py

View File

@ -5,15 +5,11 @@ project(pocketpy)
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
# use IPO # use UNITY_BUILD if CMake version >= 3.16
option(PK_BUILD_WITH_IPO "" TRUE) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16")
include(CheckIPOSupported) option(PK_BUILD_WITH_UNITY "" TRUE)
check_ipo_supported(RESULT result)
if(result AND PK_BUILD_WITH_IPO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
else() else()
message(WARNING ">> IPO disabled. You will not get the best performance.") option(PK_BUILD_WITH_UNITY "" FALSE)
endif() endif()
if(WIN32) if(WIN32)
@ -94,13 +90,20 @@ else()
target_link_libraries(main ${PROJECT_NAME}) target_link_libraries(main ${PROJECT_NAME})
endif() endif()
if(UNIX) if(UNIX AND NOT APPLE)
target_link_libraries(${PROJECT_NAME} m) target_link_libraries(${PROJECT_NAME} m)
if(PK_ENABLE_OS) if(PK_ENABLE_OS)
target_link_libraries(${PROJECT_NAME} dl) target_link_libraries(${PROJECT_NAME} dl)
endif() endif()
endif() endif()
if(PK_BUILD_WITH_UNITY)
set_source_files_properties(${POCKETPY_SRC} PROPERTIES UNITY_GROUP "pocketpy")
set_target_properties(${PROJECT_NAME} PROPERTIES UNITY_BUILD_MODE GROUP)
set_target_properties(${PROJECT_NAME} PROPERTIES UNITY_BUILD ON)
endif()
############################################
if(PK_BUILD_MODULE_LZ4) if(PK_BUILD_MODULE_LZ4)
target_link_libraries(${PROJECT_NAME} lz4) target_link_libraries(${PROJECT_NAME} lz4)
endif() endif()

View File

@ -8,10 +8,7 @@ cd build
FLAGS="-DCMAKE_TOOLCHAIN_FILE=3rd/ios.toolchain.cmake \ FLAGS="-DCMAKE_TOOLCHAIN_FILE=3rd/ios.toolchain.cmake \
-DDEPLOYMENT_TARGET=13.0 \ -DDEPLOYMENT_TARGET=13.0 \
-DPK_BUILD_STATIC_LIB=ON \ -DPK_BUILD_STATIC_LIB=ON"
-DPK_BUILD_WITH_IPO=OFF \
-DPK_BUILD_MODULE_LZ4=ON \
-DPK_BUILD_MODULE_LIBHV=ON"
cmake -B os64 -G Xcode $FLAGS -DPLATFORM=OS64 .. cmake -B os64 -G Xcode $FLAGS -DPLATFORM=OS64 ..
cmake --build os64 --config Release cmake --build os64 --config Release

221
docs/coding-style-guide.md Normal file
View File

@ -0,0 +1,221 @@
---
icon: book
order: -5
label: Coding Style Guide
---
## Indentation
Use four spaces for indentation. Do not use `TAB`.
## Strings
```python
# Prefer single quotes for strings
s = 'this is a string'
# Use double quotes only if the string itself contains a single quote
s = "this ' is single quote"
```
## Docstrings
Always use triple quotes for docstrings.
```python
def f():
"""This is a multi-line docstring.
Here is some content. Docstrings partially support Markdown.
"""
def g():
"""This is a single-line docstring."""
```
Use natural language to describe the function's purpose. Do not enumerate each parameter and return value.
```python
# Correct
def add(a: int, b: int):
"""Add two integers `a` and `b`."""
# Incorrect
def add(a: int, b: int):
"""
@param a, the first argument
@param b, the second argument
@return, the result of a + b
"""
```
## Spaces
```python
# Add a space after `,` or `:`
a, b = 1, 2
c = [1, 2, 3]
d = {'key': 'value'}
# Spaces may be added around operators
res = 1 + 2
if res < 2: pass
# Spaces can also be selectively added to indicate operator precedence
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)
# Add a space after `:` in type annotations
def f(a: int, b: float): ...
def g() -> int: ...
# Add spaces around `=` when specifying default values in function parameters
def f(a: int = 1, b: int | None = None): ...
# However, omit spaces if the parameter has no type annotation
def f(a=1, b=2): pass
# Do not add spaces in keyword arguments when calling functions
print(1, 2, 3, end='', sep=',')
f(a=10, b=20)
```
## Naming Conventions
+ Classes: `CapitalizedWords`
+ Functions and variables: `lower_case_with_underscores`
+ Constants and enums: `UPPER_CASE_WITH_UNDERSCORES` or `CapitalizedWords`
+ Anonymous ordered variables: `_0`, `_1`, `_2`
+ Discarded variables: `_`
+ Some standard library functions: `lowercase`
Here are some commonly used naming conventions:
+ `self`: The first parameter of an instance method
+ `cls`: The first parameter of class methods and `__new__`
### Using Abbreviations
Use abbreviations only for temporary variables and internal implementations.
Abbreviations should be well-established, include key syllables of the original word, and be immediately recognizable.
* `context` -> `ctx` (✔)
* `temporary` -> `tmp` (✔)
* `distribution` -> `dist` (✔)
* `visited` -> `vis` (❌)
```python
# Incorrect: Using abbreviations in public function parameters
def some_pub_fn(ctx, req_id, data):
pass
# Correct
def some_public_function(context, request_id, data):
pass
```
### Using Precise Terminology
Naming should convey precise meanings, especially when multiple synonyms exist.
For example, `count`, `size`, and `length` all relate to quantity, but they have different nuances:
+ `count`: Represents a counted value
+ `length`: Represents the number of elements in a container
+ `size`: Represents the byte size of an object
```python
s = 'aaabc⭐'
count = s.count('a')
length = len(s)
size = len(s.encode())
print(f"{s!r} has a length of {length}, a size of {size} bytes, and contains {count} occurrences of 'a'")
# 'aaabc⭐' has a length of 6, a size of 8 bytes, and contains 3 occurrences of 'a'
```
### Using Professional Terminology
+ For item quantities in a game: `quantity` is better than `item_count`
+ For grid counts: `area` (meaning surface area) is better than `grid_count`
### Avoiding Built-in Names
```python
# Incorrect: Overwriting `builtins.map`
map = [[1, 2, 3], [4, 5, 6]]
# Incorrect: Overwriting `builtins.type`
type = some_thing.type
```
### Internal Functions and Classes
Use a single underscore `_` as a prefix for internal functions. Never use a double underscore `__` (except for magic methods).
```python
def _internal_func():
"""This is an internal function."""
class _InternalClass:
def _internal_f(self): pass
```
## Importing Modules
1. Import standard library modules first.
2. Then import third-party dependencies.
3. Finally, import project-specific modules.
```python
from typing import Any
from collections import deque
from array2d import array2d
from ..utils import logger
```
## Coding Practices
Use `is not` when checking for `None`. Do not explicitly compare with `True` or `False`.
```python
# Correct
if x is not None: pass
# Incorrect
if x != None: pass
# Correct
x = True
if x: pass
if not x: pass
# Incorrect
if x == True: pass
if x is True: pass
if x != False: pass
```
The `if` statement implicitly calls `bool()`, so it can be used to check if a container is empty.
```python
not_empty_list = [1]
not_empty_string = '1'
truth = True
if not_empty_list:
print('true value')
if not_empty_string:
print('true value')
if truth:
print('true value')
# Explicitly checking for emptiness is also valid
if len(not_empty_list) > 0: pass
```
## References
[PEP 8 Style Guide for Python Code](https://peps.python.org/pep-0008/)

View File

@ -49,7 +49,7 @@ Type "exit()" to exit.
### Coding style guide ### Coding style guide
See [Coding Style Guide](../coding_style_guide.md). See [Coding Style Guide](../coding-style-guide.md).
### Contact us ### Contact us

View File

@ -49,7 +49,7 @@ Type "exit()" to exit.
### Coding style guide ### Coding style guide
See [Coding Style Guide](../coding_style_guide.md). See [Coding Style Guide](../coding-style-guide.md).
### Contact us ### Contact us

View File

@ -1,3 +1,5 @@
#pragma once
#include "pocketpy/objects/object.h" #include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/objectpool.h" #include "pocketpy/interpreter/objectpool.h"

View File

@ -269,7 +269,6 @@ class PocketpyBindings {
_py_newglobalsPtr.asFunction<void Function(py_OutRef)>(); _py_newglobalsPtr.asFunction<void Function(py_OutRef)>();
/// Python equivalent to `locals()`. /// Python equivalent to `locals()`.
/// @return a temporary object, which expires on the associated function return.
void py_newlocals( void py_newlocals(
py_OutRef arg0, py_OutRef arg0,
) { ) {
@ -421,6 +420,23 @@ class PocketpyBindings {
late final _py_newstrv = late final _py_newstrv =
_py_newstrvPtr.asFunction<void Function(py_OutRef, c11_sv)>(); _py_newstrvPtr.asFunction<void Function(py_OutRef, c11_sv)>();
/// Create a formatted `str` object.
void py_newfstr(
py_OutRef arg0,
ffi.Pointer<ffi.Char> arg1,
) {
return _py_newfstr(
arg0,
arg1,
);
}
late final _py_newfstrPtr = _lookup<
ffi.NativeFunction<
ffi.Void Function(py_OutRef, ffi.Pointer<ffi.Char>)>>('py_newfstr');
late final _py_newfstr = _py_newfstrPtr
.asFunction<void Function(py_OutRef, ffi.Pointer<ffi.Char>)>();
/// Create a `bytes` object with `n` UNINITIALIZED bytes. /// Create a `bytes` object with `n` UNINITIALIZED bytes.
ffi.Pointer<ffi.UnsignedChar> py_newbytes( ffi.Pointer<ffi.UnsignedChar> py_newbytes(
py_OutRef arg0, py_OutRef arg0,
@ -499,7 +515,7 @@ class PocketpyBindings {
/// Create a `tuple` with `n` UNINITIALIZED elements. /// Create a `tuple` with `n` UNINITIALIZED elements.
/// You should initialize all elements before using it. /// You should initialize all elements before using it.
void py_newtuple( py_ObjectRef py_newtuple(
py_OutRef arg0, py_OutRef arg0,
int n, int n,
) { ) {
@ -510,10 +526,10 @@ class PocketpyBindings {
} }
late final _py_newtuplePtr = late final _py_newtuplePtr =
_lookup<ffi.NativeFunction<ffi.Void Function(py_OutRef, ffi.Int)>>( _lookup<ffi.NativeFunction<py_ObjectRef Function(py_OutRef, ffi.Int)>>(
'py_newtuple'); 'py_newtuple');
late final _py_newtuple = late final _py_newtuple =
_py_newtuplePtr.asFunction<void Function(py_OutRef, int)>(); _py_newtuplePtr.asFunction<py_ObjectRef Function(py_OutRef, int)>();
/// Create an empty `list`. /// Create an empty `list`.
void py_newlist( void py_newlist(
@ -667,6 +683,21 @@ class PocketpyBindings {
late final _py_name2str = late final _py_name2str =
_py_name2strPtr.asFunction<ffi.Pointer<ffi.Char> Function(int)>(); _py_name2strPtr.asFunction<ffi.Pointer<ffi.Char> Function(int)>();
/// Convert a name to a python `str` object with cache.
py_GlobalRef py_name2ref(
int arg0,
) {
return _py_name2ref(
arg0,
);
}
late final _py_name2refPtr =
_lookup<ffi.NativeFunction<py_GlobalRef Function(py_Name)>>(
'py_name2ref');
late final _py_name2ref =
_py_name2refPtr.asFunction<py_GlobalRef Function(int)>();
/// Convert a `c11_sv` to a name. /// Convert a `c11_sv` to a name.
int py_namev( int py_namev(
c11_sv arg0, c11_sv arg0,
@ -1132,7 +1163,7 @@ class PocketpyBindings {
late final _py_tpcall = late final _py_tpcall =
_py_tpcallPtr.asFunction<bool Function(int, int, py_Ref)>(); _py_tpcallPtr.asFunction<bool Function(int, int, py_Ref)>();
/// Check if the object is an instance of the given type. /// Check if the object is an instance of the given type exactly.
/// Raise `TypeError` if the check fails. /// Raise `TypeError` if the check fails.
bool py_checktype( bool py_checktype(
py_Ref self, py_Ref self,
@ -1150,6 +1181,24 @@ class PocketpyBindings {
late final _py_checktype = late final _py_checktype =
_py_checktypePtr.asFunction<bool Function(py_Ref, int)>(); _py_checktypePtr.asFunction<bool Function(py_Ref, int)>();
/// Check if the object is an instance of the given type or its subclass.
/// Raise `TypeError` if the check fails.
bool py_checkinstance(
py_Ref self,
int type,
) {
return _py_checkinstance(
self,
type,
);
}
late final _py_checkinstancePtr =
_lookup<ffi.NativeFunction<ffi.Bool Function(py_Ref, py_Type)>>(
'py_checkinstance');
late final _py_checkinstance =
_py_checkinstancePtr.asFunction<bool Function(py_Ref, int)>();
/// Get the i-th register. /// Get the i-th register.
/// All registers are located in a contiguous memory. /// All registers are located in a contiguous memory.
py_GlobalRef py_getreg( py_GlobalRef py_getreg(
@ -2851,6 +2900,9 @@ final class c11_vec2i extends ffi.Union {
@ffi.Array.multi([2]) @ffi.Array.multi([2])
external ffi.Array<ffi.Int> data; external ffi.Array<ffi.Int> data;
@ffi.Int64()
external int _i64;
} }
final class UnnamedStruct1 extends ffi.Struct { final class UnnamedStruct1 extends ffi.Struct {
@ -2972,6 +3024,9 @@ final class py_Callbacks extends ffi.Struct {
external ffi external ffi
.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Char>)>> .Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Char>)>>
print; print;
/// Used by `input` to get a character.
external ffi.Pointer<ffi.NativeFunction<ffi.Int Function()>> getchar;
} }
/// Python compiler modes. /// Python compiler modes.
@ -2999,6 +3054,9 @@ typedef py_i64 = ffi.Int64;
/// A 64-bit floating-point type. Corresponds to `float` in python. /// A 64-bit floating-point type. Corresponds to `float` in python.
typedef py_f64 = ffi.Double; typedef py_f64 = ffi.Double;
/// A reference which has the same lifespan as the python object.
typedef py_ObjectRef = ffi.Pointer<py_TValue>;
/// Native function signature. /// Native function signature.
/// @param argc number of arguments. /// @param argc number of arguments.
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument. /// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
@ -3023,9 +3081,6 @@ typedef py_Dtor
/// An item reference to a container object. It invalidates when the container is modified. /// An item reference to a container object. It invalidates when the container is modified.
typedef py_ItemRef = ffi.Pointer<py_TValue>; typedef py_ItemRef = ffi.Pointer<py_TValue>;
/// A reference which has the same lifespan as the python object.
typedef py_ObjectRef = ffi.Pointer<py_TValue>;
/// Python favored string formatting. /// Python favored string formatting.
/// %d: int /// %d: int
/// %i: py_i64 (int64_t) /// %i: py_i64 (int64_t)
@ -3202,17 +3257,20 @@ abstract class py_PredefinedTypes {
static const int tp_mat3x3 = 57; static const int tp_mat3x3 = 57;
/// array2d /// array2d
static const int tp_array2d = 58; static const int tp_array2d_like = 58;
static const int tp_array2d_iterator = 59; static const int tp_array2d_like_iterator = 59;
static const int tp_array2d = 60;
static const int tp_array2d_view = 61;
static const int tp_chunked_array2d = 62;
} }
const String PK_VERSION = '2.0.5'; const String PK_VERSION = '2.0.6';
const int PK_VERSION_MAJOR = 2; const int PK_VERSION_MAJOR = 2;
const int PK_VERSION_MINOR = 0; const int PK_VERSION_MINOR = 0;
const int PK_VERSION_PATCH = 5; const int PK_VERSION_PATCH = 6;
const int PK_LOW_MEMORY_MODE = 0; const int PK_LOW_MEMORY_MODE = 0;

View File

@ -0,0 +1,20 @@
import os
import sys
def check_pragma_once_in_dir(path):
for root, dirs, files in os.walk(path):
if 'include/pocketpy/xmacros' in root or 'include/pybind11' in root:
continue
for file in files:
if file.endswith(".c") or file.endswith(".h"):
with open(os.path.join(root, file), "r", encoding='utf-8') as f:
print(f"==> {os.path.join(root, file)}")
text = f.read()
assert text.count("#pragma once") == 1, "#pragma once should appear exactly once"
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python scripts/check_pragma_once.py <path>")
sys.exit(1)
check_pragma_once_in_dir(sys.argv[1])

View File

@ -2858,7 +2858,6 @@ const static PrattRule rules[TK__COUNT__] = {
}; };
// clang-format on // clang-format on
#undef static_assert_expr_size
#undef vtcall #undef vtcall
#undef vtemit_ #undef vtemit_
#undef vtemit_del #undef vtemit_del