mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
...
This commit is contained in:
parent
2ca9df3f90
commit
286d603e31
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
icon: book
|
icon: book
|
||||||
order: 2
|
order: 2
|
||||||
label: Coding Style Guide
|
label: Coding style guide
|
||||||
---
|
---
|
||||||
|
|
||||||
# Coding Style Guide
|
# Coding Style Guide
|
||||||
|
@ -1,151 +0,0 @@
|
|||||||
---
|
|
||||||
icon: code
|
|
||||||
label: 'C++'
|
|
||||||
order: 10
|
|
||||||
---
|
|
||||||
|
|
||||||
For C++ developers, you can download the `pocketpy.h` on our GitHub release page.
|
|
||||||
|
|
||||||
https://github.com/blueloveTH/pocketpy/releases/latest
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "pocketpy.h"
|
|
||||||
|
|
||||||
using namespace pkpy;
|
|
||||||
|
|
||||||
int main(){
|
|
||||||
// Create a virtual machine
|
|
||||||
VM* vm = new VM(true);
|
|
||||||
|
|
||||||
// Hello world!
|
|
||||||
vm->exec("print('Hello world!')", "main.py", EXEC_MODE);
|
|
||||||
|
|
||||||
// Create a list
|
|
||||||
vm->exec("a = [1, 2, 3]", "main.py", EXEC_MODE);
|
|
||||||
|
|
||||||
// Eval the sum of the list
|
|
||||||
PyObject* result = vm->exec("sum(a)", "<eval>", EVAL_MODE);
|
|
||||||
std::cout << py_cast<i64>(vm, result); // 6
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Interop with `PyObject*`
|
|
||||||
|
|
||||||
In PkPy, any python object is represented by a `PyObject*`.
|
|
||||||
|
|
||||||
+ `VAR(...)`,
|
|
||||||
create a `PyObject*` from a C type
|
|
||||||
+ `CAST(T, ...)`,
|
|
||||||
cast a `PyObject*` to a C type
|
|
||||||
+ `_CAST(T, ...)`,
|
|
||||||
cast a `PyObject*` to a C type, without type check
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
PyObject* x = VAR(12); // cast a C int to PyObject*
|
|
||||||
int y = CAST(int, x); // cast a PyObject* to C int
|
|
||||||
|
|
||||||
PyObject* i = VAR("abc");
|
|
||||||
std::cout << CAST(Str, i); // abc
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Types
|
|
||||||
|
|
||||||
| `PyObject` type | C type | note |
|
|
||||||
| ------------ | ---------------- | ---------------------- |
|
|
||||||
| `int` | `i64` | 62 bits integer |
|
|
||||||
| `float` | `f64` | 62 bits floating point |
|
|
||||||
| `str` | `pkpy::Str` | |
|
|
||||||
| `bool` | `bool` | |
|
|
||||||
| `list` | `pkpy::List` | |
|
|
||||||
| `tuple` | `pkpy::Tuple` | |
|
|
||||||
| `function` | `pkpy::Function` | |
|
|
||||||
| ... | ... | ... |
|
|
||||||
|
|
||||||
## Bind a Native Function
|
|
||||||
|
|
||||||
In `VM` class, there are 4 methods to bind native function.
|
|
||||||
|
|
||||||
+ `VM::bind_func<ARGC>`
|
|
||||||
+ `VM::bind_builtin_func<ARGC>`
|
|
||||||
+ `VM::bind_method<ARGC>`
|
|
||||||
+ `VM::bind_static_method<ARGC>`
|
|
||||||
|
|
||||||
They are all template methods, the template argument is a `int` number, indicating the argument count. For variadic arguments, use `-1`. For methods, `ARGC` do not include `self`.
|
|
||||||
|
|
||||||
!!!
|
|
||||||
|
|
||||||
Native functions do not support keyword arguments.
|
|
||||||
|
|
||||||
!!!
|
|
||||||
|
|
||||||
PkPy uses a universal C function pointer for native functions:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
|
||||||
```
|
|
||||||
|
|
||||||
The first argument is the pointer of `VM` instance.
|
|
||||||
|
|
||||||
The second argument is a view of an array. You can use `[]` operator to get the element. If you have specified `ARGC` other than `-1`, the interpreter will ensure `args.size() == ARGC`. No need to do size check.
|
|
||||||
|
|
||||||
The return value is a `PyObject*`, which should not be `nullptr`. If there is no return value, return `vm->None`.
|
|
||||||
|
|
||||||
This is an example of binding the `input()` function to the `builtins` module.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
VM* vm = pkpy_new_vm(true);
|
|
||||||
vm->bind_builtin_func<0>("input", [](VM* vm, ArgsView args){
|
|
||||||
static std::string line;
|
|
||||||
std::getline(std::cin, line);
|
|
||||||
return VAR(line);
|
|
||||||
});
|
|
||||||
|
|
||||||
// vvv function name
|
|
||||||
vm->bind_builtin_func<2>("add", [](VM* vm, ArgsView args){
|
|
||||||
// ^ argument count
|
|
||||||
i64 lhs = CAST(i64, args[0]);
|
|
||||||
i64 rhs = CAST(i64, args[1]);
|
|
||||||
return VAR(lhs + rhs);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Call a Python Function
|
|
||||||
|
|
||||||
Use these to call a python function.
|
|
||||||
|
|
||||||
+ `PyObject* VM::call(PyObject* obj, ...)`
|
|
||||||
+ `PyObject* VM::call_method(PyObject* obj, StrName name, ...)`
|
|
||||||
|
|
||||||
For example, to create a `dict` object,
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
PyObject* tp = vm->builtins->attr("dict");
|
|
||||||
PyObject* obj = vm->call(tp); // this is a `dict`
|
|
||||||
```
|
|
||||||
|
|
||||||
And set a key-value pair,
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
vm->call_method(obj, "__setitem__", VAR("a"), VAR(5));
|
|
||||||
PyObject* ret = vm->call(obj, "__getitem__", VAR("a"));
|
|
||||||
std::cout << CAST(int, ret) << std::endl; // 5
|
|
||||||
```
|
|
||||||
|
|
||||||
## Attribute Access
|
|
||||||
|
|
||||||
There are 3 methods for this.
|
|
||||||
|
|
||||||
+ `PyObject* VM::getattr(PyObject*, StrName)`
|
|
||||||
+ `void VM::setattr(PyObject*, StrName, PyObject*)`
|
|
||||||
+ `PyObject* VM::get_unbound_method(PyObject*, StrName, PyObject**)`
|
|
||||||
|
|
||||||
## Wrapping a `struct` as `PyObject`
|
|
||||||
|
|
||||||
!!!
|
|
||||||
|
|
||||||
This feature is unstable.
|
|
||||||
|
|
||||||
!!!
|
|
@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
icon: code
|
|
||||||
label: Godot Engine
|
|
||||||
order: 2
|
|
||||||
---
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
PocketPy for Godot is integrated via [GDExtension](https://godotengine.org/article/introducing-gd-extensions).
|
|
||||||
|
|
||||||
!!!
|
|
||||||
GDExtension is a Godot 4.0 feature. Godot 3.x won't work.
|
|
||||||
!!!
|
|
||||||
|
|
||||||
Please see https://github.com/blueloveTH/godot-cpp/tree/master/pocketpy for details.
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```gdscript
|
|
||||||
# main.gd
|
|
||||||
|
|
||||||
extends Node
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
# Create a virtual machine
|
|
||||||
var vm = pkpy.new_vm(false)
|
|
||||||
|
|
||||||
# Run a script
|
|
||||||
pkpy.vm_exec(vm, "print('Hello World!')")
|
|
||||||
|
|
||||||
# Read the output
|
|
||||||
var _o = pkpy.vm_read_output(vm)
|
|
||||||
|
|
||||||
# Parse the output
|
|
||||||
var res = JSON.parse_string(_o)
|
|
||||||
|
|
||||||
# Print the output
|
|
||||||
print(res["stdout"]) # "Hello World!\n"
|
|
||||||
```
|
|
41
docs/quick-start/01_installation.md
Normal file
41
docs/quick-start/01_installation.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
icon: code
|
||||||
|
label: 'Installation'
|
||||||
|
order: 100
|
||||||
|
---
|
||||||
|
|
||||||
|
You need to download `pocketpy.h` on our GitHub release page.
|
||||||
|
And `#include` it in your project.
|
||||||
|
|
||||||
|
https://github.com/blueloveTH/pocketpy/releases/latest
|
||||||
|
|
||||||
|
Alternatively, you can install it via vcpkg.io.
|
||||||
|
(Will be available soon)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vcpkg install pocketpy
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "pocketpy.h"
|
||||||
|
|
||||||
|
using namespace pkpy;
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
// Create a virtual machine
|
||||||
|
VM* vm = new VM(true);
|
||||||
|
|
||||||
|
// Hello world!
|
||||||
|
vm->exec("print('Hello world!')", "main.py", EXEC_MODE);
|
||||||
|
|
||||||
|
// Create a list
|
||||||
|
vm->exec("a = [1, 2, 3]", "main.py", EXEC_MODE);
|
||||||
|
|
||||||
|
// Eval the sum of the list
|
||||||
|
PyObject* result = vm->exec("sum(a)", "<eval>", EVAL_MODE);
|
||||||
|
std::cout << CAST(int, result); // 6
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
35
docs/quick-start/02_interop.md
Normal file
35
docs/quick-start/02_interop.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
icon: code
|
||||||
|
label: 'Interop with PyObject'
|
||||||
|
order: 90
|
||||||
|
---
|
||||||
|
|
||||||
|
Any python object is represented by a `PyObject*`.
|
||||||
|
|
||||||
|
+ `VAR(...)`,
|
||||||
|
create a `PyObject*` from a C type
|
||||||
|
+ `CAST(T, ...)`,
|
||||||
|
cast a `PyObject*` to a C type
|
||||||
|
+ `_CAST(T, ...)`,
|
||||||
|
cast a `PyObject*` to a C type, without type check
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyObject* x = VAR(12); // cast a C int to PyObject*
|
||||||
|
int y = CAST(int, x); // cast a PyObject* to C int
|
||||||
|
|
||||||
|
PyObject* i = VAR("abc");
|
||||||
|
std::cout << CAST(Str, i); // abc
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Types
|
||||||
|
|
||||||
|
| `PyObject` type | C type | note |
|
||||||
|
| ------------ | ---------------- | ---------------------- |
|
||||||
|
| `int` | `i64` | 62 bits integer |
|
||||||
|
| `float` | `f64` | 62 bits floating point |
|
||||||
|
| `str` | `pkpy::Str` | |
|
||||||
|
| `bool` | `bool` | |
|
||||||
|
| `list` | `pkpy::List` | |
|
||||||
|
| `tuple` | `pkpy::Tuple` | |
|
||||||
|
| `function` | `pkpy::Function` | |
|
||||||
|
| ... | ... | ... |
|
31
docs/quick-start/03_attr.md
Normal file
31
docs/quick-start/03_attr.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
icon: code
|
||||||
|
label: 'Attribute access'
|
||||||
|
order: 80
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true)`
|
||||||
|
|
||||||
|
This method is equivalent to `getattr` in Python.
|
||||||
|
If the attribute is not found, it will return `nullptr`
|
||||||
|
or throw an `AttributeError` depending on the value of `throw_err`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// create a `int` object
|
||||||
|
PyObject* obj = VAR(1);
|
||||||
|
|
||||||
|
// get its `__add__` method, which is a `bound_method` object
|
||||||
|
PyObject* add = vm->getattr(obj, "__add__");
|
||||||
|
|
||||||
|
// call it (equivalent to `1 + 2`)
|
||||||
|
PyObject* ret = vm->call(add, VAR(2));
|
||||||
|
|
||||||
|
// get the result
|
||||||
|
int result = CAST(int, ret);
|
||||||
|
std::cout << result << std::endl; // 3
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `void setattr(PyObject*, StrName, PyObject*)`
|
||||||
|
|
||||||
|
This method is equivalent to `setattr` in Python.
|
||||||
|
It raises `TypeError` if the object does not support attribute assignment.
|
25
docs/quick-start/04_call.md
Normal file
25
docs/quick-start/04_call.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
icon: code
|
||||||
|
label: 'Call a Python function'
|
||||||
|
order: 70
|
||||||
|
---
|
||||||
|
|
||||||
|
Use these to call a python function.
|
||||||
|
|
||||||
|
+ `PyObject* VM::call(PyObject* obj, ...)`
|
||||||
|
+ `PyObject* VM::call_method(PyObject* obj, StrName name, ...)`
|
||||||
|
|
||||||
|
For example, to create a `dict` object,
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyObject* tp = vm->builtins->attr("dict");
|
||||||
|
PyObject* obj = vm->call(tp); // this is a `dict`
|
||||||
|
```
|
||||||
|
|
||||||
|
And set a key-value pair,
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
vm->call_method(obj, "__setitem__", VAR("a"), VAR(5));
|
||||||
|
PyObject* ret = vm->call(obj, "__getitem__", VAR("a"));
|
||||||
|
std::cout << CAST(int, ret) << std::endl; // 5
|
||||||
|
```
|
51
docs/quick-start/05_bind.md
Normal file
51
docs/quick-start/05_bind.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
icon: code
|
||||||
|
label: 'Bind native function'
|
||||||
|
order: 60
|
||||||
|
---
|
||||||
|
|
||||||
|
In `VM` class, there are 4 methods to bind native function.
|
||||||
|
|
||||||
|
+ `VM::bind_func<ARGC>`
|
||||||
|
+ `VM::bind_builtin_func<ARGC>`
|
||||||
|
+ `VM::bind_method<ARGC>`
|
||||||
|
+ `VM::bind_static_method<ARGC>`
|
||||||
|
|
||||||
|
They are all template methods, the template argument is a `int` number, indicating the argument count. For variadic arguments, use `-1`. For methods, `ARGC` do not include `self`.
|
||||||
|
|
||||||
|
!!!
|
||||||
|
|
||||||
|
Native functions do not support keyword arguments.
|
||||||
|
|
||||||
|
!!!
|
||||||
|
|
||||||
|
PkPy uses a universal C function pointer for native functions:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
||||||
|
```
|
||||||
|
|
||||||
|
The first argument is the pointer of `VM` instance.
|
||||||
|
|
||||||
|
The second argument is a view of an array. You can use `[]` operator to get the element. If you have specified `ARGC` other than `-1`, the interpreter will ensure `args.size() == ARGC`. No need to do size check.
|
||||||
|
|
||||||
|
The return value is a `PyObject*`, which should not be `nullptr`. If there is no return value, return `vm->None`.
|
||||||
|
|
||||||
|
This is an example of binding the `input()` function to the `builtins` module.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
VM* vm = pkpy_new_vm(true);
|
||||||
|
vm->bind_builtin_func<0>("input", [](VM* vm, ArgsView args){
|
||||||
|
static std::string line;
|
||||||
|
std::getline(std::cin, line);
|
||||||
|
return VAR(line);
|
||||||
|
});
|
||||||
|
|
||||||
|
// vvv function name
|
||||||
|
vm->bind_builtin_func<2>("add", [](VM* vm, ArgsView args){
|
||||||
|
// ^ argument count
|
||||||
|
i64 lhs = CAST(i64, args[0]);
|
||||||
|
i64 rhs = CAST(i64, args[1]);
|
||||||
|
return VAR(lhs + rhs);
|
||||||
|
});
|
||||||
|
```
|
7
docs/quick-start/06_wrap.md
Normal file
7
docs/quick-start/06_wrap.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
icon: code
|
||||||
|
label: 'Wrap a native struct'
|
||||||
|
order: 50
|
||||||
|
---
|
||||||
|
|
||||||
|
Wrapping a `struct` as `PyObject`
|
Loading…
x
Reference in New Issue
Block a user