mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-09 05:00:17 +00:00
Compare commits
4 Commits
8a3bdd7e0a
...
8c8c5f13cf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c8c5f13cf | ||
|
|
4434bfcf23 | ||
|
|
698a7b7f4f | ||
|
|
5d428a8818 |
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
@ -70,6 +70,7 @@ jobs:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
- name: Compile and Test
|
||||
run: |
|
||||
python scripts/check_pragma_once.py include
|
||||
mkdir -p output/x86_64
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
|
||||
@ -5,15 +5,11 @@ project(pocketpy)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# use IPO
|
||||
option(PK_BUILD_WITH_IPO "" TRUE)
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT result)
|
||||
|
||||
if(result AND PK_BUILD_WITH_IPO)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
# use UNITY_BUILD if CMake version >= 3.16
|
||||
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16")
|
||||
option(PK_BUILD_WITH_UNITY "" TRUE)
|
||||
else()
|
||||
message(WARNING ">> IPO disabled. You will not get the best performance.")
|
||||
option(PK_BUILD_WITH_UNITY "" FALSE)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
@ -94,13 +90,20 @@ else()
|
||||
target_link_libraries(main ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(${PROJECT_NAME} m)
|
||||
if(PK_ENABLE_OS)
|
||||
target_link_libraries(${PROJECT_NAME} dl)
|
||||
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)
|
||||
target_link_libraries(${PROJECT_NAME} lz4)
|
||||
endif()
|
||||
|
||||
@ -8,10 +8,7 @@ cd build
|
||||
|
||||
FLAGS="-DCMAKE_TOOLCHAIN_FILE=3rd/ios.toolchain.cmake \
|
||||
-DDEPLOYMENT_TARGET=13.0 \
|
||||
-DPK_BUILD_STATIC_LIB=ON \
|
||||
-DPK_BUILD_WITH_IPO=OFF \
|
||||
-DPK_BUILD_MODULE_LZ4=ON \
|
||||
-DPK_BUILD_MODULE_LIBHV=ON"
|
||||
-DPK_BUILD_STATIC_LIB=ON"
|
||||
|
||||
cmake -B os64 -G Xcode $FLAGS -DPLATFORM=OS64 ..
|
||||
cmake --build os64 --config Release
|
||||
|
||||
221
docs/coding-style-guide.md
Normal file
221
docs/coding-style-guide.md
Normal 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/)
|
||||
@ -49,7 +49,7 @@ Type "exit()" to exit.
|
||||
|
||||
### Coding style guide
|
||||
|
||||
See [Coding Style Guide](../coding_style_guide.md).
|
||||
See [Coding Style Guide](../coding-style-guide.md).
|
||||
|
||||
### Contact us
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ Type "exit()" to exit.
|
||||
|
||||
### Coding style guide
|
||||
|
||||
See [Coding Style Guide](../coding_style_guide.md).
|
||||
See [Coding Style Guide](../coding-style-guide.md).
|
||||
|
||||
### Contact us
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/objectpool.h"
|
||||
|
||||
|
||||
@ -269,7 +269,6 @@ class PocketpyBindings {
|
||||
_py_newglobalsPtr.asFunction<void Function(py_OutRef)>();
|
||||
|
||||
/// Python equivalent to `locals()`.
|
||||
/// @return a temporary object, which expires on the associated function return.
|
||||
void py_newlocals(
|
||||
py_OutRef arg0,
|
||||
) {
|
||||
@ -421,6 +420,23 @@ class PocketpyBindings {
|
||||
late final _py_newstrv =
|
||||
_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.
|
||||
ffi.Pointer<ffi.UnsignedChar> py_newbytes(
|
||||
py_OutRef arg0,
|
||||
@ -499,7 +515,7 @@ class PocketpyBindings {
|
||||
|
||||
/// Create a `tuple` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
void py_newtuple(
|
||||
py_ObjectRef py_newtuple(
|
||||
py_OutRef arg0,
|
||||
int n,
|
||||
) {
|
||||
@ -510,10 +526,10 @@ class PocketpyBindings {
|
||||
}
|
||||
|
||||
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');
|
||||
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`.
|
||||
void py_newlist(
|
||||
@ -667,6 +683,21 @@ class PocketpyBindings {
|
||||
late final _py_name2str =
|
||||
_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.
|
||||
int py_namev(
|
||||
c11_sv arg0,
|
||||
@ -1132,7 +1163,7 @@ class PocketpyBindings {
|
||||
late final _py_tpcall =
|
||||
_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.
|
||||
bool py_checktype(
|
||||
py_Ref self,
|
||||
@ -1150,6 +1181,24 @@ class PocketpyBindings {
|
||||
late final _py_checktype =
|
||||
_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.
|
||||
/// All registers are located in a contiguous memory.
|
||||
py_GlobalRef py_getreg(
|
||||
@ -2851,6 +2900,9 @@ final class c11_vec2i extends ffi.Union {
|
||||
|
||||
@ffi.Array.multi([2])
|
||||
external ffi.Array<ffi.Int> data;
|
||||
|
||||
@ffi.Int64()
|
||||
external int _i64;
|
||||
}
|
||||
|
||||
final class UnnamedStruct1 extends ffi.Struct {
|
||||
@ -2972,6 +3024,9 @@ final class py_Callbacks extends ffi.Struct {
|
||||
external ffi
|
||||
.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Char>)>>
|
||||
print;
|
||||
|
||||
/// Used by `input` to get a character.
|
||||
external ffi.Pointer<ffi.NativeFunction<ffi.Int Function()>> getchar;
|
||||
}
|
||||
|
||||
/// Python compiler modes.
|
||||
@ -2999,6 +3054,9 @@ typedef py_i64 = ffi.Int64;
|
||||
/// A 64-bit floating-point type. Corresponds to `float` in python.
|
||||
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.
|
||||
/// @param argc number of arguments.
|
||||
/// @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.
|
||||
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.
|
||||
/// %d: int
|
||||
/// %i: py_i64 (int64_t)
|
||||
@ -3202,17 +3257,20 @@ abstract class py_PredefinedTypes {
|
||||
static const int tp_mat3x3 = 57;
|
||||
|
||||
/// array2d
|
||||
static const int tp_array2d = 58;
|
||||
static const int tp_array2d_iterator = 59;
|
||||
static const int tp_array2d_like = 58;
|
||||
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_MINOR = 0;
|
||||
|
||||
const int PK_VERSION_PATCH = 5;
|
||||
const int PK_VERSION_PATCH = 6;
|
||||
|
||||
const int PK_LOW_MEMORY_MODE = 0;
|
||||
|
||||
|
||||
20
scripts/check_pragma_once.py
Normal file
20
scripts/check_pragma_once.py
Normal 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])
|
||||
@ -2858,7 +2858,6 @@ const static PrattRule rules[TK__COUNT__] = {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#undef static_assert_expr_size
|
||||
#undef vtcall
|
||||
#undef vtemit_
|
||||
#undef vtemit_del
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user