Skip to content

Commit 570e4cb

Browse files
committed
Improve callback support in node and python, still not working properly with @trgwii tests.
1 parent 417a7f9 commit 570e4cb

File tree

4 files changed

+85
-27
lines changed

4 files changed

+85
-27
lines changed

source/loaders/py_loader/source/py_loader_impl.c

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ type_id py_loader_impl_capi_to_value_type(PyObject * obj)
240240
{
241241
return TYPE_PTR;
242242
}
243-
else if (PyFunction_Check(obj))
243+
else if (PyFunction_Check(obj) || PyCFunction_Check(obj))
244244
{
245245
return TYPE_FUNCTION;
246246
}
@@ -304,7 +304,7 @@ value py_loader_impl_capi_to_value(loader_impl impl, PyObject * obj, type_id id)
304304
{
305305
if (PyErr_Occurred() != NULL)
306306
{
307-
loader_impl_py py_impl = loader_impl_get(py_func->impl);
307+
loader_impl_py py_impl = loader_impl_get(impl);
308308

309309
py_loader_impl_error_print(py_impl);
310310
}
@@ -401,7 +401,7 @@ value py_loader_impl_capi_to_value(loader_impl impl, PyObject * obj, type_id id)
401401
{
402402
if (PyErr_Occurred() != NULL)
403403
{
404-
loader_impl_py py_impl = loader_impl_get(py_func->impl);
404+
loader_impl_py py_impl = loader_impl_get(impl);
405405

406406
py_loader_impl_error_print(py_impl);
407407
}
@@ -448,7 +448,21 @@ value py_loader_impl_capi_to_value(loader_impl impl, PyObject * obj, type_id id)
448448
}
449449
else if (id == TYPE_FUNCTION)
450450
{
451-
int discover_args_count = py_loader_impl_discover_func_args_count(obj);
451+
int discover_args_count;
452+
453+
/* Check if we are passing our own hook to the callback */
454+
if (PyCFunction_Check(obj) && PyCFunction_GET_FUNCTION(obj) == py_loader_impl_function_type_invoke)
455+
{
456+
loader_impl_py py_impl = loader_impl_get(impl);
457+
458+
loader_impl_py_function_type_invoke_state invoke_state;
459+
460+
invoke_state = (loader_impl_py_function_type_invoke_state)PyModule_GetState(py_impl->function_type_invoke_mod);
461+
462+
return value_create_function(invoke_state->callback);
463+
}
464+
465+
discover_args_count = py_loader_impl_discover_func_args_count(obj);
452466

453467
if (discover_args_count >= 0)
454468
{
@@ -483,8 +497,6 @@ value py_loader_impl_capi_to_value(loader_impl impl, PyObject * obj, type_id id)
483497

484498
return value_create_function(f);
485499
}
486-
487-
return NULL;
488500
}
489501
else if (id == TYPE_NULL)
490502
{
@@ -493,7 +505,7 @@ value py_loader_impl_capi_to_value(loader_impl impl, PyObject * obj, type_id id)
493505
}
494506
else
495507
{
496-
log_write("metacall", LOG_LEVEL_ERROR, "Unrecognized return type");
508+
log_write("metacall", LOG_LEVEL_ERROR, "Unrecognized python type");
497509
}
498510

499511
return v;
@@ -611,6 +623,10 @@ PyObject * py_loader_impl_value_to_capi(loader_impl impl, loader_impl_py py_impl
611623

612624
return py_impl->function_type_invoke_func;
613625
}
626+
else
627+
{
628+
log_write("metacall", LOG_LEVEL_ERROR, "Unrecognized value type");
629+
}
614630

615631
return NULL;
616632
}
@@ -793,7 +809,7 @@ static PyObject * py_loader_impl_function_type_invoke(PyObject * self, PyObject
793809

794810
if (args_size != (size_t)callee_args_size)
795811
{
796-
log_write("metacall", LOG_LEVEL_WARNING, "Callback being executed without different number of arguments %u != %u", args_size, callee_args_size);
812+
log_write("metacall", LOG_LEVEL_WARNING, "Callback being executed without different number of arguments %u (signature) != %u (call)", args_size, callee_args_size);
797813
}
798814

799815
value_args = min_args_size == 0 ? null_args : malloc(sizeof(void *) * min_args_size);
@@ -1398,21 +1414,23 @@ type py_loader_impl_discover_type(loader_impl impl, PyObject * annotation)
13981414
{
13991415
type t = NULL;
14001416

1401-
PyObject * annotation_qualname = PyObject_GetAttrString(annotation, "__qualname__");
1417+
if (annotation != NULL)
1418+
{
1419+
PyObject * annotation_qualname = PyObject_GetAttrString(annotation, "__qualname__");
14021420

1403-
const char * annotation_name = PyUnicode_AsUTF8(annotation_qualname);
1421+
const char * annotation_name = PyUnicode_AsUTF8(annotation_qualname);
14041422

1405-
if (strcmp(annotation_name, "_empty") != 0)
1406-
{
1407-
t = loader_impl_type(impl, annotation_name);
1423+
if (strcmp(annotation_name, "_empty") != 0)
1424+
{
1425+
t = loader_impl_type(impl, annotation_name);
14081426

1409-
log_write("metacall", LOG_LEVEL_DEBUG, "Discover type (%p) (%p): %s", (void *)annotation, (void *)type_derived(t), annotation_name);
1427+
log_write("metacall", LOG_LEVEL_DEBUG, "Discover type (%p) (%p): %s", (void *)annotation, (void *)type_derived(t), annotation_name);
14101428

1411-
Py_DECREF(annotation_qualname);
1429+
Py_DECREF(annotation_qualname);
1430+
}
14121431
}
14131432

14141433
return t;
1415-
14161434
}
14171435

14181436
int py_loader_impl_discover_func_args_count(PyObject * func)
@@ -1452,6 +1470,21 @@ int py_loader_impl_discover_func_args_count(PyObject * func)
14521470

14531471
Py_DECREF(func_code);
14541472
}
1473+
else if (PyCFunction_Check(func))
1474+
{
1475+
int flags = PyCFunction_GetFlags(func);
1476+
1477+
if (flags & METH_NOARGS)
1478+
{
1479+
args_count = 0;
1480+
}
1481+
else if (flags & METH_VARARGS)
1482+
{
1483+
/* TODO: Varidic arguments are not supported */
1484+
log_write("metacall", LOG_LEVEL_ERROR, "Builtins (C Python Functions) with varidic arguments are not supported");
1485+
args_count = -1;
1486+
}
1487+
}
14551488
}
14561489

