diff --git a/docs/quick-start/bind.md b/docs/quick-start/bind.md index 30f38ada..7ebb308d 100644 --- a/docs/quick-start/bind.md +++ b/docs/quick-start/bind.md @@ -14,6 +14,34 @@ typedef PyObject* (*NativeFuncC)(VM*, ArgsView); + The second argument is an array-like object indicates the arguments list. You can use `[]` operator to get the element. + The return value is a `PyObject*`, which should not be `nullptr`. If there is no return value, return `vm->None`. + +## New style bindings + +Use `vm->bind` to bind a function or method. + ++ `PyObject* bind(PyObject*, const char* sig, NativeFuncC)` ++ `PyObject* bind(PyObject*, const char* sig, const char* docstring, NativeFuncC)` + +```cpp + +vm->bind(obj, "add(a: int, b: int) -> int", [](VM* vm, ArgsView args){ + int a = CAST(int, args[0]); + int b = CAST(int, args[1]); + return VAR(a + b); +}); + +// or you can provide a docstring +vm->bind(obj, + "add(a: int, b: int) -> int", + "add two integers", [](VM* vm, ArgsView args){ + int a = CAST(int, args[0]); + int b = CAST(int, args[1]); + return VAR(a + b); +}); +``` + +## Old style bindings + !!! Native functions do not support keyword arguments. !!! diff --git a/src/obj.h b/src/obj.h index 4a4d2356..95435c8b 100644 --- a/src/obj.h +++ b/src/obj.h @@ -37,9 +37,13 @@ using FuncDecl_ = shared_ptr; struct NativeFunc { NativeFuncC f; + + // old style argc-based call int argc; - FuncDecl_ decl; // if this is not null, use ex call + // new style decl-based call + FuncDecl_ decl; + const char* docstring; using UserData = char[32]; UserData _userdata; @@ -71,10 +75,11 @@ struct NativeFunc { _has_userdata = false; } - NativeFunc(NativeFuncC f, FuncDecl_ decl){ + NativeFunc(NativeFuncC f, FuncDecl_ decl, const char* docstring){ this->f = f; this->argc = -1; this->decl = decl; + this->docstring = docstring; _has_userdata = false; } diff --git a/src/vm.h b/src/vm.h index ddb478af..f5140cc9 100644 --- a/src/vm.h +++ b/src/vm.h @@ -689,7 +689,8 @@ public: void post_init(); PyObject* _py_generator(Frame&& frame, ArgsView buffer); // new style binding api - PyObject* bind(PyObject*, const Str&, NativeFuncC); + PyObject* bind(PyObject*, const char*, const char*, NativeFuncC); + PyObject* bind(PyObject*, const char*, NativeFuncC); void _prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&); }; @@ -1544,20 +1545,23 @@ PyObject* VM::bind_func(PyObject* obj, Str name, NativeFuncC fn) { return nf; } -inline PyObject* VM::bind(PyObject* obj, const Str& sig, NativeFuncC fn){ +inline PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn){ + return bind(obj, sig, nullptr, fn); +} + +inline PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn){ CodeObject_ co; try{ // fn(a, b, *c, d=1) -> None - co = compile("def " + sig + " : pass", "", EXEC_MODE); + co = compile("def " + Str(sig) + " : pass", "", EXEC_MODE); }catch(Exception& e){ - throw std::runtime_error(("invalid signature: " + sig).str()); + throw std::runtime_error("invalid signature: " + std::string(sig)); } if(co->func_decls.size() != 1){ throw std::runtime_error("expected 1 function declaration"); } FuncDecl_ decl = co->func_decls[0]; - // return VAR(NativeFuncEx(fn, argc, false, sig)); - return nullptr; + return VAR(NativeFunc(fn, decl, docstring)); } inline void VM::_error(Exception e){