Skip to content

Commit be3022b

Browse files
committed
Allow calling stored JS functions.
1 parent 4156e73 commit be3022b

File tree

2 files changed

+55
-13
lines changed

2 files changed

+55
-13
lines changed

module.c

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,42 @@ static PyObject *object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2525
}
2626

2727
static void object_dealloc(ObjectData *self) {
28+
if (self->context) {
29+
JS_FreeValue(self->context, self->object);
30+
}
2831
Py_TYPE(self)->tp_free((PyObject *)self);
2932
}
3033

31-
static PyObject *object_call(ObjectData *self, PyObject *args) {
32-
if (self->context) {
33-
JS_FreeValue(self->context, self->object);
34+
static PyObject *object_call(ObjectData *self, PyObject *args, PyObject *kwds) {
35+
if (self->context == NULL) {
36+
Py_RETURN_NONE;
3437
}
35-
Py_RETURN_NONE;
38+
const int nargs = PyTuple_Size(args);
39+
for (int i = 0; i < nargs; ++i) {
40+
PyObject *item = PyTuple_GetItem(args, i);
41+
if (PyLong_Check(item)) {
42+
} else {
43+
PyErr_Format(PyExc_ValueError, "Unsupported type when calling quickjs object");
44+
return NULL;
45+
}
46+
}
47+
JSValueConst *jsargs = malloc(nargs * sizeof(JSValueConst));
48+
for (int i = 0; i < nargs; ++i) {
49+
PyObject *item = PyTuple_GetItem(args, i);
50+
if (PyLong_Check(item)) {
51+
jsargs[i] = JS_MKVAL(JS_TAG_INT, PyLong_AsLong(item));
52+
}
53+
}
54+
JSValue value = JS_Call(self->context, self->object, JS_NULL, 1, jsargs);
55+
for (int i = 0; i < nargs; ++i) {
56+
JS_FreeValue(self->context, jsargs[i]);
57+
}
58+
free(jsargs);
59+
return quickjs_to_python(self->context, value);
3660
}
3761

3862
static PyMethodDef object_methods[] = {
39-
{"call", (PyCFunction)object_call, METH_VARARGS, "Calls a JS function."}, {NULL} /* Sentinel */
63+
{NULL} /* Sentinel */
4064
};
4165

4266
static PyTypeObject Object = {PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_quickjs.Object",
@@ -46,6 +70,7 @@ static PyTypeObject Object = {PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_quickjs
4670
.tp_flags = Py_TPFLAGS_DEFAULT,
4771
.tp_new = object_new,
4872
.tp_dealloc = (destructor)object_dealloc,
73+
.tp_call = object_call,
4974
.tp_methods = object_methods};
5075

5176
static PyObject *quickjs_to_python(JSContext *context, JSValue value) {

test_quickjs.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,37 @@ def test_context_between_calls(self):
4040

4141
def test_function(self):
4242
self.context.eval("""
43-
function special(x) {
44-
return 40 + x;
45-
}
46-
""")
43+
function special(x) {
44+
return 40 + x;
45+
}
46+
""")
4747
self.assertEqual(self.context.eval("special(2)"), 42)
4848

4949
def test_function_is_object(self):
5050
f = self.context.eval("""
51-
a = function(x) {
52-
return 40 + x;
53-
}
54-
""")
51+
a = function(x) {
52+
return 40 + x;
53+
}
54+
""")
5555
self.assertIsInstance(f, quickjs.Object)
5656

57+
def test_function_call(self):
58+
f = self.context.eval("""
59+
f = function(x) {
60+
return 40 + x;
61+
}
62+
""")
63+
self.assertEqual(f(2), 42)
64+
65+
def test_function_call_unsupported_arg(self):
66+
f = self.context.eval("""
67+
f = function(x) {
68+
return 40 + x;
69+
}
70+
""")
71+
with self.assertRaisesRegex(ValueError, "Unsupported type"):
72+
self.assertEqual(f({}), 42)
73+
5774
def test_error(self):
5875
with self.assertRaisesRegex(quickjs.JSException, "ReferenceError: missing is not defined"):
5976
self.context.eval("missing + missing")

0 commit comments

Comments
 (0)