Skip to content

Commit 01a11ea

Browse files
committed
webassembly/objjsproxy: Support arbitrary number of args with kwargs.
When calling from Python into JavaScript and passing along keyword arguments, the FFI bindings currently only support at most 1 positional argument. For example: import js js.func(1, b=2, c=3) This commit fixes that by supporting arbitrary number of positional arguments, in combination with keyword arguments. So now the following works: import js js.func(1, 2, c=3, d=4) Tests are added for these new, supported cases. Signed-off-by: Damien George <damien@micropython.org>
1 parent ac4649d commit 01a11ea

3 files changed

Lines changed: 67 additions & 16 deletions

File tree

ports/webassembly/objjsproxy.c

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -153,20 +153,24 @@ EM_JS(void, call0_kwarg, (int f_ref, bool via_call, uint32_t n_kw, uint32_t * ke
153153
proxy_convert_js_to_mp_obj_jsside(ret, out);
154154
});
155155

156-
EM_JS(void, call1_kwarg, (int f_ref, bool via_call, uint32_t * arg0, uint32_t n_kw, uint32_t * key, uint32_t * value, uint32_t * out), {
156+
EM_JS(void, calln_kwarg, (int f_ref, bool via_call, uint32_t n_args, uint32_t * args_value, uint32_t n_kw, uint32_t * kw_key, uint32_t * kw_value, uint32_t * out), {
157157
const f = proxy_js_ref[f_ref];
158-
const a0 = proxy_convert_mp_to_js_obj_jsside(arg0);
159-
const a = {};
158+
const a = [];
159+
for (let i = 0; i < n_args; ++i) {
160+
const v = proxy_convert_mp_to_js_obj_jsside(args_value + i * 3 * 4);
161+
a.push(v);
162+
}
163+
const ks = {};
160164
for (let i = 0; i < n_kw; ++i) {
161-
const k = UTF8ToString(getValue(key + i * 4, "i32"));
162-
const v = proxy_convert_mp_to_js_obj_jsside(value + i * 3 * 4);
163-
a[k] = v;
165+
const k = UTF8ToString(getValue(kw_key + i * 4, "i32"));
166+
const v = proxy_convert_mp_to_js_obj_jsside(kw_value + i * 3 * 4);
167+
ks[k] = v;
164168
}
165169
let ret;
166170
if (via_call) {
167-
ret = f.call(a0, a);
171+
ret = f.call(... a, ks);
168172
} else {
169-
ret = f(a0, a);
173+
ret = f(... a, ks);
170174
}
171175
proxy_convert_js_to_mp_obj_jsside(ret, out);
172176
});
@@ -218,10 +222,9 @@ static void jsproxy_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
218222
static mp_obj_t jsproxy_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
219223
mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in);
220224

221-
if (n_kw == 0) {
222-
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, false);
223-
} else {
224-
mp_arg_check_num(n_args, n_kw, 0, 1, true);
225+
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
226+
227+
if (n_kw != 0) {
225228
uint32_t key[n_kw];
226229
uint32_t value[PVN * n_kw];
227230
for (int i = 0; i < n_kw; ++i) {
@@ -232,10 +235,11 @@ static mp_obj_t jsproxy_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
232235
if (n_args == 0) {
233236
call0_kwarg(self->ref, self->bind_to_self, n_kw, key, value, out);
234237
} else {
235-
// n_args == 1
236-
uint32_t arg0[PVN];
237-
proxy_convert_mp_to_js_obj_cside(args[0], arg0);
238-
call1_kwarg(self->ref, self->bind_to_self, arg0, n_kw, key, value, out);
238+
uint32_t value_args[PVN * n_args];
239+
for (int i = 0; i < n_args; ++i) {
240+
proxy_convert_mp_to_js_obj_cside(args[i], &value_args[i * PVN]);
241+
}
242+
calln_kwarg(self->ref, self->bind_to_self, n_args, value_args, n_kw, key, value, out);
239243
}
240244
return proxy_convert_js_to_mp_obj_cside(out);
241245
}

tests/ports/webassembly/fun_call.mjs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,30 @@ js.f(1, 2, 3, 4)
1515
js.f(1, 2, 3, 4, 5)
1616
js.f(1, 2, 3, 4, 5, 6)
1717
`);
18+
19+
globalThis.g = (...args) => {
20+
console.log(args);
21+
};
22+
mp.runPython(`
23+
import js
24+
js.g()
25+
js.g(a=1)
26+
js.g(a=1, b=2)
27+
js.g(a=1, b=2, c=3)
28+
js.g(a=1, b=2, c=3, d=4)
29+
js.g(a=1, b=2, c=3, d=4, e=5)
30+
js.g(1)
31+
js.g(1, b=2)
32+
js.g(1, b=2, c=3)
33+
js.g(1, b=2, c=3, d=4)
34+
js.g(1, b=2, c=3, d=4, e=5)
35+
js.g(1, 2)
36+
js.g(1, 2, c=3)
37+
js.g(1, 2, c=3, d=4)
38+
js.g(1, 2, c=3, d=4, e=5)
39+
js.g(1, 2, 3)
40+
js.g(1, 2, 3, d=4)
41+
js.g(1, 2, 3, d=4, e=5)
42+
js.g(1, 2, 3, 4)
43+
js.g(1, 2, 3, 4, e=5)
44+
`);

tests/ports/webassembly/fun_call.mjs.exp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,23 @@ undefined undefined undefined undefined undefined
55
1 2 3 4 undefined
66
1 2 3 4 5
77
1 2 3 4 5
8+
[]
9+
[ { a: 1 } ]
10+
[ { a: 1, b: 2 } ]
11+
[ { a: 1, b: 2, c: 3 } ]
12+
[ { a: 1, b: 2, c: 3, d: 4 } ]
13+
[ { a: 1, b: 2, c: 3, d: 4, e: 5 } ]
14+
[ 1 ]
15+
[ 1, { b: 2 } ]
16+
[ 1, { b: 2, c: 3 } ]
17+
[ 1, { b: 2, c: 3, d: 4 } ]
18+
[ 1, { b: 2, c: 3, d: 4, e: 5 } ]
19+
[ 1, 2 ]
20+
[ 1, 2, { c: 3 } ]
21+
[ 1, 2, { c: 3, d: 4 } ]
22+
[ 1, 2, { c: 3, d: 4, e: 5 } ]
23+
[ 1, 2, 3 ]
24+
[ 1, 2, 3, { d: 4 } ]
25+
[ 1, 2, 3, { d: 4, e: 5 } ]
26+
[ 1, 2, 3, 4 ]
27+
[ 1, 2, 3, 4, { e: 5 } ]

0 commit comments

Comments
 (0)