14571490
return args_count;
@@ -1471,6 +1504,8 @@ int py_loader_impl_discover_func(loader_impl impl, PyObject * func, function f)
14711504
if (PyErr_Occurred() != NULL)
14721505
{
14731506
py_loader_impl_error_print(py_impl);
1507+
1508+
return 1;
14741509
}
14751510

14761511
result = PyObject_CallObject(py_impl->inspect_signature, args);
@@ -1528,6 +1563,19 @@ int py_loader_impl_discover_func(loader_impl impl, PyObject * func, function f)
15281563

15291564
return 0;
15301565
}
1566+
else
1567+
{
1568+
/* TODO: Implement builtins with varidic arguments */
1569+
if (PyCFunction_Check(func))
1570+
{
1571+
signature s = function_signature(f);
1572+
1573+
signature_set_return(s, NULL);
1574+
1575+
return 0;
1576+
}
1577+
1578+
}
15311579

15321580
return 1;
15331581
}

source/ports/node_port/source/node_port.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ void * metacall_node_napi_to_value(/*loader_impl_node node_impl,*/ napi_env env,
514514
closure->env = env;
515515

516516
// Create a reference to this
517-
status = napi_create_reference(env, v, 1, &closure->recv_ref);
517+
status = napi_create_reference(env, recv, 1, &closure->recv_ref);
518518

519519
metacall_node_exception(env, status);
520520

@@ -694,9 +694,21 @@ napi_value metacall_node_value_to_napi(/* loader_impl_node node_impl,*/ napi_env
694694
{
695695
void * f = metacall_value_to_function(arg_value);
696696

697+
size_t length = metacall_function_size(f);
698+
699+
napi_value length_v;
700+
697701
status = napi_create_function(env, NULL, 0, metacall_node_callback_napi_to_value, f, &v);
698702

699703
metacall_node_exception(env, status);
704+
705+
status = napi_create_uint32(env, static_cast<uint32_t>(length), &length_v);
706+
707+
metacall_node_exception(env, status);
708+
709+
status = napi_set_named_property(env, v, "length", length_v);
710+
711+
metacall_node_exception(env, status);
700712
}
701713
else
702714
{

source/ports/node_port/test/index.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@ describe('metacall', () => {
3434
});
3535
});
3636

37-
describe('logs', () => {
38-
it('metacall_logs', () => {
39-
assert.strictEqual(metacall_logs(), undefined);
40-
});
41-
});
42-
4337
describe('load', () => {
4438
it('metacall_load_from_file (py)', () => {
4539
assert.strictEqual(metacall_load_from_file('py', [ 'helloworld.py' ] ), undefined);
@@ -138,9 +132,13 @@ describe('metacall', () => {
138132

139133
// Factorial composition (@trgwii)
140134
/*
141-
const factorial = f.function_factorial_compose(f.function_factorial);
142-
assert.notStrictEqual(factorial, undefined);
143-
assert.strictEqual(factorial(5), 120);
135+
const js_factorial = f.function_chain((x) => (n) => n == 0 ? 1 : n * x(x)(n - 1));
136+
assert.notStrictEqual(js_factorial, undefined);
137+
assert.strictEqual(js_factorial(5), 120);
138+
139+
const py_factorial = f.function_chain(f.function_factorial);
140+
assert.notStrictEqual(py_factorial, undefined);
141+
assert.strictEqual(py_factorial(5), 120);
144142
*/
145143
});
146144
});

source/scripts/python/function/source/function.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def function_currying(y):
2525
def function_currying_more(y):
2626
return lambda x: lambda z: lambda w: lambda n: x * z * w * n * y
2727

28-
def function_factorial_compose(x):
28+
def function_chain(x):
2929
return lambda n: x(x)(n)
3030

3131
def function_factorial(x):

0 commit comments

Comments
 (0)