--- 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_MODE); std::cout << py_cast(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` + `VM::bind_builtin_func` + `VM::bind_method` + `VM::bind_static_method` 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. !!!