Skip to content

Commit 076cfdd

Browse files
committed
py arguments & newFunction
1 parent b5d09f9 commit 076cfdd

File tree

6 files changed

+98
-15
lines changed

6 files changed

+98
-15
lines changed

backend/Python/PyHelper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ SCRIPTX_END_INCLUDE_LIBRARY
3434

3535
namespace script::py_backend {
3636

37+
class PyEngine;
38+
3739
PyObject* checkException(PyObject* obj);
3840
int checkException(int ret);
3941
void checkException();

backend/Python/PyHelper.hpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,37 @@
1616
*/
1717

1818
#pragma once
19+
#include "../../src/Native.hpp"
1920
#include "../../src/Reference.h"
2021
#include "PyHelper.h"
2122

22-
namespace script::py_backend {
23+
namespace script {
2324

2425
struct py_interop {
25-
template <class T>
26+
template <typename T>
2627
static Local<T> makeLocal(PyObject* ref) {
2728
return Local<T>(ref);
2829
}
30+
31+
/**
32+
* @return stolen ref.
33+
*/
34+
template <typename T>
35+
static PyObject* toPy(const Local<T>& ref) {
36+
return Py_XNewRef(ref.val_);
37+
}
38+
39+
/**
40+
* @return borrowed ref.
41+
*/
42+
template <typename T>
43+
static PyObject* asPy(const Local<T>& ref) {
44+
return ref.val_;
45+
}
46+
47+
static Arguments makeArguments(py_backend::PyEngine* engine, PyObject* self, PyObject* args) {
48+
return Arguments(py_backend::ArgumentsData{engine, self, args});
49+
}
2950
};
3051

31-
} // namespace script::py_backend
52+
} // namespace script

backend/Python/PyNative.cc

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,37 @@
1515
* limitations under the License.
1616
*/
1717

18-
#include <ScriptX/ScriptX.h>
18+
#include "../../src/Native.hpp"
19+
#include "PyEngine.h"
20+
#include "PyHelper.hpp"
1921

2022
namespace script {
2123

2224
Arguments::Arguments(InternalCallbackInfoType callbackInfo) : callbackInfo_(callbackInfo) {}
2325

2426
Arguments::~Arguments() = default;
2527

26-
Local<Object> Arguments::thiz() const { TEMPLATE_NOT_IMPLEMENTED(); }
28+
Local<Object> Arguments::thiz() const {
29+
return py_interop::makeLocal<Value>(callbackInfo_.self).asObject();
30+
}
2731

28-
bool Arguments::hasThiz() const { TEMPLATE_NOT_IMPLEMENTED(); }
32+
bool Arguments::hasThiz() const { return callbackInfo_.self != nullptr; }
2933

30-
size_t Arguments::size() const { TEMPLATE_NOT_IMPLEMENTED(); }
34+
size_t Arguments::size() const {
35+
if (!callbackInfo_.args) {
36+
return 0;
37+
}
38+
return PyTuple_Size(callbackInfo_.args);
39+
}
3140

32-
Local<Value> Arguments::operator[](size_t i) const { return {}; }
41+
Local<Value> Arguments::operator[](size_t i) const {
42+
if (i < size()) {
43+
return py_interop::makeLocal<Value>(PyTuple_GetItem(callbackInfo_.args, i));
44+
}
45+
return {};
46+
}
3347

34-
ScriptEngine* Arguments::engine() const { return nullptr; }
48+
ScriptEngine* Arguments::engine() const { return callbackInfo_.engine; }
3549

3650
ScriptClass::ScriptClass(const script::Local<script::Object>& scriptObject) : internalState_() {
3751
TEMPLATE_NOT_IMPLEMENTED();

backend/Python/PyValue.cc

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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+
8899
Local<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

92138
Local<Array> Array::newArray(size_t size) {

backend/Python/trait/TraitNative.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717

1818
#pragma once
1919
#include "../../src/types.h"
20+
#include "../PyHelper.h"
2021

2122
namespace script {
2223

2324
namespace py_backend {
2425

2526
struct ArgumentsData {
26-
int stackBase;
27-
size_t size;
27+
mutable PyEngine* engine;
28+
PyObject* self;
29+
PyObject* args;
2830
};
2931

3032
struct ScriptClassState {

backend/Python/trait/TraitUtils.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020

2121
namespace script {
2222

23-
namespace py_backend {
2423
struct py_interop;
25-
}
2624

2725
template <>
2826
struct internal::ImplType<StringHolder> {
@@ -31,7 +29,7 @@ struct internal::ImplType<StringHolder> {
3129

3230
template <>
3331
struct internal::ImplType<internal::interop> {
34-
using type = py_backend::py_interop;
32+
using type = py_interop;
3533
};
3634

3735
} // namespace script

0 commit comments

Comments
 (0)