mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
some fix
This commit is contained in:
parent
291ee682b7
commit
ac8f4a1c2d
@ -12,12 +12,9 @@ check_ipo_supported(RESULT result)
|
||||
if(result AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
else()
|
||||
message(WARNING ">> IPO disabled. You will get very poor performance!!")
|
||||
message(WARNING ">> IPO disabled. You will get very poor performance!!")
|
||||
message(WARNING ">> IPO disabled. You will get very poor performance!!")
|
||||
message(WARNING ">> IPO disabled. You will not get the best performance.")
|
||||
endif()
|
||||
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8 /jumptablerdata /GS-")
|
||||
add_compile_options(/wd4267 /wd4244)
|
||||
@ -47,11 +44,6 @@ if(PK_ENABLE_OS)
|
||||
add_definitions(-DPK_ENABLE_OS=1)
|
||||
endif()
|
||||
|
||||
option(PK_ENABLE_PROFILER "" OFF)
|
||||
if(PK_ENABLE_PROFILER)
|
||||
add_definitions(-DPK_ENABLE_PROFILER=1)
|
||||
endif()
|
||||
|
||||
# PK_IS_MAIN determines whether the project is being used from root
|
||||
# or if it is added as a dependency (through add_subdirectory for example).
|
||||
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
@ -79,6 +79,7 @@ To compile it with your project, these flags must be set:
|
||||
|
||||
+ `--std=c11` flag must be set
|
||||
+ For MSVC, `/utf-8` flag must be set
|
||||
+ `NDEBUG` macro should be defined for release build, or you will get poor performance
|
||||
|
||||
For amalgamated build, run `python amalgamate.py` to generate `pocketpy.c` and `pocketpy.h` in `amalgamated/` directory.
|
||||
|
||||
@ -146,9 +147,6 @@ __ERROR:
|
||||
|
||||
## Features
|
||||
|
||||
Check this [Cheatsheet](https://reference.pocketpy.dev/python.html)
|
||||
for a quick overview of the supported features.
|
||||
|
||||
| Name | Example | Supported |
|
||||
| --------------- | ------------------------------- | --------- |
|
||||
| If Else | `if..else..elif` | ✅ |
|
||||
@ -237,7 +235,6 @@ Your sponsorship will help us develop pkpy continuously.
|
||||
[](https://star-history.com/#blueloveth/pocketpy&Date)
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](http://opensource.org/licenses/MIT)
|
||||
|
@ -8,7 +8,7 @@ from typing import List, Dict
|
||||
assert os.system("python prebuild.py") == 0
|
||||
|
||||
ROOT = 'include/pocketpy'
|
||||
PUBLIC_HEADERS = ['config.h', 'export.h', 'pocketpy.h']
|
||||
PUBLIC_HEADERS = ['config.h', 'export.h', 'linalg.h', 'pocketpy.h']
|
||||
|
||||
COPYRIGHT = '''/*
|
||||
* Copyright (c) 2024 blueloveTH
|
||||
|
291
docs/bindings-cpp.md
Normal file
291
docs/bindings-cpp.md
Normal file
@ -0,0 +1,291 @@
|
||||
---
|
||||
icon: cpu
|
||||
title: Write C++ Bindings
|
||||
order: 17
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
pkpy provides a [pybind11](https://pybind11.readthedocs.io/en/stable/) compatible layer which allows users to do convenient bindings.
|
||||
|
||||
To begin with, use `py::scoped_interpreter guard{}` to start the interpreter before using any Python objects.
|
||||
Or explicitly call `py::interpreter::initialize()` and `py::interpreter::finalize()`.
|
||||
|
||||
### module
|
||||
|
||||
```cpp
|
||||
#include <pybind11/pybind11.h>
|
||||
namespace py = pybind11;
|
||||
|
||||
PYBIND11_EMBEDDED_MODULE(example, m) {
|
||||
m.def("add", [](int a, int b) {
|
||||
return a + b;
|
||||
});
|
||||
|
||||
auto math = m.def_submodule("math");
|
||||
}
|
||||
```
|
||||
|
||||
### function
|
||||
|
||||
```cpp
|
||||
int add(int a, int b) { return a + b; }
|
||||
|
||||
int add(int a, int b, int c) { return a + b + c; }
|
||||
|
||||
void register_function(py::module_& m)
|
||||
{
|
||||
m.def("add", py::overload_cast<int, int>(&add));
|
||||
|
||||
// support function overload
|
||||
m.def("add", py::overload_cast<int, int, int>(&add));
|
||||
|
||||
// bind with default arguments
|
||||
m.def("sub", [](int a, int b) {
|
||||
return a - b;
|
||||
}, py::arg("a") = 1, py::arg("b") = 2);
|
||||
|
||||
// bind *args
|
||||
m.def("add", [](py::args args) {
|
||||
int sum = 0;
|
||||
for (auto& arg : args) {
|
||||
sum += arg.cast<int>();
|
||||
}
|
||||
return sum;
|
||||
});
|
||||
|
||||
// bind **kwargs
|
||||
m.def("add", [](py::kwargs kwargs) {
|
||||
int sum = 0;
|
||||
for (auto item : kwargs) {
|
||||
sum += item.second.cast<int>();
|
||||
}
|
||||
return sum;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### class
|
||||
|
||||
```cpp
|
||||
struct Point
|
||||
{
|
||||
const int x;
|
||||
int y;
|
||||
|
||||
public:
|
||||
Point() : x(0), y(0) {}
|
||||
|
||||
Point(int x, int y) : x(x), y(y) {}
|
||||
|
||||
Point(const Point& p) : x(p.x), y(p.y) {}
|
||||
|
||||
std::string stringfy() const {
|
||||
return "(" + std::to_string(x) + ", " + std::to_string(y) + ")";
|
||||
}
|
||||
};
|
||||
|
||||
struct Point3D : Point
|
||||
{
|
||||
private:
|
||||
int z;
|
||||
|
||||
public:
|
||||
Point3D(int x, int y, int z) : Point(x, y), z(z) {}
|
||||
|
||||
int get_z() const { return z; }
|
||||
|
||||
void set_z(int z) { this->z = z; }
|
||||
};
|
||||
|
||||
void bind_class(py::module_& m)
|
||||
{
|
||||
py::class_<Point>(m, "Point")
|
||||
.def(py::init<>())
|
||||
.def(py::init<int, int>())
|
||||
.def(py::init<const Point&>())
|
||||
.def_readonly("x", &Point::x)
|
||||
.def_readwrite("y", &Point::y)
|
||||
.def("__str__", &Point::stringfy);
|
||||
|
||||
// only support single inheritance
|
||||
py::class_<Point3D, Point>(m, "Point3D", py::dynamic_attr())
|
||||
.def(py::init<int, int, int>())
|
||||
.def_property("z", &Point3D::get_z, &Point3D::set_z);
|
||||
|
||||
// dynamic_attr will enable the dict of bound class
|
||||
}
|
||||
```
|
||||
|
||||
### operators
|
||||
|
||||
```cpp
|
||||
#include <pybind11/operators.h>
|
||||
namespace py = pybind11;
|
||||
|
||||
struct Int {
|
||||
int value;
|
||||
|
||||
Int(int value) : value(value) {}
|
||||
|
||||
Int operator+(const Int& other) const {
|
||||
return Int(value + other.value);
|
||||
}
|
||||
|
||||
Int operator-(const Int& other) const {
|
||||
return Int(value - other.value);
|
||||
}
|
||||
|
||||
bool operator==(const Int& other) const {
|
||||
return value == other.value;
|
||||
}
|
||||
|
||||
bool operator!=(const Int& other) const {
|
||||
return value != other.value;
|
||||
}
|
||||
};
|
||||
|
||||
void bind_operators(py::module_& m)
|
||||
{
|
||||
py::class_<Int>(m, "Int")
|
||||
.def(py::init<int>())
|
||||
.def(py::self + py::self)
|
||||
.def(py::self - py::self)
|
||||
.def(py::self == py::self)
|
||||
.def(py::self != py::self);
|
||||
// other operators are similar
|
||||
}
|
||||
```
|
||||
|
||||
### py::object
|
||||
|
||||
`py::object` is just simple wrapper around `PyVar`. It supports some convenient methods to interact with Python objects.
|
||||
|
||||
|
||||
here are some common methods:
|
||||
|
||||
```cpp
|
||||
obj.attr("x"); // access attribute
|
||||
obj[1]; // access item
|
||||
|
||||
obj.is_none(); // same as obj is None in Python
|
||||
obj.is(obj2); // same as obj is obj2 in Python
|
||||
|
||||
// operators
|
||||
obj + obj2; // same as obj + obj2 in Python
|
||||
// ...
|
||||
obj == obj2; // same as obj == obj2 in Python
|
||||
// ...
|
||||
|
||||
obj(...); // same as obj.__call__(...)
|
||||
|
||||
py::cast(obj); // cast to Python object
|
||||
obj.cast<T>; // cast to C++ type
|
||||
|
||||
py::type::of(obj); // get type of obj
|
||||
py::type::of<T>(); // get type of T, if T is registered
|
||||
```
|
||||
|
||||
you can also create some builtin objects with their according wrappers:
|
||||
|
||||
```cpp
|
||||
py::bool_ b = {true};
|
||||
py::int_ i = {1};
|
||||
py::float_ f = {1.0};
|
||||
py::str s = {"hello"};
|
||||
py::list l = {1, 2, 3};
|
||||
py::tuple t = {1, 2, 3};
|
||||
// ...
|
||||
```
|
||||
|
||||
|
||||
|
||||
## More Examples
|
||||
|
||||
More examples please see the test [folder](https://github.com/pocketpy/gsoc-2024-dev/tree/main/pybind11/tests) in the GSoC repository. All tested features are supported.
|
||||
|
||||
## Limits and Comparison
|
||||
|
||||
This is a feature list of pybind11 for pocketpy. It lists all completed and pending features. It also lists the features that cannot be implemented in the current version of pocketpy.
|
||||
|
||||
### [Function](https://pybind11.readthedocs.io/en/stable/advanced/functions.html)
|
||||
|
||||
- [x] Function overloading
|
||||
- [x] Return value policy
|
||||
- [x] is_prepend
|
||||
- [x] `*args` and `**kwargs`
|
||||
- [ ] Keep-alive
|
||||
- [ ] Call Guard
|
||||
- [x] Default arguments
|
||||
- [ ] Keyword-Only arguments
|
||||
- [ ] Positional-Only arguments
|
||||
- [ ] Allow/Prohibiting None arguments
|
||||
|
||||
### [Class](https://pybind11.readthedocs.io/en/stable/classes.html)
|
||||
|
||||
- [x] Creating bindings for a custom type
|
||||
- [x] Binding lambda functions
|
||||
- [x] Dynamic attributes
|
||||
- [x] Inheritance and automatic downcasting
|
||||
- [x] Enumerations and internal types
|
||||
- [ ] Instance and static fields
|
||||
|
||||
> Binding static fields may never be implemented in pocketpy because it requires a metaclass, which is a heavy and infrequently used feature.
|
||||
|
||||
### [Exceptions](https://pybind11.readthedocs.io/en/stable/advanced/exceptions.html)
|
||||
|
||||
Need further discussion.
|
||||
|
||||
### [Smart pointers](https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html)
|
||||
|
||||
- [ ] std::shared_ptr
|
||||
- [ ] std::unique_ptr
|
||||
- [ ] Custom smart pointers
|
||||
|
||||
### [Type conversions](https://pybind11.readthedocs.io/en/stable/advanced/cast/index.html)
|
||||
|
||||
- [x] Python built-in types
|
||||
- [x] STL Containers
|
||||
- [ ] Functional
|
||||
- [ ] Chrono
|
||||
|
||||
### [Python C++ interface](https://pybind11.readthedocs.io/en/stable/advanced/pycpp/object.html)
|
||||
|
||||
Need further discussion.
|
||||
|
||||
- [x] `object`
|
||||
- [x] `none`
|
||||
- [x] `type`
|
||||
- [x] `bool_`
|
||||
- [x] `int_`
|
||||
- [x] `float_`
|
||||
- [x] `str`
|
||||
- [ ] `bytes`
|
||||
- [ ] `bytearray`
|
||||
- [x] `tuple`
|
||||
- [x] `list`
|
||||
- [ ] `set`
|
||||
- [x] `dict`
|
||||
- [ ] `slice`
|
||||
- [x] `iterable`
|
||||
- [x] `iterator`
|
||||
- [ ] `function`
|
||||
- [ ] `buffer`
|
||||
- [ ] `memoryview`
|
||||
- [x] `capsule`
|
||||
|
||||
### [Miscellaneous](https://pybind11.readthedocs.io/en/stable/advanced/misc.html)
|
||||
|
||||
- [ ] Global Interpreter Lock (GIL)
|
||||
- [ ] Binding sequence data types, iterators, the slicing protocol, etc.
|
||||
- [x] Convenient operators binding
|
||||
|
||||
### Differences between CPython and pocketpy
|
||||
|
||||
- only `add`, `sub` and `mul` have corresponding right versions in pocketpy. So if you bind `int() >> py::self`, it will has no effect in pocketpy.
|
||||
|
||||
- `__new__` and `__del__` are not supported in pocketpy.
|
||||
|
||||
- in-place operators, such as `+=`, `-=`, `*=`, etc., are not supported in pocketpy.
|
||||
|
||||
- thre return value of `globals` is immutable in pocketpy.
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
icon: cpu
|
||||
title: Write Bindings
|
||||
title: Write C Bindings
|
||||
order: 18
|
||||
---
|
||||
|
||||
@ -16,3 +16,11 @@ typedef bool (*py_CFunction)(int argc, py_Ref argv);
|
||||
|
||||
If successful, the function should return `true` and set the return value in `py_retval()`. In case there is no return value, you should use `py_newnone(py_retval())`.
|
||||
If an error occurs, the function should raise an exception and return `false`.
|
||||
|
||||
See also:
|
||||
+ [`py_bind`](/c-api/functions/#py_bind)
|
||||
+ [`py_bindmethod`](/c-api/functions/#py_bindmethod)
|
||||
+ [`py_bindfunc`](/c-api/functions/#py_bindfunc)
|
||||
+ [`py_bindproperty`](/c-api/functions/#py_bindproperty)
|
||||
+ [`py_newmodule`](/c-api/functions/#py_newmodule)
|
||||
+ [`py_newtype`](/c-api/functions/#py_newtype)
|
@ -4,9 +4,6 @@ title: Basic Features
|
||||
order: 100
|
||||
---
|
||||
|
||||
Check this [Cheatsheet](https://reference.pocketpy.dev/python.html)
|
||||
for a quick overview of the supported features.
|
||||
|
||||
The following table shows the basic features of pkpy with respect to [cpython](https://github.com/python/cpython).
|
||||
The features marked with `YES` are supported, and the features marked with `NO` are not supported.
|
||||
|
||||
|
@ -4,7 +4,7 @@ title: Debugging
|
||||
---
|
||||
|
||||
!!!
|
||||
This feature is available in `v1.4.5` or higher. Set `PK_ENABLE_PROFILER` to `1` to enable this feature.
|
||||
This feature is not available in `v2.0` yet.
|
||||
!!!
|
||||
|
||||
You can invoke `breakpoint()` in your python code to start a PDB-like session.
|
||||
|
@ -23,20 +23,18 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
|
||||
1. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
|
||||
2. `__slots__` in class definition.
|
||||
3. `else` clause in try..except.
|
||||
4. Inplace methods like `__iadd__` and `__imul__`.
|
||||
4. Inplace methods like `__iadd__` and `__imul__`.
|
||||
5. `__del__` in class definition.
|
||||
6. Multiple inheritance.
|
||||
|
||||
## Different behaviors
|
||||
|
||||
1. positional and keyword arguments are strictly evaluated.
|
||||
2. `++i` and `--j` is an increment/decrement statement, not an expression.
|
||||
3. `int` does not derive from `bool`.
|
||||
4. `int` is 64-bit. You can use `long` type explicitly for arbitrary sized integers.
|
||||
5. `__ne__` is not required. Define `__eq__` is enough.
|
||||
6. Raw string cannot have boundary quotes in it, even escaped. See [#55](https://github.com/pocketpy/pocketpy/issues/55).
|
||||
7. In a starred unpacked assignment, e.g. `a, b, *c = x`, the starred variable can only be presented in the last position. `a, *b, c = x` is not supported.
|
||||
8. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
|
||||
9. `%`, `&`, `//`, `^` and `|` for `int` behave the same as C, not python.
|
||||
10. `str.split` and `str.splitlines` will remove all empty entries.
|
||||
11. `__getattr__`, `__setattr__` and `__delattr__` can only be set in cpp.
|
||||
2. `int` does not derive from `bool`.
|
||||
3. `int` is 64-bit.
|
||||
4. Raw string cannot have boundary quotes in it, even escaped. See [#55](https://github.com/pocketpy/pocketpy/issues/55).
|
||||
5. In a starred unpacked assignment, e.g. `a, b, *c = x`, the starred variable can only be presented in the last position. `a, *b, c = x` is not supported.
|
||||
6. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
|
||||
7. `%`, `&`, `//`, `^` and `|` for `int` behave the same as C, not python.
|
||||
8. `str.split` and `str.splitlines` will remove all empty entries.
|
||||
|
||||
|
@ -1,145 +0,0 @@
|
||||
---
|
||||
icon: dot
|
||||
title: Precompiling
|
||||
---
|
||||
|
||||
pkpy allows you to precompile python code into two special forms, which can be executed later.
|
||||
|
||||
### In-memory precompilation
|
||||
|
||||
You can use `vm->compile` to compile your source code into a `CodeObject_` object.
|
||||
This object can be executed later by `vm->_exec`.
|
||||
|
||||
```cpp
|
||||
CodeObject_ code = vm->compile("print('Hello, world!')", "<string>", EXEC_MODE);
|
||||
vm->_exec(code); // Hello, world!
|
||||
```
|
||||
|
||||
This `CodeObject_` object is a very non-generic form of the compiled code,
|
||||
which is an in-memory form. Very efficient, but not portable.
|
||||
You are not able to save it to a file or load it from a file.
|
||||
|
||||
|
||||
### String precompilation
|
||||
|
||||
In order to save the compiled code to a file, you need to use `vm->precompile`.
|
||||
It does some basic preprocessing and outputs the result as a human-readable string.
|
||||
|
||||
```cpp
|
||||
// precompile the source code into a string
|
||||
Str source = vm->precompile("print('Hello, world!')", "<string>", EXEC_MODE);
|
||||
|
||||
CodeObject code = vm->compile(source, "<string>", EXEC_MODE);
|
||||
vm->_exec(code); // Hello, world!
|
||||
```
|
||||
|
||||
You can also use python's `compile` function to achieve the same effect.
|
||||
|
||||
```python
|
||||
code = compile("print('Hello, world!')", "<string>", "exec")
|
||||
exec(code) # Hello, world!
|
||||
```
|
||||
|
||||
Let's take a look at the precompiled string.
|
||||
```python
|
||||
print(code)
|
||||
```
|
||||
|
||||
```txt
|
||||
pkpy:1.4.5
|
||||
0
|
||||
=1
|
||||
print
|
||||
=6
|
||||
5,1,0,
|
||||
6,0,,,
|
||||
42,,1,
|
||||
8,,,S48656c6c6f2c20776f726c6421
|
||||
43,,0,
|
||||
3,,,
|
||||
|
||||
```
|
||||
|
||||
Comparing with **In-memory precompilation**,
|
||||
**String precompilation** drops most of the information of the original source code.
|
||||
It has an encryption effect, which can protect your source code from being stolen.
|
||||
This also means there is no source line information when an error occurs.
|
||||
|
||||
```python
|
||||
src = """
|
||||
def f(a, b):
|
||||
return g(a, b)
|
||||
|
||||
def g(a, b):
|
||||
c = f(a, b)
|
||||
d = g(a, b)
|
||||
return c + d
|
||||
"""
|
||||
|
||||
code = compile(src, "<exec>", "exec")
|
||||
exec(code)
|
||||
f(1, 2)
|
||||
```
|
||||
|
||||
You will get this (without source line information):
|
||||
```txt
|
||||
Traceback (most recent call last):
|
||||
File "<exec>", line 3, in f
|
||||
File "<exec>", line 6, in g
|
||||
File "<exec>", line 3, in f
|
||||
File "<exec>", line 6, in g
|
||||
File "<exec>", line 3, in f
|
||||
File "<exec>", line 6, in g
|
||||
File "<exec>", line 3, in f
|
||||
StackOverflowError
|
||||
```
|
||||
|
||||
instead of this (with source line information):
|
||||
|
||||
```txt
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 2, in f
|
||||
return g(a, b)
|
||||
File "<stdin>", line 2, in g
|
||||
c = f(a, b)
|
||||
File "<stdin>", line 2, in f
|
||||
return g(a, b)
|
||||
File "<stdin>", line 2, in g
|
||||
c = f(a, b)
|
||||
File "<stdin>", line 2, in f
|
||||
return g(a, b)
|
||||
File "<stdin>", line 2, in g
|
||||
c = f(a, b)
|
||||
File "<stdin>", line 2, in f
|
||||
return g(a, b)
|
||||
StackOverflowError
|
||||
```
|
||||
|
||||
!!!
|
||||
String compilation has no guarantee of compatibility between different versions of pkpy.
|
||||
!!!
|
||||
|
||||
You can use this snippet to convert every python file in a directory into precompiled strings.
|
||||
|
||||
```python
|
||||
# precompile.py
|
||||
import sys, os
|
||||
|
||||
def precompile(filepath: str):
|
||||
"""Precompile a python file inplace"""
|
||||
print(filepath)
|
||||
with open(filepath, 'r') as f:
|
||||
source = f.read()
|
||||
source = compile(source, filepath, 'exec')
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(source)
|
||||
|
||||
def traverse(root: str):
|
||||
"""Traverse a directory and precompile every python file"""
|
||||
for entry in os.listdir(root):
|
||||
entrypath = os.path.join(root, entry)
|
||||
if os.path.isdir(entrypath):
|
||||
traverse(entrypath)
|
||||
elif entrypath.endswith(".py"):
|
||||
precompile(entrypath)
|
||||
```
|
@ -9,4 +9,4 @@ These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined i
|
||||
2. Call an unbound method with the wrong type of `self`. For example, `int.__add__('1', 2)`.
|
||||
3. Type `T`'s `__new__` returns an object that is not an instance of `T`.
|
||||
4. Call `__new__` with a type that is not a subclass of `type`.
|
||||
5. `__eq__`, `__lt__` or `__contains__`, etc.. returns a value that is not a boolean.
|
||||
|
||||
|
@ -31,6 +31,7 @@ To compile it with your project, these flags must be set:
|
||||
|
||||
+ `--std=c11` flag must be set
|
||||
+ For MSVC, `/utf-8` flag must be set
|
||||
+ `NDEBUG` macro should be defined for release build, or you will get poor performance
|
||||
|
||||
### Get prebuilt binaries
|
||||
|
||||
@ -53,12 +54,6 @@ You can download an artifact there which contains the following files.
|
||||
│ └── x86_64
|
||||
│ ├── libpocketpy.so
|
||||
│ └── main
|
||||
├── macos
|
||||
│ └── pocketpy.bundle
|
||||
│ └── Contents
|
||||
│ ├── Info.plist
|
||||
│ └── MacOS
|
||||
│ └── pocketpy
|
||||
└── windows
|
||||
└── x86_64
|
||||
├── main.exe
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* string */
|
||||
typedef struct c11_string{
|
||||
// int size | char[] | '\0'
|
||||
|
@ -22,15 +22,13 @@ typedef struct c11_vec3 {
|
||||
float z;
|
||||
} c11_vec3;
|
||||
|
||||
typedef struct c11_mat3x3 {
|
||||
union {
|
||||
struct {
|
||||
float _11, _12, _13;
|
||||
float _21, _22, _23;
|
||||
float _31, _32, _33;
|
||||
};
|
||||
|
||||
float m[3][3];
|
||||
float data[9];
|
||||
typedef union c11_mat3x3 {
|
||||
struct {
|
||||
float _11, _12, _13;
|
||||
float _21, _22, _23;
|
||||
float _31, _32, _33;
|
||||
};
|
||||
|
||||
float m[3][3];
|
||||
float data[9];
|
||||
} c11_mat3x3;
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "pocketpy/config.h"
|
||||
|
@ -1,2 +0,0 @@
|
||||
def loads(data: str | bytes) -> object: ...
|
||||
def dumps(obj: object) -> str: ...
|
@ -14,6 +14,8 @@ class vec2:
|
||||
|
||||
def __init__(self, x: float, y: float) -> None: ...
|
||||
def __repr__(self) -> str: ...
|
||||
def __eq__(self, other: vec2) -> bool: ...
|
||||
def __ne__(self, other: vec2) -> bool: ...
|
||||
|
||||
def __add__(self, other: vec2) -> vec2: ...
|
||||
def __sub__(self, other: vec2) -> vec2: ...
|
||||
@ -51,6 +53,8 @@ class vec2:
|
||||
class mat3x3:
|
||||
def __init__(self, _11, _12, _13, _21, _22, _23, _31, _32, _33) -> None: ...
|
||||
def __repr__(self) -> str: ...
|
||||
def __eq__(self, other: mat3x3) -> bool: ...
|
||||
def __ne__(self, other: mat3x3) -> bool: ...
|
||||
|
||||
def __getitem__(self, index: tuple[int, int]) -> float: ...
|
||||
def __setitem__(self, index: tuple[int, int], value: float) -> None: ...
|
||||
@ -101,6 +105,8 @@ class vec2i:
|
||||
|
||||
def __init__(self, x: int, y: int) -> None: ...
|
||||
def __repr__(self) -> str: ...
|
||||
def __eq__(self, other: vec2i) -> bool: ...
|
||||
def __ne__(self, other: vec2i) -> bool: ...
|
||||
|
||||
|
||||
class vec3i:
|
||||
@ -117,6 +123,8 @@ class vec3i:
|
||||
|
||||
def __init__(self, x: int, y: int, z: int) -> None: ...
|
||||
def __repr__(self) -> str: ...
|
||||
def __eq__(self, other: vec3i) -> bool: ...
|
||||
def __ne__(self, other: vec3i) -> bool: ...
|
||||
|
||||
|
||||
class vec3:
|
||||
@ -133,3 +141,5 @@ class vec3:
|
||||
|
||||
def __init__(self, x: float, y: float, z: float) -> None: ...
|
||||
def __repr__(self) -> str: ...
|
||||
def __eq__(self, other: vec3) -> bool: ...
|
||||
def __ne__(self, other: vec3) -> bool: ...
|
||||
|
@ -283,12 +283,13 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
if(magic->type == tp_nativefunc) {
|
||||
if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
|
||||
POP();
|
||||
py_assign(TOP(), py_retval());
|
||||
} else {
|
||||
INSERT_THIRD(); // [?, a, b]
|
||||
*THIRD() = *magic; // [__getitem__, a, b]
|
||||
if(!py_vectorcall(1, 0)) goto __ERROR;
|
||||
PUSH(py_retval());
|
||||
}
|
||||
*TOP() = self->last_retval;
|
||||
DISPATCH();
|
||||
}
|
||||
TypeError("'%t' object is not subscriptable", SECOND()->type);
|
||||
@ -349,7 +350,6 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
} else {
|
||||
*FOURTH() = *magic; // [__selitem__, a, b, val]
|
||||
if(!py_vectorcall(2, 0)) goto __ERROR;
|
||||
POP(); // discard retval
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
@ -423,7 +423,6 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
INSERT_THIRD(); // [?, a, b]
|
||||
*THIRD() = *magic; // [__delitem__, a, b]
|
||||
if(!py_vectorcall(1, 0)) goto __ERROR;
|
||||
POP(); // discard retval
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
|
@ -63,11 +63,44 @@ static bool slice_step(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool slice__eq__(int argc, py_Ref argv) {
|
||||
py_Ref self = py_arg(0);
|
||||
py_Ref other = py_arg(1);
|
||||
if(!py_istype(other, tp_slice)) {
|
||||
py_newnotimplemented(py_retval());
|
||||
return true;
|
||||
}
|
||||
for(int i = 0; i < 3; i++) {
|
||||
py_Ref lhs = py_getslot(self, i);
|
||||
py_Ref rhs = py_getslot(other, i);
|
||||
int res = py_equal(lhs, rhs);
|
||||
if(res == -1) return false;
|
||||
if(res == 0) {
|
||||
py_newbool(py_retval(), false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
py_newbool(py_retval(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool slice__ne__(int argc, py_Ref argv) {
|
||||
bool ok = slice__eq__(argc, argv);
|
||||
if(!ok) return false;
|
||||
py_Ref res = py_retval();
|
||||
if(py_isbool(res)) py_newbool(py_retval(), !py_tobool(res));
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_slice__register() {
|
||||
py_Type type = pk_newtype("slice", tp_object, NULL, NULL, false, true);
|
||||
|
||||
py_bindmagic(type, __new__, slice__new__);
|
||||
py_bindmagic(type, __repr__, slice__repr__);
|
||||
py_bindmagic(type, __eq__, slice__eq__);
|
||||
py_bindmagic(type, __ne__, slice__ne__);
|
||||
|
||||
py_setdict(py_tpobject(type), __hash__, py_None);
|
||||
|
||||
py_bindproperty(type, "start", slice_start, NULL);
|
||||
py_bindproperty(type, "stop", slice_stop, NULL);
|
||||
|
@ -167,26 +167,6 @@ assert b == [(5, 1), (1, 2), (3,3)]
|
||||
|
||||
# assert repr(a) == "[0, [1, 2, [...]]]"
|
||||
|
||||
# try:
|
||||
# a.index(1, 1)
|
||||
# exit(1)
|
||||
# except ValueError:
|
||||
# pass
|
||||
|
||||
# slice extras
|
||||
# class A:
|
||||
# def __getitem__(self, index):
|
||||
# return index
|
||||
|
||||
# assert A()[1:2, 3] == (slice(1, 2, None), 3)
|
||||
# assert A()[1:2, 3:4] == (slice(1, 2, None), slice(3, 4, None))
|
||||
# assert A()[1:2, 3:4, 5] == (slice(1, 2, None), slice(3, 4, None), 5)
|
||||
# assert A()[:, :] == (slice(None, None, None), slice(None, None, None))
|
||||
# assert A()[::, :] == (slice(None, None, None), slice(None, None, None))
|
||||
# assert A()[::, :2] == (slice(None, None, None), slice(None, 2, None))
|
||||
# assert A()['b':'c':1, :] == (slice('b', 'c', 1), slice(None, None, None))
|
||||
# assert A()[1:2, :A()[3:4, ::-1]] == (slice(1, 2, None), slice(None, (slice(3, 4, None), slice(None, None, -1)), None))
|
||||
|
||||
# unpacking builder (not supported)
|
||||
# a = [1, 2, 3]
|
||||
# b = [*a, 4, 5]
|
||||
|
@ -47,7 +47,7 @@ try:
|
||||
a = A()
|
||||
b = a[1]
|
||||
exit(1)
|
||||
except:
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
|
49
tests/99_extras.py
Normal file
49
tests/99_extras.py
Normal file
@ -0,0 +1,49 @@
|
||||
try:
|
||||
a = [1, 2, 3]
|
||||
a.index(999)
|
||||
exit(1)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# test some python magics
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.d = {}
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.d[index]
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
self.d[index] = value
|
||||
|
||||
def __contains__(self, index):
|
||||
return index in self.d
|
||||
|
||||
def __delitem__(self, index):
|
||||
del self.d[index]
|
||||
|
||||
a = A()
|
||||
a['1'] = 3
|
||||
assert '1' in a
|
||||
assert '2' not in a
|
||||
assert a['1'] == 3
|
||||
del a['1']
|
||||
assert '1' not in a
|
||||
|
||||
# slice extras
|
||||
class A:
|
||||
def __getitem__(self, index):
|
||||
return index
|
||||
|
||||
assert slice(1, 2, None) == slice(1, 2, None)
|
||||
assert slice(1, 3, None) != slice(1, 2, None)
|
||||
|
||||
assert A()[1] == 1
|
||||
assert A()[1:2, 3] == (slice(1, 2, None), 3)
|
||||
assert A()[1:2, 3:4] == (slice(1, 2, None), slice(3, 4, None))
|
||||
assert A()[1:2, 3:4, 5] == (slice(1, 2, None), slice(3, 4, None), 5)
|
||||
assert A()[:, :] == (slice(None, None, None), slice(None, None, None))
|
||||
assert A()[::, :] == (slice(None, None, None), slice(None, None, None))
|
||||
assert A()[::, :2] == (slice(None, None, None), slice(None, 2, None))
|
||||
assert A()['b':'c':1, :] == (slice('b', 'c', 1), slice(None, None, None))
|
||||
assert A()[1:2, :A()[3:4, ::-1]] == (slice(1, 2, None), slice(None, (slice(3, 4, None), slice(None, None, -1)), None))
|
Loading…
x
Reference in New Issue
Block a user