From d7da571be795efa57a919975363633c0c7fcedd1 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 18 Mar 2024 16:28:48 +0100 Subject: [PATCH 1/6] work on module type --- inc/ti/fn/fnsearch.h | 1 + inc/ti/forloop.h | 3 ++- inc/ti/module.t.h | 4 ++++ inc/ti/val.inline.h | 22 ++++++++++++++++++++++ inc/ti/val.t.h | 1 + 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/inc/ti/fn/fnsearch.h b/inc/ti/fn/fnsearch.h index 2c4fe01e..2973df25 100644 --- a/inc/ti/fn/fnsearch.h +++ b/inc/ti/fn/fnsearch.h @@ -204,6 +204,7 @@ static int do__search_thing( } case TI_VAL_TEMPLATE: case TI_VAL_FUTURE: + case TI_VAL_MODULE: return 0; } assert(0); diff --git a/inc/ti/forloop.h b/inc/ti/forloop.h index f800c08f..ace83a4c 100644 --- a/inc/ti/forloop.h +++ b/inc/ti/forloop.h @@ -39,7 +39,7 @@ typedef int (*ti_forloop_t) ( cleri_node_t *, ex_t *); -static const ti_forloop_t ti_forloop_callbacks[21] = { +static const ti_forloop_t ti_forloop_callbacks[22] = { ti_forloop_no_iter, /* TI_VAL_NIL */ ti_forloop_no_iter, /* TI_VAL_INT */ ti_forloop_no_iter, /* TI_VAL_FLOAT */ @@ -60,6 +60,7 @@ static const ti_forloop_t ti_forloop_callbacks[21] = { ti_forloop_no_iter, /* TI_VAL_MPDATA */ ti_forloop_no_iter, /* TI_VAL_CLOSURE */ ti_forloop_no_iter, /* TI_VAL_FUTURE */ + ti_forloop_no_iter, /* TI_VAL_MODULE */ ti_forloop_no_iter, /* TI_VAL_TEMPLATE */ }; diff --git a/inc/ti/module.t.h b/inc/ti/module.t.h index 13ea7d91..4b4ac75e 100644 --- a/inc/ti/module.t.h +++ b/inc/ti/module.t.h @@ -62,6 +62,10 @@ typedef union struct ti_module_s { uint32_t ref; + uint8_t tp; + uint8_t _pad0; + uint16_t _pad1; + int status; /* 0 = success, >0 = enum, <0 = uv error */ int flags; uint16_t restarts; /* keep the number of times this module has been diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index 1916372c..65760b31 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -229,6 +229,7 @@ static inline int val__set_to_arr(ti_val_t ** v, ti_varr_t * varr, ex_t * e) static inline int val__member_to_arr(ti_val_t ** v, ti_varr_t * varr, ex_t * e); static inline int val__future_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * UNUSED(e)); +static inline int val__module_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * UNUSED(e)); static inline int val__closure_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * e) { @@ -454,6 +455,15 @@ static ti_val_type_t ti_val_type_props[21] = { .get_type_str = val__future_type_str, .allowed_as_vtask_arg = false, }, + /* TI_VAL_MODULE */ + { + .destroy = (ti_val_destroy_cb) ti_module_destroy, + .to_str = val__no_to_str, + .to_arr_cb = val__module_to_arr, + .to_client_pk = (ti_val_to_client_pk_cb) val__module_to_client_pk, + .get_type_str = val__future_type_str, + .allowed_as_vtask_arg = false, + }, /* TI_VAL_TEMPLATE */ { .destroy = (ti_val_destroy_cb) ti_template_destroy, @@ -1119,6 +1129,11 @@ static inline int val__future_to_client_pk(ti_future_t * future, ti_vp_t * vp, i : msgpack_pack_nil(&vp->pk); } +static inline int val__module_to_client_pk(ti_module_t * UNUSED(module), ti_vp_t * vp, int UNUSED(deep), int UNUSED(flags)) +{ + return msgpack_pack_nil(&vp->pk); +} + static inline int val__member_to_client_pk(ti_member_t * member, ti_vp_t * vp, int deep, int flags) { return ti_val(member->val)->to_client_pk(member->val, vp, deep, flags); @@ -1289,6 +1304,13 @@ static inline int val__future_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex return 0; } +static inline int val__module_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * UNUSED(e)) +{ + ti_val_unsafe_drop(*v); + *v = (ti_val_t *) ti_nil_get(); + return 0; +} + /* * does not increment `*v` reference counter but the value might change to * a (new) tuple pointer. diff --git a/inc/ti/val.t.h b/inc/ti/val.t.h index 1d2a3b9d..56e07c01 100644 --- a/inc/ti/val.t.h +++ b/inc/ti/val.t.h @@ -66,6 +66,7 @@ typedef enum TI_VAL_MPDATA, /* msgpack data */ TI_VAL_CLOSURE, TI_VAL_FUTURE, /* future */ + TI_VAL_MODULE, /* module */ TI_VAL_TEMPLATE, /* template to generate TI_VAL_STR note that a template is never stored like a value, rather it may build from either a query or a stored From 9791cd1a0f19b85581f2a4766f8f9da1cb8ca6c2 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 18 Mar 2024 16:29:22 +0100 Subject: [PATCH 2/6] work on module type --- inc/ti/fn/fnclosure.h | 1 + 1 file changed, 1 insertion(+) diff --git a/inc/ti/fn/fnclosure.h b/inc/ti/fn/fnclosure.h index 1367e336..c66f4c67 100644 --- a/inc/ti/fn/fnclosure.h +++ b/inc/ti/fn/fnclosure.h @@ -63,6 +63,7 @@ static int do__f_closure_new(ti_query_t * query, cleri_node_t * nd, ex_t * e) case TI_VAL_MEMBER: case TI_VAL_MPDATA: case TI_VAL_FUTURE: + case TI_VAL_MODULE: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_CLOSURE_S"`", ti_val_str(query->rval)); From ee97014f6cc404db55a2d95d96ecc69e790983cc Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 18 Mar 2024 16:37:03 +0100 Subject: [PATCH 3/6] work on module type --- inc/ti/val.inline.h | 7 +++++-- inc/ti/val.t.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index 65760b31..66addba3 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -117,7 +117,10 @@ static inline const char * val__future_type_str(ti_val_t * UNUSED(val)) { return TI_VAL_FUTURE_S; } - +static inline const char * val__module_type_str(ti_val_t * UNUSED(val)) +{ + return TI_VAL_MODULE_S; +} static inline int val__nil_to_client_pk(ti_val_t * UNUSED(v), ti_vp_t * vp, int UNUSED(d), int UNUSED(f)) { return msgpack_pack_nil(&vp->pk); @@ -461,7 +464,7 @@ static ti_val_type_t ti_val_type_props[21] = { .to_str = val__no_to_str, .to_arr_cb = val__module_to_arr, .to_client_pk = (ti_val_to_client_pk_cb) val__module_to_client_pk, - .get_type_str = val__future_type_str, + .get_type_str = val__module_type_str, .allowed_as_vtask_arg = false, }, /* TI_VAL_TEMPLATE */ diff --git a/inc/ti/val.t.h b/inc/ti/val.t.h index 56e07c01..5a14e625 100644 --- a/inc/ti/val.t.h +++ b/inc/ti/val.t.h @@ -24,6 +24,7 @@ #define TI_VAL_DATETIME_S "datetime" #define TI_VAL_TIMEVAL_S "timeval" #define TI_VAL_FUTURE_S "future" +#define TI_VAL_MODULE_S "module" #define TI_VAL_TASK_S "task" #define TI_KIND_S_INSTANCE "." /* Internally, New typed thing */ From fccf14b1feeeb5bab2cbc424934a5bd4e968595e Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 18 Mar 2024 18:11:40 +0100 Subject: [PATCH 4/6] No future with Id arguments --- inc/ti/thing.h | 1 + inc/ti/val.h | 1 + inc/ti/version.h | 4 ++-- itest/test_future.py | 11 ++++++++++ src/ti/query.c | 7 ++++++ src/ti/thing.c | 45 ++++++++++++++++++++++++++++++++++++++ src/ti/val.c | 51 ++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 116 insertions(+), 4 deletions(-) diff --git a/inc/ti/thing.h b/inc/ti/thing.h index 83f5db0d..c99f5c28 100644 --- a/inc/ti/thing.h +++ b/inc/ti/thing.h @@ -88,6 +88,7 @@ int ti_thing_get_by_raw_e( ti_raw_t * r, ex_t * e); int ti_thing_gen_id(ti_thing_t * thing); +_Bool ti_thing_has_id(ti_thing_t * thing); int ti_thing__to_client_pk( ti_thing_t * thing, ti_vp_t * vp, diff --git a/inc/ti/val.h b/inc/ti/val.h index 46b6f256..ddf510bd 100644 --- a/inc/ti/val.h +++ b/inc/ti/val.h @@ -68,6 +68,7 @@ int ti_val_convert_to_set(ti_val_t ** val, ex_t * e); _Bool ti_val_as_bool(ti_val_t * val); size_t ti_val_get_len(ti_val_t * val); int ti_val_gen_ids(ti_val_t * val); +_Bool ti_val_has_ids(ti_val_t * val); size_t ti_val_alloc_size(ti_val_t * val); ti_val_t * ti_val_strv(ti_val_t * val); int ti_val_copy(ti_val_t ** val, ti_thing_t * parent, void * key, uint8_t deep); diff --git a/inc/ti/version.h b/inc/ti/version.h index e26ff7b6..f4004962 100644 --- a/inc/ti/version.h +++ b/inc/ti/version.h @@ -6,7 +6,7 @@ #define TI_VERSION_MAJOR 1 #define TI_VERSION_MINOR 5 -#define TI_VERSION_PATCH 1 +#define TI_VERSION_PATCH 2 /* The syntax version is used to test compatibility with functions * using the `ti_nodes_check_syntax()` function */ @@ -25,7 +25,7 @@ * "-rc0" * "" */ -#define TI_VERSION_PRE_RELEASE "" +#define TI_VERSION_PRE_RELEASE "-alpha0" #define TI_MAINTAINER \ "Jeroen van der Heijden " diff --git a/itest/test_future.py b/itest/test_future.py index ce49b9c6..efd8f896 100755 --- a/itest/test_future.py +++ b/itest/test_future.py @@ -245,5 +245,16 @@ async def test_future_arguments(self, client): future(|a, b| a + b); """) + async def test_no_ids(self, client): + with self.assertRaisesRegex( + OperationError, + 'context does not allow arguments which are stored by Id'): + await client.query("""//ti + .t = t = {name: 'iris'}; + future(|t| { + t.name = 'Iris'; + }); + """) + if __name__ == '__main__': run_test(TestFuture()) diff --git a/src/ti/query.c b/src/ti/query.c index 4c409889..78cb8360 100644 --- a/src/ti/query.c +++ b/src/ti/query.c @@ -793,6 +793,13 @@ static void query__then(ti_query_t * query, ex_t * e) if (ti_query_wse(query)) { + if (ti_val_has_ids(query->with.future->rval)) + { + ex_set(e, EX_OPERATION, + "context does not allow arguments which are stored by Id"); + goto finish; + } + access_ = ti_query_access(query); assert(access_); diff --git a/src/ti/thing.c b/src/ti/thing.c index db4c56e2..4bcf31b0 100644 --- a/src/ti/thing.c +++ b/src/ti/thing.c @@ -1157,6 +1157,11 @@ static inline int thing__gen_id_i_cb(ti_item_t * item, void * UNUSED(arg)) return ti_val_gen_ids(item->val); } +static inline int thing__has_id_i_cb(ti_item_t * item, void * UNUSED(arg)) +{ + return ti_val_has_ids(item->val); +} + int ti_thing_gen_id(ti_thing_t * thing) { assert(!thing->id); @@ -1192,6 +1197,46 @@ int ti_thing_gen_id(ti_thing_t * thing) return 0; } +_Bool ti_thing_has_id(ti_thing_t * thing) +{ + if (thing->id) + return true; + if (thing->flags & TI_VFLAG_LOCK) + return false; + + thing->flags |= TI_VFLAG_LOCK; + + if (ti_thing_is_object(thing)) + { + if (ti_thing_is_dict(thing)) + { + if (smap_values( + thing->items.smap, + (smap_val_cb) thing__has_id_i_cb, + NULL)) + goto ret_true; + goto ret_false; + } + + for (vec_each(thing->items.vec, ti_prop_t, prop)) + if (ti_val_has_ids(prop->val)) + goto ret_true; + goto ret_false; + } + + /* type */ + for (vec_each(thing->items.vec, ti_val_t, val)) + if (ti_val_has_ids(val)) + goto ret_true; + +ret_false: + thing->flags &= ~TI_VFLAG_LOCK; + return false; +ret_true: + thing->flags &= ~TI_VFLAG_LOCK; + return true; +} + void ti_thing_t_to_object(ti_thing_t * thing) { assert(!ti_thing_is_object(thing)); diff --git a/src/ti/val.c b/src/ti/val.c index 9fd264ce..4613438e 100644 --- a/src/ti/val.c +++ b/src/ti/val.c @@ -1410,11 +1410,16 @@ size_t ti_val_get_len(ti_val_t * val) return 0; } -static inline int val__walk_set(ti_thing_t * thing, void * UNUSED(_)) +static inline int val__walk_gen_id_set(ti_thing_t * thing, void * UNUSED(_)) { return !thing->id && ti_thing_gen_id(thing); } +static inline int val__walk_has_id_set(ti_thing_t * thing, void * UNUSED(_)) +{ + return (int) ti_thing_has_id(thing); +} + /* * Must be called when, and only when generating a new `task`. New ID's must * also be present in a task so other nodes will consume the same ID's. @@ -1475,7 +1480,7 @@ int ti_val_gen_ids(ti_val_t * val) return -1; break; case TI_VAL_SET: - return imap_walk(VSET(val), (imap_cb) val__walk_set, NULL); + return imap_walk(VSET(val), (imap_cb) val__walk_gen_id_set, NULL); case TI_VAL_CLOSURE: case TI_VAL_ERROR: break; @@ -1486,6 +1491,48 @@ int ti_val_gen_ids(ti_val_t * val) return 0; } +_Bool ti_val_has_ids(ti_val_t * val) +{ + switch ((ti_val_enum) val->tp) + { + case TI_VAL_NIL: + case TI_VAL_INT: + case TI_VAL_FLOAT: + case TI_VAL_BOOL: + case TI_VAL_DATETIME: + case TI_VAL_MPDATA: + case TI_VAL_NAME: + case TI_VAL_STR: + case TI_VAL_BYTES: + case TI_VAL_REGEX: + return false; + case TI_VAL_TASK: + return ((ti_vtask_t *) val)->id != 0; + case TI_VAL_MEMBER: + return ((ti_member_t *) val)->tp == TI_ENUM_THING; + case TI_VAL_THING: + return ti_thing_has_id((ti_thing_t *) val); + case TI_VAL_WRAP: + return ti_thing_has_id(((ti_wrap_t *) val)->thing); + case TI_VAL_ROOM: + return ((ti_room_t *) val)->id != 0; + case TI_VAL_ARR: + for (vec_each(VARR(val), ti_val_t, v)) + if (ti_val_has_ids(v)) + return true; + return false; + case TI_VAL_SET: + return imap_walk(VSET(val), (imap_cb) val__walk_has_id_set, NULL); + case TI_VAL_CLOSURE: + case TI_VAL_ERROR: + case TI_VAL_FUTURE: + return false; + case TI_VAL_TEMPLATE: + assert(0); + } + return false; +} + size_t ti_val_alloc_size(ti_val_t * val) { switch ((ti_val_enum) val->tp) From 9c351a67a7bca86a3d096f9406135ced58f1fe8d Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Tue, 19 Mar 2024 15:12:36 +0100 Subject: [PATCH 5/6] Upd changelog --- CHANGELOG.md | 7 +++ inc/doc.h | 1 + inc/ti/fn/fn.h | 9 ++-- inc/ti/fn/fnismodule.h | 18 ++++++++ inc/ti/mod/expose.h | 5 +++ inc/ti/mod/expose.t.h | 11 +++-- inc/ti/val.inline.h | 11 ++++- inc/ti/version.h | 2 +- itest/test_advanced.py | 4 +- src/ti/do.c | 7 +-- src/ti/enum.c | 1 + src/ti/export.c | 1 + src/ti/field.c | 7 +-- src/ti/index.c | 1 + src/ti/mod/expose.c | 96 +++++++++++++++++++++++++++++++++++++++--- src/ti/mod/manifest.c | 40 ++++++++++++++++-- src/ti/module.c | 2 + src/ti/qbind.c | 60 +++++++++++++------------- src/ti/query.c | 1 + src/ti/thing.c | 2 + src/ti/val.c | 32 +++++++++++--- src/ti/varr.c | 2 + src/ti/wrap.c | 2 + 23 files changed, 257 insertions(+), 65 deletions(-) create mode 100644 inc/ti/fn/fnismodule.h diff --git a/CHANGELOG.md b/CHANGELOG.md index f62e88c7..c1019aa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v1.5.2 + +* Restrict future arguments for `then()` or `else()` to objects without an Id. +* Module as type, no longer the workaround of exposing modules as futures. +* Added the `is_module()` function. +* Support ThingsDB code in exposed module functions. + # v1.5.1 * Added support for building on MacOS. diff --git a/inc/doc.h b/inc/doc.h index 87809f62..f1658e1e 100644 --- a/inc/doc.h +++ b/inc/doc.h @@ -50,6 +50,7 @@ #define DOC_IS_INF DOC_SEE("collection-api/is/is_inf") #define DOC_IS_INT DOC_SEE("collection-api/is/is_int") #define DOC_IS_LIST DOC_SEE("collection-api/is/is_list") +#define DOC_IS_MODULE DOC_SEE("collection-api/is/is_module") #define DOC_IS_MPDATA DOC_SEE("collection-api/is/is_mpdata") #define DOC_IS_NAN DOC_SEE("collection-api/is/is_nan") #define DOC_IS_NIL DOC_SEE("collection-api/is/is_nil") diff --git a/inc/ti/fn/fn.h b/inc/ti/fn/fn.h index 82759948..e3c59f6b 100644 --- a/inc/ti/fn/fn.h +++ b/inc/ti/fn/fn.h @@ -649,12 +649,13 @@ static int fn_call_f_try_n( cleri_node_t * nd, ex_t * e) { - ti_future_t * future = (ti_future_t *) query->rval; - ti_module_t * module = future->module; + ti_module_t * module = (ti_module_t *) query->rval; ti_mod_expose_t * expose = ti_mod_expose_by_strn(module, name, n); if (expose) - return ti_mod_expose_call(expose, query, nd, e); + return expose->closure + ? ti_mod_closure_call(expose, query, nd, e) + : ti_mod_expose_call(expose, query, nd, e); ex_set(e, EX_LOOKUP_ERROR, "module `%s` has no function `%.*s`", @@ -708,7 +709,7 @@ static int fn_call_try_n( if (ti_val_is_wrap(query->rval)) return fn_call_w_try_n(name, n, query, nd, e); - if (ti_val_is_future(query->rval)) + if (ti_val_is_module(query->rval)) return fn_call_f_try_n(name, n, query, nd, e); if (ti_val_is_member(query->rval)) diff --git a/inc/ti/fn/fnismodule.h b/inc/ti/fn/fnismodule.h new file mode 100644 index 00000000..b223dd7d --- /dev/null +++ b/inc/ti/fn/fnismodule.h @@ -0,0 +1,18 @@ +#include + +static int do__f_is_module(ti_query_t * query, cleri_node_t * nd, ex_t * e) +{ + const int nargs = fn_get_nargs(nd); + _Bool is_module; + + if (fn_nargs("is_module", DOC_IS_MODULE, 1, nargs, e) || + ti_do_statement(query, nd->children, e)) + return e->nr; + + is_module = ti_val_is_module(query->rval); + + ti_val_unsafe_drop(query->rval); + query->rval = (ti_val_t *) ti_vbool_get(is_module); + + return 0; +} diff --git a/inc/ti/mod/expose.h b/inc/ti/mod/expose.h index baab591a..26e4a15f 100644 --- a/inc/ti/mod/expose.h +++ b/inc/ti/mod/expose.h @@ -14,6 +14,11 @@ ti_mod_expose_t * ti_mod_expose_create(void); void ti_mod_expose_destroy(ti_mod_expose_t * expose); +int ti_mod_closure_call( + ti_mod_expose_t * expose, + ti_query_t * query, + cleri_node_t * nd, + ex_t * e); int ti_mod_expose_call( ti_mod_expose_t * expose, ti_query_t * query, diff --git a/inc/ti/mod/expose.t.h b/inc/ti/mod/expose.t.h index 8facd749..ba1cade6 100644 --- a/inc/ti/mod/expose.t.h +++ b/inc/ti/mod/expose.t.h @@ -9,14 +9,17 @@ typedef struct ti_mod_expose_s ti_mod_expose_t; #include +#include struct ti_mod_expose_s { - uint8_t * deep; /* NULL or 0..127 */ + uint8_t * deep; /* NULL or 0..127 */ _Bool * load; /* NULL or true/false */ - char * doc; /* NULL or string */ - vec_t * argmap; /* ti_item_t */ - vec_t * defaults; /* ti_item_t */ + char * doc; /* NULL or string */ + vec_t * argmap; /* ti_item_t */ + vec_t * defaults; /* ti_item_t */ + ti_closure_t * closure; /* closure */ + ti_raw_t * def; /* closure definition */ }; #endif /* TI_MOD_EXPOSE_T_H_ */ diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index 66addba3..83c29c7d 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -186,6 +187,7 @@ static inline int val__closure_to_client_pk(ti_val_t * val, ti_vp_t * vp, int UN return ti_closure_to_client_pk((ti_closure_t *) val, &vp->pk); } static inline int val__future_to_client_pk(ti_future_t * future, ti_vp_t * vp, int deep, int flags); +static inline int val__module_to_client_pk(ti_module_t * UNUSED(module), ti_vp_t * vp, int UNUSED(deep), int UNUSED(flags)); static inline int val__member_to_client_pk(ti_member_t * member, ti_vp_t * vp, int deep, int flags); static inline int val__member_to_store_pk(ti_member_t * member, msgpack_packer * pk); static inline int val__varr_to_client_pk(ti_varr_t * varr, ti_vp_t * vp, int deep, int flags); @@ -258,7 +260,7 @@ typedef struct } ti_val_type_t; -static ti_val_type_t ti_val_type_props[21] = { +static ti_val_type_t ti_val_type_props[22] = { /* TI_VAL_NIL */ { .destroy = (ti_val_destroy_cb) free, @@ -764,6 +766,11 @@ static inline _Bool ti_val_is_future(ti_val_t * val) return val->tp == TI_VAL_FUTURE; } +static inline _Bool ti_val_is_module(ti_val_t * val) +{ + return val->tp == TI_VAL_MODULE; +} + static inline _Bool ti_val_overflow_cast(double d) { return !(d >= -VAL__CAST_MAX && d < VAL__CAST_MAX); @@ -1030,6 +1037,7 @@ static inline void ti_val_attach( case TI_VAL_MEMBER: case TI_VAL_CLOSURE: case TI_VAL_FUTURE: + case TI_VAL_MODULE: return; case TI_VAL_ARR: ((ti_varr_t *) val)->parent = parent; @@ -1101,6 +1109,7 @@ static inline int ti_val_make_assignable( case TI_VAL_CLOSURE: return ti_closure_unbound((ti_closure_t *) *val, e); case TI_VAL_FUTURE: + case TI_VAL_MODULE: ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; diff --git a/inc/ti/version.h b/inc/ti/version.h index f4004962..b1af77d1 100644 --- a/inc/ti/version.h +++ b/inc/ti/version.h @@ -25,7 +25,7 @@ * "-rc0" * "" */ -#define TI_VERSION_PRE_RELEASE "-alpha0" +#define TI_VERSION_PRE_RELEASE "-alpha1" #define TI_MAINTAINER \ "Jeroen van der Heijden " diff --git a/itest/test_advanced.py b/itest/test_advanced.py index 4bc0dfac..f05777d2 100755 --- a/itest/test_advanced.py +++ b/itest/test_advanced.py @@ -1822,7 +1822,7 @@ async def test_future_to_type(self, client): with self.assertRaisesRegex( TypeError, r'mismatch in type `A`; property `x` allows `any` type ' - r"with the exception of the `future` type"): + r"with the exception of the `future` and `module` type"): await client.query("""//ti A{ x: future(||nil) @@ -2504,7 +2504,7 @@ async def test_future_name(self, client): with self.assertRaisesRegex( LookupError, - r'module `async` has no function `id`'): + r'type `future` has no function `id`'): await client.query(r"""//ti user = add_user(); user.id(); """) diff --git a/src/ti/do.c b/src/ti/do.c index 294fccb6..ed9ac355 100644 --- a/src/ti/do.c +++ b/src/ti/do.c @@ -1571,11 +1571,8 @@ static inline int do__var(ti_query_t * query, cleri_node_t * nd, ex_t * e) return e->nr; } - query->rval = \ - (ti_val_t *) ti_future_create(query, module, 0, 1, false); - - if (!query->rval) - ex_set_mem(e); + query->rval = (ti_val_t *) module; + ti_incref(module); return e->nr; } diff --git a/src/ti/enum.c b/src/ti/enum.c index 9854e12b..ffa25725 100644 --- a/src/ti/enum.c +++ b/src/ti/enum.c @@ -640,6 +640,7 @@ ti_member_t * ti_enum_member_by_val_e( case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_TEMPLATE: break; diff --git a/src/ti/export.c b/src/ti/export.c index 498e9bc9..8b8b2940 100644 --- a/src/ti/export.c +++ b/src/ti/export.c @@ -181,6 +181,7 @@ static int export__set_enum_cb(ti_enum_t * enum_, ti_fmt_t * fmt) case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_TEMPLATE: assert(0); break; diff --git a/src/ti/field.c b/src/ti/field.c index 9c2e2e1b..d93066fc 100644 --- a/src/ti/field.c +++ b/src/ti/field.c @@ -1679,7 +1679,8 @@ int ti_field_make_assignable( case TI_VAL_TEMPLATE: break; case TI_VAL_FUTURE: - goto future_error; + case TI_VAL_MODULE: + goto future_module_error; } return 0; case TI_SPEC_OBJECT: @@ -1851,11 +1852,11 @@ int ti_field_make_assignable( goto type_error; -future_error: +future_module_error: ex_set(e, EX_TYPE_ERROR, "mismatch in type `%s`; " "property `%s` allows `any` type with the exception " - "of the `future` type", + "of the `future` and `module` type", field->type->name, field->name->str); return e->nr; diff --git a/src/ti/index.c b/src/ti/index.c index e7c6e3d8..712f4592 100644 --- a/src/ti/index.c +++ b/src/ti/index.c @@ -674,6 +674,7 @@ int ti_index(ti_query_t * query, cleri_node_t * nd, ex_t * e) case TI_VAL_MPDATA: case TI_VAL_CLOSURE: case TI_VAL_FUTURE: + case TI_VAL_MODULE: if (do_slice) goto slice_error; goto index_error; diff --git a/src/ti/mod/expose.c b/src/ti/mod/expose.c index 3ba3adcd..2d67215b 100644 --- a/src/ti/mod/expose.c +++ b/src/ti/mod/expose.c @@ -28,11 +28,73 @@ void ti_mod_expose_destroy(ti_mod_expose_t * expose) free(expose->deep); free(expose->load); free(expose->doc); + ti_val_drop((ti_val_t *) expose->def); + ti_val_drop((ti_val_t *) expose->closure); vec_destroy(expose->argmap, (vec_destroy_cb) expose__item_destroy); vec_destroy(expose->defaults, (vec_destroy_cb) expose__item_destroy); free(expose); } +int ti_mod_closure_call( + ti_mod_expose_t * expose, + ti_query_t * query, + cleri_node_t * nd, + ex_t * e) +{ + cleri_node_t * child = nd->children; /* first in argument list */ + ti_closure_t * closure = expose->closure; + vec_t * args = NULL; + uint32_t n = closure->vars->n; + ti_module_t * module = (ti_module_t *) query->rval; + + ti_incref(expose->closure); + + query->rval = NULL; + + if (n) + { + args = vec_new(n--); + if (!args) + { + ex_set_mem(e); + goto fail0; + } + + VEC_push(args, module); + ti_incref(module); + + while (child && n) + { + --n; // outside `while` so we do not go below zero + + if (ti_do_statement(query, child, e)) + goto fail1; + + VEC_push(args, query->rval); + query->rval = NULL; + + if (!child->next) + break; + + child = child->next->next; + } + + while (n--) + VEC_push(args, ti_nil_get()); + } + + (void) ti_closure_call(closure, query, args, e); + +fail1: + vec_destroy(args, (vec_destroy_cb) ti_val_unsafe_drop); + +fail0: + ti_val_unsafe_drop((ti_val_t *) closure); + ti_val_unsafe_drop((ti_val_t *) module); + + return e->nr; +} + int ti_mod_expose_call( ti_mod_expose_t * expose, ti_query_t * query, @@ -40,10 +102,10 @@ int ti_mod_expose_call( ex_t * e) { unsigned int nargs = (unsigned int) fn_get_nargs(nd); - ti_future_t * future = (ti_future_t *) query->rval; + ti_module_t * module = (ti_module_t *) query->rval; cleri_node_t * child = nd->children; - ti_module_t * module = future->module; size_t defaults_n = expose->defaults ? expose->defaults->n : 0; + ti_future_t * future; ti_thing_t * thing; ti_name_t * deep_name = (ti_name_t *) ti_val_borrow_deep_name(); ti_name_t * load_name = (ti_name_t *) ti_val_borrow_load_name(); @@ -58,6 +120,14 @@ int ti_mod_expose_call( return e->nr; } + future = ti_future_create(query, module, 0, 1, false); + if (!future) + { + ex_set_mem(e); + return e->nr; + } + + ti_decref(module); query->rval = NULL; /* @@ -262,16 +332,20 @@ int ti_mod_expose_info_to_vp( ti_vp_t * vp) { msgpack_packer * pk = &vp->pk; - size_t defaults_n = (expose->defaults ? expose->defaults->n : 0) + \ - !!expose->deep + \ + size_t defaults_n = (expose->defaults ? expose->defaults->n : 0) +\ + !!expose->deep +\ !!expose->load; - size_t sz = !!expose->doc + !!defaults_n + !!expose->argmap; + size_t sz = !!(expose->doc && *expose->doc) +\ + !!defaults_n +\ + !!expose->argmap +\ + !!expose->def +\ + !!expose->closure; if (mp_pack_strn(pk, key, n) || msgpack_pack_map(pk, sz)) return -1; - if (expose->doc && ( + if (expose->doc && *expose->doc && ( mp_pack_str(pk, "doc") || mp_pack_str(pk, expose->doc))) return -1; @@ -310,5 +384,15 @@ int ti_mod_expose_info_to_vp( return -1; } + if (expose->def && ( + mp_pack_str(pk, "definition") || + mp_pack_strn(pk, expose->def->data, expose->def->n))) + return -1; + + if (expose->closure && ( + mp_pack_str(pk, "with_side_effects") || + mp_pack_bool(pk, expose->closure->flags & TI_CLOSURE_FLAG_WSE))) + return -1; + return 0; } diff --git a/src/ti/mod/manifest.c b/src/ti/mod/manifest.c index 026243b5..8a092c72 100644 --- a/src/ti/mod/manifest.c +++ b/src/ti/mod/manifest.c @@ -1,4 +1,3 @@ - /* * ti/mod/manifest.c */ @@ -635,7 +634,36 @@ static int manifest__json_string( case MF__INCLUDES_NO_OSARCH: return manifest__set_mode(ctx, MF__INCLUDES_MAP); case MF__EXPOSES: return manifest__err_exposes(ctx, TI_NSTR); - case MF__X: return manifest__err_x(ctx, TI_NSTR); + case MF__X: + { + ex_t e = {0}; + ti_raw_t * doc; + ti_mod_expose_t * expose = ctx->data; + ti_qbind_t syntax = { + .immutable_n = 0, + .flags = TI_QBIND_FLAG_COLLECTION|TI_QBIND_FLAG_THINGSDB, + }; + + expose->closure = ti_closure_from_strn( + &syntax, + (const char *) s, + n, + &e); + if (!expose->closure) + return manifest__set_err(ctx, + "exposing string is not a closure: %s", e.msg); + + /* both doc and the definition are none critical, so no error checking + * is required here; */ + expose->def = ti_closure_def(expose->closure); + doc = ti_closure_doc(expose->closure); + if (doc) + { + expose->doc = strndup((const char *) doc->data, doc->n); + ti_val_unsafe_drop((ti_val_t *) doc); + } + return manifest__set_mode(ctx, MF__EXPOSES_MAP); + } case MF__X_DOC: { ti_mod_expose_t * expose = ctx->data; @@ -832,6 +860,12 @@ static int manifest__json_map_key( case MF__EXPOSES_MAP: { ti_mod_expose_t * expose = ti_mod_expose_create(); + + if (!ti_name_is_valid_strn((const char *) s, n)) + return manifest__set_err( + ctx, + "invalid expose function name in "TI_MANIFEST); + if (!expose || smap_addn(ctx->manifest->exposes, (const char *) s, n, expose)) return manifest__set_err( @@ -1061,7 +1095,7 @@ static void manifest__force_argmap(ti_mod_expose_t * expose) * leave empty argmap alone; */ ti_item_t * item; - if (expose->argmap) + if (expose->argmap || expose->closure) return; expose->argmap = vec_new(1); diff --git a/src/ti/module.c b/src/ti/module.c index a1aecf0d..e956f969 100644 --- a/src/ti/module.c +++ b/src/ti/module.c @@ -310,6 +310,7 @@ ti_module_t* ti_module_create( } module->ref = 1; + module->tp = TI_VAL_MODULE; module->status = TI_MODULE_STAT_NOT_INSTALLED; module->cb = (ti_module_cb) &module__cb; module->name = ti_names_get(name, name_n); @@ -1429,6 +1430,7 @@ static int module__info_to_vp(ti_module_t * module, ti_vp_t * vp, int flags) { char namebuf[TI_NAME_MAX]; smap_t * exposes = manifest->exposes; + if (mp_pack_str(pk, "exposes") || msgpack_pack_map(pk, exposes->n) || smap_items( diff --git a/src/ti/qbind.c b/src/ti/qbind.c index f102d4f7..7191c1ed 100644 --- a/src/ti/qbind.c +++ b/src/ti/qbind.c @@ -114,6 +114,7 @@ #include #include #include +#include #include #include #include @@ -295,11 +296,11 @@ static void qbind__statement(ti_qbind_t * qbind, cleri_node_t * nd); */ enum { - TOTAL_KEYWORDS = 270, + TOTAL_KEYWORDS = 271, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 17, - MIN_HASH_VALUE = 40, - MAX_HASH_VALUE = 692 + MIN_HASH_VALUE = 30, + MAX_HASH_VALUE = 664 }; /* @@ -311,32 +312,32 @@ static inline unsigned int qbind__hash( { static unsigned short asso_values[] = { - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 19, 19, - 16, 693, 16, 693, 16, 693, 18, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 16, 693, 21, 57, 74, - 28, 18, 96, 180, 179, 16, 17, 27, 18, 28, - 21, 23, 178, 56, 17, 16, 17, 74, 148, 144, - 187, 140, 37, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, - 693, 693, 693, 693, 693, 693 + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 11, 11, + 19, 665, 13, 665, 13, 665, 14, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 11, 665, 16, 40, 80, + 37, 13, 128, 264, 189, 11, 19, 167, 24, 55, + 16, 19, 102, 83, 12, 11, 12, 22, 205, 125, + 105, 255, 60, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 665, 665, + 665, 665, 665, 665, 665, 665 }; register unsigned int hval = n; @@ -587,6 +588,7 @@ qbind__fmap_t qbind__fn_mapping[TOTAL_KEYWORDS] = { {.name="is_inf", .fn=do__f_is_inf, ROOT_NE}, {.name="is_int", .fn=do__f_is_int, ROOT_NE}, {.name="is_list", .fn=do__f_is_list, ROOT_NE}, + {.name="is_module", .fn=do__f_is_module, ROOT_NE}, {.name="is_mpdata", .fn=do__f_is_mpdata, ROOT_NE}, {.name="is_nan", .fn=do__f_is_nan, ROOT_NE}, {.name="is_nil", .fn=do__f_is_nil, ROOT_NE}, diff --git a/src/ti/query.c b/src/ti/query.c index 78cb8360..8f6c3a68 100644 --- a/src/ti/query.c +++ b/src/ti/query.c @@ -1422,6 +1422,7 @@ static int query__get_things(ti_val_t * val, imap_t * imap) break; case TI_VAL_FUTURE: return VFUT(val) ? query__get_things(VFUT(val), imap) : 0; + case TI_VAL_MODULE: case TI_VAL_TEMPLATE: break; } diff --git a/src/ti/thing.c b/src/ti/thing.c index 4bcf31b0..788d0f63 100644 --- a/src/ti/thing.c +++ b/src/ti/thing.c @@ -454,6 +454,7 @@ int ti_thing_p_prop_add_assign( ti_incref(val); break; case TI_VAL_FUTURE: + case TI_VAL_MODULE: val = (ti_val_t *) ti_nil_get(); break; case TI_VAL_TEMPLATE: @@ -554,6 +555,7 @@ int ti_thing_i_item_add_assign( ti_incref(val); break; case TI_VAL_FUTURE: + case TI_VAL_MODULE: val = (ti_val_t *) ti_nil_get(); break; case TI_VAL_TEMPLATE: diff --git a/src/ti/val.c b/src/ti/val.c index 4613438e..1eead9de 100644 --- a/src/ti/val.c +++ b/src/ti/val.c @@ -55,6 +55,7 @@ static ti_val_t * val__sdatetime; static ti_val_t * val__serror; static ti_val_t * val__sfloat; static ti_val_t * val__sfuture; +static ti_val_t * val__smodule; static ti_val_t * val__sint; static ti_val_t * val__slist; static ti_val_t * val__smpdata; @@ -462,6 +463,7 @@ static int val__push(ti_varr_t * varr, ti_val_t * val, ex_t * e) varr->flags |= TI_VARR_FLAG_MHT; break; case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_TEMPLATE: assert(0); return e->nr; @@ -726,6 +728,7 @@ int ti_val_init_common(void) val__serror = (ti_val_t *) ti_str_from_str(TI_VAL_ERROR_S); val__sclosure = (ti_val_t *) ti_str_from_str(TI_VAL_CLOSURE_S); val__sfuture = (ti_val_t *) ti_str_from_str(TI_VAL_FUTURE_S); + val__smodule = (ti_val_t *) ti_str_from_str(TI_VAL_MODULE_S); val__slist = (ti_val_t *) ti_str_from_str(TI_VAL_LIST_S); val__stuple = (ti_val_t *) ti_str_from_str(TI_VAL_TUPLE_S); val__sset = (ti_val_t *) ti_str_from_str(TI_VAL_SET_S); @@ -777,7 +780,7 @@ int ti_val_init_common(void) !val__beautify_name || !val__parent_name || !val__parent_type_name || !val__key_name || !val__key_type_name || !val__flags_name || !val__data_name || !val__time_name || !val__re_email || - !val__re_url || !val__re_tel || !val__async_name) + !val__smodule || !val__re_url || !val__re_tel || !val__async_name) { return -1; } @@ -808,6 +811,7 @@ void ti_val_drop_common(void) ti_val_drop(val__serror); ti_val_drop(val__sclosure); ti_val_drop(val__sfuture); + ti_val_drop(val__smodule); ti_val_drop(val__slist); ti_val_drop(val__stuple); ti_val_drop(val__sset); @@ -1000,6 +1004,7 @@ int ti_val_convert_to_bytes(ti_val_t ** val, ex_t * e) case TI_VAL_SET: case TI_VAL_CLOSURE: case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_ERROR: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_BYTES_S"`", @@ -1038,6 +1043,7 @@ int ti_val_convert_to_int(ti_val_t ** val, ex_t * e) case TI_VAL_SET: case TI_VAL_CLOSURE: case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_MPDATA: case TI_VAL_BYTES: ex_set(e, EX_TYPE_ERROR, @@ -1133,6 +1139,7 @@ int ti_val_convert_to_float(ti_val_t ** val, ex_t * e) case TI_VAL_SET: case TI_VAL_CLOSURE: case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_MPDATA: case TI_VAL_BYTES: ex_set(e, EX_TYPE_ERROR, @@ -1214,6 +1221,12 @@ int ti_val_convert_to_array(ti_val_t ** val, ex_t * e) { switch((ti_val_enum) (*val)->tp) { + case TI_VAL_ARR: + break; + case TI_VAL_SET: + if (ti_vset_to_list((ti_vset_t **) val)) + ex_set_mem(e); + break; case TI_VAL_NIL: case TI_VAL_INT: case TI_VAL_FLOAT: @@ -1232,16 +1245,11 @@ int ti_val_convert_to_array(ti_val_t ** val, ex_t * e) case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_FUTURE: + case TI_VAL_MODULE: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_LIST_S"`", ti_val_str(*val)); break; - case TI_VAL_ARR: - break; - case TI_VAL_SET: - if (ti_vset_to_list((ti_vset_t **) val)) - ex_set_mem(e); - break; case TI_VAL_TEMPLATE: assert(0); } @@ -1269,6 +1277,7 @@ int ti_val_convert_to_set(ti_val_t ** val, ex_t * e) case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_FUTURE: + case TI_VAL_MODULE: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_SET_S"`", ti_val_str(*val)); @@ -1355,6 +1364,7 @@ _Bool ti_val_as_bool(ti_val_t * val) return ((ti_vtask_t *) val)->run_at; case TI_VAL_CLOSURE: case TI_VAL_FUTURE: + case TI_VAL_MODULE: return true; case TI_VAL_ERROR: return false; @@ -1404,6 +1414,7 @@ size_t ti_val_get_len(ti_val_t * val) case TI_VAL_MEMBER: return ti_val_get_len(VMEMBER(val)); case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_ERROR: break; } @@ -1485,6 +1496,7 @@ int ti_val_gen_ids(ti_val_t * val) case TI_VAL_ERROR: break; case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_TEMPLATE: assert(0); } @@ -1526,6 +1538,7 @@ _Bool ti_val_has_ids(ti_val_t * val) case TI_VAL_CLOSURE: case TI_VAL_ERROR: case TI_VAL_FUTURE: + case TI_VAL_MODULE: return false; case TI_VAL_TEMPLATE: assert(0); @@ -1566,6 +1579,8 @@ size_t ti_val_alloc_size(ti_val_t * val) return ti_val_alloc_size(VMEMBER(val)); case TI_VAL_FUTURE: return VFUT(val) ? ti_val_alloc_size(VFUT(val)) : 64; + case TI_VAL_MODULE: + return 64; case TI_VAL_TEMPLATE: assert(0); } @@ -1608,6 +1623,7 @@ ti_val_t * ti_val_strv(ti_val_t * val) case TI_VAL_MEMBER: return (ti_val_t *) ti_member_enum_get_rname((ti_member_t *) val); case TI_VAL_FUTURE: return ti_grab(val__sfuture); + case TI_VAL_MODULE: return ti_grab(val__smodule); case TI_VAL_TEMPLATE: assert(0); } @@ -1663,6 +1679,7 @@ int ti_val_copy(ti_val_t ** val, ti_thing_t * parent, void * key, uint8_t deep) return ti_closure_unbound((ti_closure_t * ) *val, &e); } case TI_VAL_FUTURE: + case TI_VAL_MODULE: ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; @@ -1721,6 +1738,7 @@ int ti_val_dup(ti_val_t ** val, ti_thing_t * parent, void * key, uint8_t deep) return ti_closure_unbound((ti_closure_t * ) *val, &e); } case TI_VAL_FUTURE: + case TI_VAL_MODULE: ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; diff --git a/src/ti/varr.c b/src/ti/varr.c index 6c425873..9776dee3 100644 --- a/src/ti/varr.c +++ b/src/ti/varr.c @@ -355,6 +355,7 @@ static int varr__copy(ti_val_t ** val, uint8_t deep) return -1; return 0; case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_SET: case TI_VAL_TEMPLATE: break; @@ -397,6 +398,7 @@ static int varr__dup(ti_val_t ** val, uint8_t deep) return -1; return 0; case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_SET: case TI_VAL_TEMPLATE: break; diff --git a/src/ti/wrap.c b/src/ti/wrap.c index 99dba3e3..ea7c5dec 100644 --- a/src/ti/wrap.c +++ b/src/ti/wrap.c @@ -179,6 +179,8 @@ static int wrap__field_val( deep, flags) : msgpack_pack_nil(&vp->pk); + case TI_VAL_MODULE: + return msgpack_pack_nil(&vp->pk); case TI_VAL_TEMPLATE: break; } From 43d53bcc9cba68d7476460f7401e323f15006f5a Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Tue, 19 Mar 2024 16:18:15 +0100 Subject: [PATCH 6/6] Upd tests --- itest/test_collection_functions.py | 8 ++++++++ itest/test_tasks.py | 21 ++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/itest/test_collection_functions.py b/itest/test_collection_functions.py index 9282c876..2c5425f5 100755 --- a/itest/test_collection_functions.py +++ b/itest/test_collection_functions.py @@ -2137,6 +2137,14 @@ async def test_is_future(self, client): self.assertFalse(await client.query('is_future( 42 );')) self.assertFalse(await client.query('is_future( nil );')) + async def test_is_module(self, client): + with self.assertRaisesRegex( + NumArgumentsError, + 'function `is_module` takes 1 argument but 0 were given'): + await client.query('is_module();') + + self.assertFalse(await client.query('is_module(future(nil));')) + async def test_is_inf(self, client): with self.assertRaisesRegex( NumArgumentsError, diff --git a/itest/test_tasks.py b/itest/test_tasks.py index 9d6f4a41..62304489 100755 --- a/itest/test_tasks.py +++ b/itest/test_tasks.py @@ -243,7 +243,7 @@ async def test_again_in(self, client): .x = 1; task(datetime(), |t| { if (.x >= 3) { - return; + return nil; }; .x += 1; t.again_in('seconds', 1); @@ -288,7 +288,7 @@ async def test_again_at(self, client): .x = 1; task(datetime(), |t| { if (.x >= 3) { - return; + return nil; }; .x += 1; t.again_at(datetime().move('seconds', 1)); @@ -302,18 +302,20 @@ async def test_task_with_future(self, client): .x = 1; task(datetime(), |t| { if (.x >= 3) { - return; + return nil; }; // no change id, yet... assert(is_nil(change_id())); - future(|t| { + future(|t_id| { + t = task(t_id); .x += 1; - future(|t| { + future(|t_id| { + t = task(t_id); t.again_in('seconds', 1); }); - }); + }, [t.id()]); }); """) await asyncio.sleep(num_nodes*5) @@ -323,14 +325,15 @@ async def test_task_with_future(self, client): .y = 1; task(datetime(), |t| { if (.y >= 3) { - return; + return nil; }; .y += 1; - future(|t| { + future(|t_id| { + t = task(t_id); t.again_in('seconds', 1); - }); + }, [t.id()]); }); """) await asyncio.sleep(num_nodes*5)