From 076cfdd09a981699f8efdb4f4cb109f7e7f9b4f4 Mon Sep 17 00:00:00 2001 From: landerlyoung Date: Sun, 19 Dec 2021 16:50:07 +0800 Subject: [PATCH] py arguments & newFunction --- backend/Python/PyHelper.h | 2 ++ backend/Python/PyHelper.hpp | 27 +++++++++++++++-- backend/Python/PyNative.cc | 26 ++++++++++++---- backend/Python/PyValue.cc | 48 +++++++++++++++++++++++++++++- backend/Python/trait/TraitNative.h | 6 ++-- backend/Python/trait/TraitUtils.h | 4 +-- 6 files changed, 98 insertions(+), 15 deletions(-) diff --git a/backend/Python/PyHelper.h b/backend/Python/PyHelper.h index db8375e1..8158e146 100644 --- a/backend/Python/PyHelper.h +++ b/backend/Python/PyHelper.h @@ -34,6 +34,8 @@ SCRIPTX_END_INCLUDE_LIBRARY namespace script::py_backend { +class PyEngine; + PyObject* checkException(PyObject* obj); int checkException(int ret); void checkException(); diff --git a/backend/Python/PyHelper.hpp b/backend/Python/PyHelper.hpp index 503fa184..2197ed34 100644 --- a/backend/Python/PyHelper.hpp +++ b/backend/Python/PyHelper.hpp @@ -16,16 +16,37 @@ */ #pragma once +#include "../../src/Native.hpp" #include "../../src/Reference.h" #include "PyHelper.h" -namespace script::py_backend { +namespace script { struct py_interop { - template + template static Local makeLocal(PyObject* ref) { return Local(ref); } + + /** + * @return stolen ref. + */ + template + static PyObject* toPy(const Local& ref) { + return Py_XNewRef(ref.val_); + } + + /** + * @return borrowed ref. + */ + template + static PyObject* asPy(const Local& ref) { + return ref.val_; + } + + static Arguments makeArguments(py_backend::PyEngine* engine, PyObject* self, PyObject* args) { + return Arguments(py_backend::ArgumentsData{engine, self, args}); + } }; -} // namespace script::py_backend \ No newline at end of file +} // namespace script \ No newline at end of file diff --git a/backend/Python/PyNative.cc b/backend/Python/PyNative.cc index 05c10e6a..703a43c0 100644 --- a/backend/Python/PyNative.cc +++ b/backend/Python/PyNative.cc @@ -15,7 +15,9 @@ * limitations under the License. */ -#include +#include "../../src/Native.hpp" +#include "PyEngine.h" +#include "PyHelper.hpp" namespace script { @@ -23,15 +25,27 @@ Arguments::Arguments(InternalCallbackInfoType callbackInfo) : callbackInfo_(call Arguments::~Arguments() = default; -Local Arguments::thiz() const { TEMPLATE_NOT_IMPLEMENTED(); } +Local Arguments::thiz() const { + return py_interop::makeLocal(callbackInfo_.self).asObject(); +} -bool Arguments::hasThiz() const { TEMPLATE_NOT_IMPLEMENTED(); } +bool Arguments::hasThiz() const { return callbackInfo_.self != nullptr; } -size_t Arguments::size() const { TEMPLATE_NOT_IMPLEMENTED(); } +size_t Arguments::size() const { + if (!callbackInfo_.args) { + return 0; + } + return PyTuple_Size(callbackInfo_.args); +} -Local Arguments::operator[](size_t i) const { return {}; } +Local Arguments::operator[](size_t i) const { + if (i < size()) { + return py_interop::makeLocal(PyTuple_GetItem(callbackInfo_.args, i)); + } + return {}; +} -ScriptEngine* Arguments::engine() const { return nullptr; } +ScriptEngine* Arguments::engine() const { return callbackInfo_.engine; } ScriptClass::ScriptClass(const script::Local& scriptObject) : internalState_() { TEMPLATE_NOT_IMPLEMENTED(); diff --git a/backend/Python/PyValue.cc b/backend/Python/PyValue.cc index f06ab80b..11ba4e8f 100644 --- a/backend/Python/PyValue.cc +++ b/backend/Python/PyValue.cc @@ -85,8 +85,54 @@ Local Boolean::newBoolean(bool value) { return checkAndMakeLocal(PyBool_FromLong(value)); } +namespace { + +static constexpr const char* kFunctionDataName = "capsule_function_data"; + +struct FunctionData { + FunctionCallback function; + py_backend::PyEngine* engine = nullptr; +}; + +} // namespace + Local Function::newFunction(script::FunctionCallback callback) { - TEMPLATE_NOT_IMPLEMENTED(); + auto callbackIns = std::make_unique(); + callbackIns->engine = EngineScope::currentEngineAs(); + callbackIns->function = std::move(callback); + + PyMethodDef method{}; + method.ml_name = "ScriptX_native_method"; + method.ml_flags = METH_O; + method.ml_doc = "ScriptX Function::newFunction"; + method.ml_meth = [](PyObject* self, PyObject* args) -> PyObject* { + auto ptr = PyCapsule_GetPointer(self, kFunctionDataName); + if (ptr == nullptr) { + // TODO: exception + } else { + auto data = static_cast(ptr); + try { + auto ret = data->function(py_interop::makeArguments(nullptr, self, args)); + return py_interop::toPy(ret); + } catch (Exception& e) { + // TODO: exception + } + } + return nullptr; + }; + + auto ctx = PyCapsule_New(callbackIns.get(), kFunctionDataName, [](PyObject* cap) { + auto ptr = PyCapsule_GetPointer(cap, kFunctionDataName); + delete static_cast(ptr); + }); + + PyObject* closure = PyCFunction_New(&method, ctx); + + Py_XDECREF(ctx); + + // todo: check exception + callbackIns.release(); + return Local(closure); } Local Array::newArray(size_t size) { diff --git a/backend/Python/trait/TraitNative.h b/backend/Python/trait/TraitNative.h index 79f57f3e..3022f038 100644 --- a/backend/Python/trait/TraitNative.h +++ b/backend/Python/trait/TraitNative.h @@ -17,14 +17,16 @@ #pragma once #include "../../src/types.h" +#include "../PyHelper.h" namespace script { namespace py_backend { struct ArgumentsData { - int stackBase; - size_t size; + mutable PyEngine* engine; + PyObject* self; + PyObject* args; }; struct ScriptClassState { diff --git a/backend/Python/trait/TraitUtils.h b/backend/Python/trait/TraitUtils.h index 506a9c46..215f6802 100644 --- a/backend/Python/trait/TraitUtils.h +++ b/backend/Python/trait/TraitUtils.h @@ -20,9 +20,7 @@ namespace script { -namespace py_backend { struct py_interop; -} template <> struct internal::ImplType { @@ -31,7 +29,7 @@ struct internal::ImplType { template <> struct internal::ImplType { - using type = py_backend::py_interop; + using type = py_interop; }; } // namespace script \ No newline at end of file