Portable Python 3.x Interpreter in Modern C for Game Scripting; pocketpy (2022).
npm install pocketpy.csh
$ npm i pocketpy.c
`
And then include pocketpy.h as follows:
`c
// main.c
#define POCKETPY_IMPLEMENTATION
#include
int main() { / ... / }
`
Finally, compile while adding the path node_modules/pocketpy.c to your compiler's include paths.
`bash
$ clang -I./node_modules/pocketpy.c main.c # or, use gcc
$ gcc -I./node_modules/pocketpy.c main.c
`
You may also use a simpler approach with the cpoach tool, which automatically adds the necessary include paths of all the installed dependencies for your project.
`bash
$ cpoach clang main.c # or, use gcc
$ cpoach gcc main.c
`
Supported Platforms
pkpy should work on any platform with a C11 compiler.
These platforms are officially tested.
+ Windows 64-bit
+ Linux 64-bit / 32-bit
+ macOS 64-bit
+ Android 64-bit / 32-bit
+ iOS 64-bit
+ Emscripten 32-bit
+ Raspberry Pi OS 64-bit
Quick Start
You have two options to integrate pkpy into your project.
#### Use the single header file
Include the pocketpy.h in your project.
#### Use CMake
Clone the whole repository as a submodule into your project,
In your CMakelists.txt, add the following lines:
`cmake
add_subdirectory(pocketpy)
target_link_libraries( pocketpy)
`
See CMakeLists.txt for details.
It is safe to use main branch in production if CI badge is green.
$3
To compile it with your project, these flags must be set:
+ --std=c11 flag must be set
+ For MSVC, /utf-8 and /experimental:c11atomics 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.
$3
`c
#include "pocketpy.h"
#include
static bool int_add(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(0, tp_int);
PY_CHECK_ARG_TYPE(1, tp_int);
py_i64 a = py_toint(py_arg(0));
py_i64 b = py_toint(py_arg(1));
py_newint(py_retval(), a + b);
return true;
}
int main() {
// Initialize pocketpy
py_initialize();
// Hello world!
bool ok = py_exec("print('Hello world!')", "", EXEC_MODE, NULL);
if(!ok) goto __ERROR;
// Create a list: [1, 2, 3]
py_Ref r0 = py_getreg(0);
py_newlistn(r0, 3);
py_newint(py_list_getitem(r0, 0), 1);
py_newint(py_list_getitem(r0, 1), 2);
py_newint(py_list_getitem(r0, 2), 3);
// Eval the sum of the list
py_Ref f_sum = py_getbuiltin(py_name("sum"));
py_push(f_sum);
py_pushnil();
py_push(r0);
ok = py_vectorcall(1, 0);
if(!ok) goto __ERROR;
printf("Sum of the list: %d\n", (int)py_toint(py_retval())); // 6
// Bind native int_add as a global variable
py_newnativefunc(r0, int_add);
py_setglobal(py_name("add"), r0);
// Call add in python
ok = py_exec("add(3, 7)", "", EVAL_MODE, NULL);
if(!ok) goto __ERROR;
py_i64 res = py_toint(py_retval());
printf("Sum of 2 variables: %d\n", (int)res); // 10
py_finalize();
return 0;
__ERROR:
py_printexc();
py_finalize();
return 1;
}
`
Features
| Name | Example | Supported |
| --------------- | ------------------------------- | --------- |
| If Else | if..else..elif | ✅ |
| Loop | for/while/break/continue | ✅ |
| Function | def f(x,*args,y=1): | ✅ |
| Subclass | class A(B): | ✅ |
| List | [1, 2, 'a'] | ✅ |
| ListComp | [i for i in range(5)] | ✅ |
| Slice | a[1:2], a[:2], a[1:] | ✅ |
| Tuple | (1, 2, 'a') | ✅ |
| Dict | {'a': 1, 'b': 2} | ✅ |
| F-String | f'value is {x}' | ✅ |
| Unpacking | a, b = 1, 2 | ✅ |
| Star Unpacking | a, *b = [1, 2, 3] | ✅ |
| Exception | raise/try..except.. | ✅ |
| Dynamic Code | eval()/exec() | ✅ |
| Reflection | hasattr()/getattr()/setattr() | ✅ |
| Import | import/from..import | ✅ |
| Context Block | with | ✅ |
| Type Annotation | def f(a:int, b:float=1) | ✅ |
| Generator | yield i | ✅ |
| Decorator | @cache | ✅ |
| Match Case | match code: case 200: | ✅ |
Performance
Currently, pkpy is as fast as cpython 3.9.
Performance results for cpython 3.9 are applicable to for pkpy.
See https://pocketpy.dev/performance/ for details.
And these are the results of the primes benchmark on Intel i5-12400F, WSL (Ubuntu 20.04 LTS), which roughly reflects the performance among c++, lua, pkpy and cpython.
| name | version | time | file |
| ---- | ---- | ---- | ---- |
| c++ | gnu++11 | 0.104s ■□□□□□□□□□□□□□□□ | benchmarks/primes.cpp |
| lua | 5.3.3 | 1.576s ■■■■■■■■■□□□□□□□ | benchmarks/primes.lua |
| pkpy | 1.2.7 | 2.385s ■■■■■■■■■■■■■□□□ | benchmarks/primes.py |
| cpython | 3.8.10 | 2.871s ■■■■■■■■■■■■■■■■` | benchmarks/primes.py |