@@ -85,8 +85,54 @@ Local<Boolean> Boolean::newBoolean(bool value) {
8585 return checkAndMakeLocal<Boolean>(PyBool_FromLong (value));
8686}
8787
88+ namespace {
89+
90+ static constexpr const char * kFunctionDataName = " capsule_function_data" ;
91+
92+ struct FunctionData {
93+ FunctionCallback function;
94+ py_backend::PyEngine* engine = nullptr ;
95+ };
96+
97+ } // namespace
98+
8899Local<Function> Function::newFunction (script::FunctionCallback callback) {
89- TEMPLATE_NOT_IMPLEMENTED ();
100+ auto callbackIns = std::make_unique<FunctionData>();
101+ callbackIns->engine = EngineScope::currentEngineAs<py_backend::PyEngine>();
102+ callbackIns->function = std::move (callback);
103+
104+ PyMethodDef method{};
105+ method.ml_name = " ScriptX_native_method" ;
106+ method.ml_flags = METH_O;
107+ method.ml_doc = " ScriptX Function::newFunction" ;
108+ method.ml_meth = [](PyObject* self, PyObject* args) -> PyObject* {
109+ auto ptr = PyCapsule_GetPointer (self, kFunctionDataName );
110+ if (ptr == nullptr ) {
111+ // TODO: exception
112+ } else {
113+ auto data = static_cast <FunctionData*>(ptr);
114+ try {
115+ auto ret = data->function (py_interop::makeArguments (nullptr , self, args));
116+ return py_interop::toPy (ret);
117+ } catch (Exception& e) {
118+ // TODO: exception
119+ }
120+ }
121+ return nullptr ;
122+ };
123+
124+ auto ctx = PyCapsule_New (callbackIns.get (), kFunctionDataName , [](PyObject* cap) {
125+ auto ptr = PyCapsule_GetPointer (cap, kFunctionDataName );
126+ delete static_cast <FunctionData*>(ptr);
127+ });
128+
129+ PyObject* closure = PyCFunction_New (&method, ctx);
130+
131+ Py_XDECREF (ctx);
132+
133+ // todo: check exception
134+ callbackIns.release ();
135+ return Local<Function>(closure);
90136}
91137
92138Local<Array> Array::newArray (size_t size) {
0 commit comments