From 70e7f9ea06e9f7ddc482e0ecac53b37e7a50a339 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Fri, 7 Nov 2025 16:52:03 +0100 Subject: [PATCH 01/13] Work on ano type --- CHANGELOG.md | 5 ++ CMakeLists.txt | 1 + grammar/grammar.py | 3 + inc/doc.h | 1 + inc/langdef/langdef.h | 6 +- inc/ti/ano.h | 54 ++++++++++++++++ inc/ti/ano.t.h | 21 +++++++ inc/ti/do.h | 1 + inc/ti/fn/fn.h | 1 + inc/ti/fn/fnano.h | 23 +++++++ inc/ti/fn/fnclosure.h | 1 + inc/ti/fn/fnsearch.h | 1 + inc/ti/forloop.h | 1 + inc/ti/spec.t.h | 7 ++- inc/ti/type.h | 5 +- inc/ti/val.h | 2 +- inc/ti/val.inline.h | 35 ++++++++++- inc/ti/val.t.h | 2 + inc/util/mpack.h | 1 + src/langdef/langdef.c | 19 +++++- src/ti/ano.c | 141 ++++++++++++++++++++++++++++++++++++++++++ src/ti/async.c | 2 +- src/ti/condition.c | 6 +- src/ti/do.c | 55 +++++++++++++++- src/ti/enum.c | 1 + src/ti/export.c | 6 ++ src/ti/field.c | 26 ++++++-- src/ti/fmt.c | 5 ++ src/ti/index.c | 1 + src/ti/ncache.c | 22 ++++++- src/ti/qbind.c | 67 +++++++++++--------- src/ti/query.c | 1 + src/ti/spec.c | 97 ++++++++++++++++------------- src/ti/thing.c | 2 + src/ti/type.c | 68 ++++++++++---------- src/ti/val.c | 54 ++++++++++++++-- 36 files changed, 608 insertions(+), 136 deletions(-) create mode 100644 inc/ti/ano.h create mode 100644 inc/ti/ano.t.h create mode 100644 inc/ti/fn/fnano.h create mode 100644 src/ti/ano.c diff --git a/CHANGELOG.md b/CHANGELOG.md index b450b9cb..9d71e7f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v1.8.2-alpha0 + +* Allow converting `mpdata` to `bytes, issue #...TODO + + # v1.8.1 * Implemented formatting C-string checks and fixed typo, pr #426. diff --git a/CMakeLists.txt b/CMakeLists.txt index 2923ff8e..04ef5154 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,7 @@ set(SOURCES src/cleri/tokens.c src/cleri/version.c src/ti/access.c + src/ti/ano.c src/ti/api.c src/ti/archfile.c src/ti/archive.c diff --git a/grammar/grammar.py b/grammar/grammar.py index 72dccb80..2b5f6b6a 100644 --- a/grammar/grammar.py +++ b/grammar/grammar.py @@ -51,6 +51,7 @@ class LangDef(Grammar): x_preopr = Regex(r'(\s*~)*(\s*!|\s*[\-+](?=[^0-9]))*') x_ternary = Token('?') x_thing = Token('{') + x_ano = Token('&{') x_template = Token('`') template = Sequence( @@ -81,6 +82,7 @@ class LangDef(Grammar): chain = Ref() closure = Sequence(x_closure, List(var), '|', THIS) + t_ano = Sequence(x_ano, List(Sequence(name, ':', Optional(THIS))), '}') thing = Sequence(x_thing, List(Sequence(name, ':', Optional(THIS))), '}') array = Sequence(x_array, List(THIS), ']') @@ -184,6 +186,7 @@ class LangDef(Grammar): t_int, t_string, t_regex, + t_ano, # end immutable values template, var_opt_more, diff --git a/inc/doc.h b/inc/doc.h index e1469a1a..c185bd60 100644 --- a/inc/doc.h +++ b/inc/doc.h @@ -13,6 +13,7 @@ /* Collection API */ #define DOC_ALT_RAISE DOC_SEE("collection-api/alt_raise") +#define DOC_ANO DOC_SEE("collection-api/ano") #define DOC_ASSERT DOC_SEE("collection-api/assert") #define DOC_BASE64_DECODE DOC_SEE("collection-api/base64_decode") #define DOC_BASE64_ENCODE DOC_SEE("collection-api/base64_encode") diff --git a/inc/langdef/langdef.h b/inc/langdef/langdef.h index a37197b4..ea6a48b1 100644 --- a/inc/langdef/langdef.h +++ b/inc/langdef/langdef.h @@ -5,7 +5,7 @@ * should be used with the libcleri module. * * Source class: LangDef - * Created at: 2024-02-11 20:55:25 + * Created at: 2025-11-07 13:13:19 */ #ifndef CLERI_EXPORT_LANGDEF_H_ #define CLERI_EXPORT_LANGDEF_H_ @@ -13,6 +13,8 @@ #include cleri_grammar_t * compile_langdef(void); + +/* TODO: (COMPAT) For compatibility with < v1.5 (old syntax) */ cleri_grammar_t * compile_compat(void); enum cleri_grammar_ids { @@ -56,6 +58,7 @@ enum cleri_grammar_ids { CLERI_GID_STATEMENT, CLERI_GID_TEMPLATE, CLERI_GID_THING, + CLERI_GID_T_ANO, CLERI_GID_T_FALSE, CLERI_GID_T_FLOAT, CLERI_GID_T_INT, @@ -65,6 +68,7 @@ enum cleri_grammar_ids { CLERI_GID_T_TRUE, CLERI_GID_VAR, CLERI_GID_VAR_OPT_MORE, + CLERI_GID_X_ANO, CLERI_GID_X_ARRAY, CLERI_GID_X_ASSIGN, CLERI_GID_X_BLOCK, diff --git a/inc/ti/ano.h b/inc/ti/ano.h new file mode 100644 index 00000000..c89bfa31 --- /dev/null +++ b/inc/ti/ano.h @@ -0,0 +1,54 @@ +/* + * ti/ano.h + */ +#ifndef TI_ANO_H_ +#define TI_ANO_H_ + + +#include +#include +#include +#include +#include + +ti_ano_t * ti_ano_new(void); +int ti_ano_init( + ti_ano_t * ano, + ti_collection_t * collection, + ti_raw_t * spec_raw, + ex_t * e); +ti_ano_t * ti_ano_from_raw( + ti_collection_t * collection, + ti_raw_t * spec_raw, + ex_t * e); +ti_ano_t * ti_ano_create( + ti_collection_t * collection, + const unsigned char * bin, + size_t n, + ex_t * e); +void ti_ano_destroy(ti_ano_t * ano); + +static inline int ti_ano_to_client_pk( + ti_ano_t * ano, + msgpack_packer * pk) +{ + return mp_pack_append(pk, ano->spec_raw->data, ano->spec_raw->n); +} + +static inline _Bool ti_ano_uninitialized(ti_ano_t * ano) +{ + return !!ano->spec_raw; +} + +static inline int ti_ano_to_store_pk( + ti_ano_t * ano, + msgpack_packer * pk) +{ + return mp_pack_ext( + pk, + MPACK_EXT_ANO, + ano->spec_raw->data, + ano->spec_raw->n); +} + +#endif /* TI_ANO_H_ */ diff --git a/inc/ti/ano.t.h b/inc/ti/ano.t.h new file mode 100644 index 00000000..802ca207 --- /dev/null +++ b/inc/ti/ano.t.h @@ -0,0 +1,21 @@ +/* + * ti/ano.t.h + */ +#ifndef TI_ANO_T_H_ +#define TI_ANO_T_H_ + +typedef struct ti_ano_s ti_ano_t; + +#include +#include + +struct ti_ano_s +{ + uint32_t ref; + uint8_t tp; + int:24; + ti_raw_t * spec_raw; /* mpdata, in log use */ + ti_type_t * type; +}; + +#endif /* TI_ANO_T_H_ */ diff --git a/inc/ti/do.h b/inc/ti/do.h index 0d9c80cb..435091ca 100644 --- a/inc/ti/do.h +++ b/inc/ti/do.h @@ -41,6 +41,7 @@ int ti_do_prepare_for_loop(ti_query_t * query, cleri_node_t * vars_nd); int ti_do_init(void); void ti_do_drop(void); + static inline int ti_do_statement( ti_query_t * query, cleri_node_t * nd, diff --git a/inc/ti/fn/fn.h b/inc/ti/fn/fn.h index cbfb4ffd..48840740 100644 --- a/inc/ti/fn/fn.h +++ b/inc/ti/fn/fn.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/inc/ti/fn/fnano.h b/inc/ti/fn/fnano.h new file mode 100644 index 00000000..80b71ef4 --- /dev/null +++ b/inc/ti/fn/fnano.h @@ -0,0 +1,23 @@ +#include + +static int do__f_ano(ti_query_t * query, cleri_node_t * nd, ex_t * e) +{ + const int nargs = fn_get_nargs(nd); + ti_raw_t * spec_raw; + + if (fn_not_collection_scope("ano", query, e) || + fn_nargs("ano", DOC_ANO, 1, nargs, e) || + ti_do_statement(query, nd->children, e) || + fn_arg_thing("ano", DOC_ANO, 1, query->rval, e)) + return e->nr; + + spec_raw = ti_type_spec_raw_from_thing((ti_thing_t *) query->rval, e); + if (!spec_raw) + return e->nr; + + ti_val_unsafe_drop(query->rval); + query->rval = ti_ano_from_raw(nd->data, query->collection, spec_raw, e); + ti_val_unsafe_drop((ti_val_t *) spec_raw); + + return e->nr; +} diff --git a/inc/ti/fn/fnclosure.h b/inc/ti/fn/fnclosure.h index c66f4c67..a4f6b41d 100644 --- a/inc/ti/fn/fnclosure.h +++ b/inc/ti/fn/fnclosure.h @@ -64,6 +64,7 @@ static int do__f_closure_new(ti_query_t * query, cleri_node_t * nd, ex_t * e) case TI_VAL_MPDATA: case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_ANO: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_CLOSURE_S"`", ti_val_str(query->rval)); diff --git a/inc/ti/fn/fnsearch.h b/inc/ti/fn/fnsearch.h index 2973df25..48389127 100644 --- a/inc/ti/fn/fnsearch.h +++ b/inc/ti/fn/fnsearch.h @@ -205,6 +205,7 @@ static int do__search_thing( case TI_VAL_TEMPLATE: case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_ANO: return 0; } assert(0); diff --git a/inc/ti/forloop.h b/inc/ti/forloop.h index ace83a4c..24c347f1 100644 --- a/inc/ti/forloop.h +++ b/inc/ti/forloop.h @@ -61,6 +61,7 @@ static const ti_forloop_t ti_forloop_callbacks[22] = { 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_ANO */ ti_forloop_no_iter, /* TI_VAL_TEMPLATE */ }; diff --git a/inc/ti/spec.t.h b/inc/ti/spec.t.h index f05ecfeb..c5048c43 100644 --- a/inc/ti/spec.t.h +++ b/inc/ti/spec.t.h @@ -36,9 +36,10 @@ typedef enum TI_SPEC_ERROR, /* `error` */ TI_SPEC_ROOM, /* `room` */ TI_SPEC_TASK, /* `task` */ - TI_SPEC_EMAIL, /* `email */ - TI_SPEC_URL, /* `url ` */ - TI_SPEC_TEL, /* `tel ` */ + TI_SPEC_EMAIL, /* `email` */ + TI_SPEC_URL, /* `url` */ + TI_SPEC_TEL, /* `tel` */ + TI_SPEC_ANO, /* `ano` */ TI_SPEC_REMATCH=0x5000, /* `/.../` */ TI_SPEC_INT_RANGE, /* `int<:> */ diff --git a/inc/ti/type.h b/inc/ti/type.h index a7ed41fc..57c7684f 100644 --- a/inc/ti/type.h +++ b/inc/ti/type.h @@ -28,13 +28,13 @@ ti_type_t * ti_type_create( size_t name_n, uint64_t created_at, uint64_t modified_at); -ti_type_t * ti_type_create_unnamed( +ti_type_t * ti_type_create_anonymous( ti_types_t * types, ti_raw_t * name, uint8_t flags); imap_t * ti_type_collect_things(ti_query_t * query, ti_type_t * type); void ti_type_drop(ti_type_t * type); -void ti_type_drop_unnamed(ti_type_t * type); +void ti_type_drop_anonymous(ti_type_t * type); void ti_type_del(ti_type_t * type, vec_t * vars); void ti_type_destroy(ti_type_t * type); void ti_type_map_cleanup(ti_type_t * type); @@ -77,6 +77,7 @@ int ti_type_methods_info_to_pk( int ti_type_required_by_non_wpo(ti_type_t * type, ex_t * e); int ti_type_requires_wpo(ti_type_t * type, ex_t * e); int ti_type_rename(ti_type_t * type, ti_raw_t * nname); +ti_raw_t * ti_type_spec_raw_from_thing(ti_thing_t * thing, ex_t * e); ti_raw_t * ti__type_nested_from_val(ti_type_t * type, ti_val_t * val, ex_t * e); static inline int ti_type_use(ti_type_t * type, ex_t * e) diff --git a/inc/ti/val.h b/inc/ti/val.h index ff808acf..37bee9e8 100644 --- a/inc/ti/val.h +++ b/inc/ti/val.h @@ -31,7 +31,7 @@ extern ti_val_t * val__parent_name; extern ti_val_t * val__parent_type_name; extern ti_val_t * val__key_name; extern ti_val_t * val__key_type_name; -extern ti_val_t * val__unnamed_name; +extern ti_val_t * val__anonymous_name; /* string */ extern ti_val_t * val__sany; diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index b1b00ccd..51b9a80a 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -173,6 +173,10 @@ static inline const char * val__module_type_str(ti_val_t * UNUSED(val)) { return TI_VAL_MODULE_S; } +static inline const char * val__ano_type_str(ti_val_t * UNUSED(val)) +{ + return TI_VAL_ANO_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); @@ -229,6 +233,10 @@ static inline int val__error_to_client_pk(ti_val_t * val, ti_vp_t * vp, int UNUS { return ti_verror_to_client_pk((ti_verror_t *) val, &vp->pk); } +static inline int val__ano_to_client_pk(ti_val_t * val, ti_vp_t * vp, int UNUSED(d), int UNUSED(f)) +{ + return ti_verror_to_client_pk((ti_verror_t *) val, &vp->pk); +} static inline int val__mpdata_to_client_pk(ti_val_t * val, ti_vp_t * vp, int UNUSED(d), int UNUSED(f)) { return ti_raw_mpdata_to_client_pk((ti_raw_t *) val, &vp->pk); @@ -543,6 +551,17 @@ static ti_val_type_t ti_val_type_props[22] = { .as_bool = val__as_bool_true, .allowed_as_vtask_arg = false, }, + /* TI_VAL_ANO */ + { + .destroy = (ti_val_destroy_cb) ti_ano_destroy, + .to_str = ti_val_ano_to_str, + .to_arr_cb = val__to_arr_cb, + .to_client_pk = val__ano_to_client_pk, + .to_store_pk = (ti_val_to_store_pk_cb) ti_ano_to_store_pk, + .get_type_str = val__ano_type_str, + .as_bool = val__as_bool_true, + .allowed_as_vtask_arg = false, + }, /* TI_VAL_TEMPLATE */ { .destroy = (ti_val_destroy_cb) ti_template_destroy, @@ -855,6 +874,11 @@ static inline _Bool ti_val_is_module(ti_val_t * val) return val->tp == TI_VAL_MODULE; } +static inline _Bool ti_val_is_ano(ti_val_t * val) +{ + return val->tp == TI_VAL_ANO; +} + static inline _Bool ti_val_overflow_cast(double d) { return !(d >= -VAL__CAST_MAX && d < VAL__CAST_MAX); @@ -914,9 +938,9 @@ static inline ti_val_t * ti_val_gmt_offset_name(void) return ti_incref(val__gmt_offset_name), val__gmt_offset_name; } -static inline ti_val_t * ti_val_unnamed_name(void) +static inline ti_val_t * ti_val_anonymous_name(void) { - return ti_incref(val__unnamed_name), val__unnamed_name; + return ti_incref(val__anonymous_name), val__anonymous_name; } static inline ti_val_t * ti_val_borrow_async_name(void) @@ -1127,6 +1151,7 @@ static inline void ti_val_attach( case TI_VAL_CLOSURE: case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_ANO: return; case TI_VAL_ARR: ((ti_varr_t *) val)->parent = parent; @@ -1202,6 +1227,8 @@ static inline int ti_val_make_assignable( ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; + case TI_VAL_ANO: + return 0; case TI_VAL_TEMPLATE: break; } @@ -1314,9 +1341,10 @@ static inline _Bool val__spec_enum_eq_to_val(uint16_t spec, ti_val_t * val) * TI_SPEC_EMAIL, * TI_SPEC_URL, * TI_SPEC_TEL, + * TI_SPEC_ANO, */ -static ti_val_spec_t ti_val_spec_map[24] = { +static ti_val_spec_t ti_val_spec_map[25] = { {.is_spec=ti_val_is_thing}, {.is_spec=ti_val_is_raw}, {.is_spec=ti_val_is_str}, @@ -1341,6 +1369,7 @@ static ti_val_spec_t ti_val_spec_map[24] = { {.is_spec=ti_val_is_email}, {.is_spec=ti_val_is_url}, {.is_spec=ti_val_is_tel}, + {.is_spec=ti_val_is_ano}, }; static inline _Bool ti_val_is_spec(ti_val_t * val, uint16_t spec) diff --git a/inc/ti/val.t.h b/inc/ti/val.t.h index de8bebae..fe25a303 100644 --- a/inc/ti/val.t.h +++ b/inc/ti/val.t.h @@ -26,6 +26,7 @@ #define TI_VAL_FUTURE_S "future" #define TI_VAL_MODULE_S "module" #define TI_VAL_TASK_S "task" +#define TI_VAL_ANO_S "anonymous" #define TI_KIND_S_INSTANCE "." /* Internally, New typed thing */ #define TI_KIND_S_OBJECT "," /* Internally, New thing */ @@ -68,6 +69,7 @@ typedef enum TI_VAL_CLOSURE, TI_VAL_FUTURE, /* future */ TI_VAL_MODULE, /* module */ + TI_VAL_ANO, /* anonymous wrap-only type */ 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 diff --git a/inc/util/mpack.h b/inc/util/mpack.h index 3795c00a..28c15e5d 100644 --- a/inc/util/mpack.h +++ b/inc/util/mpack.h @@ -24,6 +24,7 @@ typedef enum MPACK_EXT_TASK, MPACK_EXT_THING, MPACK_EXT_NAME, + MPACK_EXT_ANO, } mpack_ext_t; typedef struct diff --git a/src/langdef/langdef.c b/src/langdef/langdef.c index a91cb621..705d2394 100644 --- a/src/langdef/langdef.c +++ b/src/langdef/langdef.c @@ -5,7 +5,7 @@ * should be used with the libcleri module. * * Source class: LangDef - * Created at: 2024-02-11 20:55:25 + * Created at: 2025-11-07 13:13:19 */ #include @@ -30,6 +30,7 @@ cleri_grammar_t * compile_langdef(void) cleri_t * x_preopr = cleri_regex(CLERI_GID_X_PREOPR, "^(\\s*~)*(\\s*!|\\s*[\\-+](?=[^0-9]))*"); cleri_t * x_ternary = cleri_token(CLERI_GID_X_TERNARY, "?"); cleri_t * x_thing = cleri_token(CLERI_GID_X_THING, "{"); + cleri_t * x_ano = cleri_token(CLERI_GID_X_ANO, "&{"); cleri_t * x_template = cleri_token(CLERI_GID_X_TEMPLATE, "`"); cleri_t * template = cleri_sequence( CLERI_GID_TEMPLATE, @@ -68,6 +69,19 @@ cleri_grammar_t * compile_langdef(void) cleri_token(CLERI_NONE, "|"), CLERI_THIS ); + cleri_t * t_ano = cleri_sequence( + CLERI_GID_T_ANO, + 3, + x_ano, + cleri_list(CLERI_NONE, cleri_sequence( + CLERI_NONE, + 3, + name, + cleri_token(CLERI_NONE, ":"), + cleri_optional(CLERI_NONE, CLERI_THIS) + ), cleri_token(CLERI_NONE, ","), 0, 0, 1), + cleri_token(CLERI_NONE, "}") + ); cleri_t * thing = cleri_sequence( CLERI_GID_THING, 3, @@ -252,7 +266,7 @@ cleri_grammar_t * compile_langdef(void) cleri_choice( CLERI_NONE, CLERI_FIRST_MATCH, - 13, + 14, chain, t_false, t_nil, @@ -261,6 +275,7 @@ cleri_grammar_t * compile_langdef(void) t_int, t_string, t_regex, + t_ano, template, var_opt_more, thing, diff --git a/src/ti/ano.c b/src/ti/ano.c new file mode 100644 index 00000000..831bae3c --- /dev/null +++ b/src/ti/ano.c @@ -0,0 +1,141 @@ +/* + * ti/ano.c + */ +#include +#include +#include +#include + + +ti_ano_t * ti_ano_new(void) +{ + ti_ano_t * ano = calloc(1, sizeof(ti_ano_t)); + if (!ano) + return NULL; + ano->ref = 1; + ano->tp = TI_VAL_ANO; + return ano; +} + +int ti_ano_init( + ti_ano_t * ano, + ti_collection_t * collection, + ti_raw_t * spec_raw, + ex_t * e) +{ + uint8_t flags = TI_TYPE_FLAG_WRAP_ONLY | TI_TYPE_FLAG_HIDE_ID; + ti_type_t * type; + ti_val_t * val; + mp_unp_t up; + ti_vup_t vup = { + .isclient = true, + .collection = collection, + .up = &up, + }; + mp_unp_init(&up, spec_raw->data, spec_raw->n); + + val = ti_val_from_vup_e(&vup, e); + if (!val) + return e->nr; + + if (!ti_val_is_object(val)) + { + ex_set_internal(e); /* only with corrupt internal data */ + goto fail0; + } + + for (vec_each(((ti_thing_t *) val)->items.vec, ti_prop_t, prop)) + { + ti_raw_t * sr = (ti_raw_t *) prop->val; + if (ti_val_is_raw(prop->val) && sr->n) + { + if (sr->data[0] == '#') + flags &= ~TI_TYPE_FLAG_HIDE_ID; + + if (sr->data[0] == '|') + { + ti_qbind_t syntax = { + .immutable_n = 0, + .flags = TI_QBIND_FLAG_COLLECTION, + }; + ti_closure_t * closure = ti_closure_from_strn( + &syntax, + (const char *) sr->data, + sr->n, + e); + if (!closure) + goto fail0; + + ti_val_unsafe_drop(prop->val); + prop->val = (ti_val_t *) closure; + } + } + } + + type = ti_type_create_anonymous( + field->type->types, + field->type->rname, + flags); + if (!type) + { + ex_set_mem(e); + goto fail0; + } + + if (ti_type_init_from_thing(type, (ti_thing_t *) val, e)) + ti_type_drop_anonymous(type); + else + { + ano->type = type; + ano->spec_raw = spec_raw; + ti_incref(spec_raw); + } + +fail0: + ti_val_unsafe_drop(val); + return e->nr; +} + +ti_ano_t * ti_ano_from_raw( + ti_collection_t * collection, + ti_raw_t * spec_raw, + ex_t * e) +{ + ano = ti_ano_new(); + if (!ano) + { + ex_set_mem(e); + return NULL; + } + if (ti_ano_init(ano, collection, spec_raw, e)) + { + ti_ano_destroy(ano); + return NULL; + } + return ano; +} + +ti_ano_t * ti_ano_create( + ti_collection_t * collection, + const unsigned char * bin, + size_t n, + ex_t * e) +{ + ti_ano_t * ano; + ti_raw_t * spec_raw = ti_bin_create(bin, n); + if (!spec_raw) + return NULL; + + ano = ti_ano_from_raw(collection, spec_raw, e); + ti_val_unsafe_drop((ti_val_t *) spec_raw); + return ano; +} + +void ti_ano_destroy(ti_ano_t * ano) +{ + if (!ano) + return; + ti_val_drop(ano->spec_raw); + ti_type_drop_anonymous(ano->type); + free(ano); +} diff --git a/src/ti/async.c b/src/ti/async.c index b30a1ef1..9fce7522 100644 --- a/src/ti/async.c +++ b/src/ti/async.c @@ -1,5 +1,5 @@ /* - * ti/modasync.c + * ti/async.c */ #include #include diff --git a/src/ti/condition.c b/src/ti/condition.c index 385d452f..f6072647 100644 --- a/src/ti/condition.c +++ b/src/ti/condition.c @@ -812,7 +812,7 @@ int ti_condition_init_type(ti_field_t * field, ex_t * e) } } - type = ti_type_create_unnamed( + type = ti_type_create_anonymous( field->type->types, field->type->rname, flags); @@ -823,7 +823,7 @@ int ti_condition_init_type(ti_field_t * field, ex_t * e) } if (ti_type_init_from_thing(type, thing, e)) - ti_type_drop_unnamed(type); + ti_type_drop_anonymous(type); else field->condition.type = type; @@ -843,7 +843,7 @@ void ti_condition_destroy(ti_condition_via_t condition, uint16_t spec) { case TI_SPEC_TYPE: case TI_SPEC_ARR_TYPE: - ti_type_drop_unnamed(condition.type); + ti_type_drop_anonymous(condition.type); return; case TI_SPEC_ANY: return; /* a field may be set to ANY while using mod_type in which diff --git a/src/ti/do.c b/src/ti/do.c index b2203aff..1461192d 100644 --- a/src/ti/do.c +++ b/src/ti/do.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -1228,7 +1229,11 @@ static int do__fixed_name(ti_query_t * query, cleri_node_t * nd, ex_t * e) return e->nr; } -static int do__thing(ti_query_t * query, cleri_node_t * nd, ex_t * e) +static int do__thing( + ti_query_t * query, + cleri_node_t * nd, + ex_t * e, + uintptr_t sz) { /* * Sequence('{', List(Sequence(name, ':', scope)), '}') @@ -1302,6 +1307,48 @@ static int do__thing(ti_query_t * query, cleri_node_t * nd, ex_t * e) return e->nr; } +static int do__ano(ti_query_t * query, cleri_node_t * nd, ex_t * e) +{ + if (!nd->data) + { + nd->data = ti_ano_new(); + if (!nd->data) + { + ex_set_mem(e); + return e->nr; + } + assert(vec_space(query->immutable_cache)); + VEC_push(query->immutable_cache, nd->data); + } + if (ti_ano_uninitialized(nd->data)) + { + ti_raw_t * spec_raw; + if (!query->collection) + { + ex_set(e, EX_OPERATION, + "anonymous types are not supported in the the `%s` scope", + ti_query_scope_name(query)); + return e->nr; + } + + if (do__thing(query, nd, e, 7)) + return e->nr; + + spec_raw = ti_type_spec_raw_from_thing((ti_thing_t *) query->rval, e); + if (!spec_raw) + return e->nr; + + ti_val_unsafe_drop(query->rval); + query->rval = NULL; + + if (ti_ano_init(nd->data, query->collection, spec_raw, e)) + return e->nr; + } + query->rval = nd->data; + ti_incref(query->rval); + return e->nr; +} + static int do__instance(ti_query_t * query, cleri_node_t * nd, ex_t * e) { /* @@ -1868,6 +1915,10 @@ int ti_do_expression(ti_query_t * query, cleri_node_t * nd, ex_t * e) /* nothing is possible after a chain */ goto preopr; + case CLERI_GID_T_ANO: + if (do__ano(query, nd, e)) + return e->nr; + break; case CLERI_GID_T_FALSE: query->rval = (ti_val_t *) ti_vbool_get(false); break; @@ -1978,7 +2029,7 @@ int ti_do_expression(ti_query_t * query, cleri_node_t * nd, ex_t * e) } break; case CLERI_GID_THING: - if (do__thing(query, nd, e)) + if (do__thing(query, nd, e, (uintptr_t) nd->data);) return e->nr; break; case CLERI_GID_ARRAY: diff --git a/src/ti/enum.c b/src/ti/enum.c index 72782595..cab850a9 100644 --- a/src/ti/enum.c +++ b/src/ti/enum.c @@ -730,6 +730,7 @@ ti_member_t * ti_enum_member_by_val_e( case TI_VAL_MEMBER: case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_ANO: case TI_VAL_TEMPLATE: break; diff --git a/src/ti/export.c b/src/ti/export.c index d898d120..cdfd3fb6 100644 --- a/src/ti/export.c +++ b/src/ti/export.c @@ -440,6 +440,11 @@ static int export__val(ti_fmt_t * fmt, ti_val_t * val) "%.*s /* WARN: module must be installed */", module->name->n, module->name->str); } + case TI_VAL_ANO: + return -( + buf_write(buf, '&') || + export__thing(fmt, (ti_thing_t *) val) + ); case TI_VAL_ERROR: return buf_append_str(buf, "error() /* WARN: not exported */"); case TI_VAL_MEMBER: @@ -498,6 +503,7 @@ static int export__set_enum_cb(ti_enum_t * enum_, ti_fmt_t * fmt) case TI_VAL_MEMBER: case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_ANO: case TI_VAL_TEMPLATE: assert(0); break; diff --git a/src/ti/field.c b/src/ti/field.c index 4235214f..31362f8b 100644 --- a/src/ti/field.c +++ b/src/ti/field.c @@ -247,6 +247,11 @@ static ti_val_t * field__dval_room(ti_field_t * field) return (ti_val_t *) ti_room_create(0, field->type->types->collection); } +static ti_val_t * field__dval_ano(ti_field_t * UNUSED(field)) +{ + return ti_val_default_ano(); +} + static ti_val_t * field__dval_task(ti_field_t * UNUSED(field)) { return (ti_val_t *) ti_vtask_nil(); @@ -393,6 +398,7 @@ ti_field_map_t field__mapping[TOTAL_KEYWORDS] = { {.name="email", .spec=TI_SPEC_EMAIL, .dval_cb=field__dval_str}, {.name="url", .spec=TI_SPEC_URL, .dval_cb=field__dval_str}, {.name="tel", .spec=TI_SPEC_TEL, .dval_cb=field__dval_str}, + {.name="ano", .spec=TI_SPEC_ANO, .dval_cb=field__dval_ano}, }; static ti_field_map_t * field__map[MAX_HASH_VALUE+1]; @@ -913,7 +919,7 @@ static int field__init(ti_field_t * field, ex_t * e) field->name->str, field->type->name); } /* assert(field->dval_cb); callback must have been set except for fields - on unnamed type */ + on anonymous type */ return e->nr; invalid: @@ -1819,7 +1825,6 @@ int ti_field_make_assignable( 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: @@ -1833,15 +1838,18 @@ int ti_field_make_assignable( return field__varr_assign(field, (ti_varr_t **) val, parent, e); case TI_VAL_SET: return field__vset_assign(field, (ti_vset_t **) val, parent, e); - case TI_VAL_CLOSURE: - return ti_closure_unbound((ti_closure_t *) *val, e); case TI_VAL_ERROR: case TI_VAL_MEMBER: - case TI_VAL_TEMPLATE: + case TI_VAL_MPDATA: break; + case TI_VAL_CLOSURE: + return ti_closure_unbound((ti_closure_t *) *val, e); case TI_VAL_FUTURE: case TI_VAL_MODULE: goto future_module_error; + case TI_VAL_ANO: + case TI_VAL_TEMPLATE: + break; } return 0; case TI_SPEC_OBJECT: @@ -1956,6 +1964,10 @@ int ti_field_make_assignable( (ti_raw_t *) *val)) goto tel_error; return 0; + case TI_SPEC_ANO: + if (ti_val_is_ano(*val)) + return 0; + goto type_error; case TI_SPEC_ARR: if (ti_val_is_array(*val)) return field__varr_assign(field, (ti_varr_t **) val, parent, e); @@ -2261,6 +2273,8 @@ _Bool ti_field_maps_to_val(ti_field_t * field, ti_val_t * val) return ti_val_is_str(val) && ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val); + case TI_SPEC_ANO: + return ti_val_is_ano(val); case TI_SPEC_ARR: /* we can map a set to an array */ return (( @@ -2384,6 +2398,7 @@ static _Bool field__maps_to_nested(ti_field_t * t_field, ti_field_t * f_field) case TI_SPEC_EMAIL: case TI_SPEC_URL: case TI_SPEC_TEL: + case TI_SPEC_ANO: case TI_SPEC_ARR: case TI_SPEC_SET: case TI_SPEC_REMATCH: @@ -2508,6 +2523,7 @@ _Bool ti_field_maps_to_field(ti_field_t * t_field, ti_field_t * f_field) case TI_SPEC_EMAIL: case TI_SPEC_URL: case TI_SPEC_TEL: + case TI_SPEC_ANO: return f_spec == t_spec; case TI_SPEC_ARR: return ( diff --git a/src/ti/fmt.c b/src/ti/fmt.c index a04d4f77..61e317a6 100644 --- a/src/ti/fmt.c +++ b/src/ti/fmt.c @@ -378,6 +378,11 @@ static int fmt__expr_choice(ti_fmt_t * fmt, cleri_node_t * nd) { case CLERI_GID_CHAIN: return fmt__chain(fmt, nd, false); + case CLERI_GID_T_ANO: + return -( + buf_write(&fmt->buf, '&') || + fmt__thing(fmt, nd) + ); case CLERI_GID_T_FALSE: case CLERI_GID_T_FLOAT: case CLERI_GID_T_INT: diff --git a/src/ti/index.c b/src/ti/index.c index 712f4592..32cb5923 100644 --- a/src/ti/index.c +++ b/src/ti/index.c @@ -675,6 +675,7 @@ int ti_index(ti_query_t * query, cleri_node_t * nd, ex_t * e) case TI_VAL_CLOSURE: case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_ANO: if (do_slice) goto slice_error; goto index_error; diff --git a/src/ti/ncache.c b/src/ti/ncache.c index 95efd201..d4705e71 100644 --- a/src/ti/ncache.c +++ b/src/ti/ncache.c @@ -336,6 +336,26 @@ static int ncache__expr_choice( } return e->nr; } + case CLERI_GID_T_ANO: + { + cleri_node_t * child = nd /* sequence */ + ->children->next /* list */ + ->children; + for (; child; child = child->next ? child->next->next : NULL) + { + /* sequence(name: statement) (only investigate the statements */ + if (child->children->next->next == NULL + ? ncache__gen_name(vcache, child->children, e) + : ncache__statement( + syntax, + vcache, + child->children->next->next, + e)) + return e->nr; + } + nd->data = ti_ano_new(); + break; + } case CLERI_GID_ARRAY: return ncache__list( syntax, @@ -429,7 +449,7 @@ static int ncache__return_statement( { if (!nd->children->next->children) return 0; - + if (ncache__statement(syntax, vcache, nd->children->next->children, e)) return -1; diff --git a/src/ti/qbind.c b/src/ti/qbind.c index 271604f2..015ec88c 100644 --- a/src/ti/qbind.c +++ b/src/ti/qbind.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -302,15 +303,15 @@ static void qbind__statement(ti_qbind_t * qbind, cleri_node_t * nd); * * Command: * - * pcregrep -o1 '\.name\=\"(\w+)' qbind.c | gperf -E -k '*,1,$' -m 200 + * pcregrep -o1 '\.name\=\"(\w+)' qbind.c | gperf -E -k '*,1,$' -m 400 */ enum { - TOTAL_KEYWORDS = 281, + TOTAL_KEYWORDS = 282, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 17, - MIN_HASH_VALUE = 38, - MAX_HASH_VALUE = 796 + MIN_HASH_VALUE = 24, + MAX_HASH_VALUE = 776 }; /* @@ -322,32 +323,32 @@ static inline unsigned int qbind__hash( { static unsigned short asso_values[] = { - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 16, 15, - 18, 797, 19, 797, 18, 797, 16, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 15, 797, 20, 58, 82, - 24, 17, 152, 371, 112, 15, 18, 73, 17, 25, - 20, 22, 131, 15, 16, 15, 16, 52, 174, 300, - 204, 140, 29, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797, 797, 797, 797, 797, - 797, 797, 797, 797, 797, 797 + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 7, 7, + 7, 777, 8, 777, 8, 777, 8, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 7, 777, 24, 42, 69, + 40, 9, 127, 359, 240, 7, 7, 120, 13, 40, + 12, 14, 155, 39, 8, 7, 8, 48, 230, 241, + 174, 64, 62, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777, 777, 777, 777, 777, + 777, 777, 777, 777, 777, 777 }; register unsigned int hval = n; @@ -495,6 +496,7 @@ qbind__fmap_t qbind__fn_mapping[TOTAL_KEYWORDS] = { {.name="again_at", .fn=do__f_again_at, CHAIN_BE}, {.name="again_in", .fn=do__f_again_in, CHAIN_BE}, {.name="alt_raise", .fn=do__f_alt_raise, ROOT_NE}, + {.name="ano", .fn=do__f_ano, ROOT_NE}, {.name="args", .fn=do__f_args, CHAIN_NE}, {.name="assert", .fn=do__f_assert, ROOT_NE}, {.name="assert_err", .fn=do__f_assert_err, ROOT_NE}, @@ -1261,6 +1263,11 @@ static void qbind__expr_choice(ti_qbind_t * qbind, cleri_node_t * nd) ++qbind->immutable_n; nd->data = NULL; /* initialize data to null */ return; + case CLERI_GID_T_ANO: + qbind__thing(qbind, nd); + ++qbind->immutable_n; + nd->data = NULL; /* initialize data to null */ + return; case CLERI_GID_TEMPLATE: { cleri_node_t * child = nd /* sequence */ diff --git a/src/ti/query.c b/src/ti/query.c index 0aef2640..b19e74ce 100644 --- a/src/ti/query.c +++ b/src/ti/query.c @@ -1495,6 +1495,7 @@ static int query__get_things(ti_val_t * val, imap_t * imap) case TI_VAL_FUTURE: return VFUT(val) ? query__get_things(VFUT(val), imap) : 0; case TI_VAL_MODULE: + case TI_VAL_ANO: case TI_VAL_TEMPLATE: break; } diff --git a/src/ti/spec.c b/src/ti/spec.c index ffe517cc..8e8ba627 100644 --- a/src/ti/spec.c +++ b/src/ti/spec.c @@ -27,6 +27,7 @@ * pcregrep -o1 ' :: `(\w+)' spec.c | gperf -E -k '*,1,$' -m 200 :: `any` + :: `ano` :: `bool` :: `break` :: `bytes` @@ -69,11 +70,11 @@ enum { - TOTAL_KEYWORDS = 38, + TOTAL_KEYWORDS = 39, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 8, MIN_HASH_VALUE = 3, - MAX_HASH_VALUE = 41 + MAX_HASH_VALUE = 46 }; static inline unsigned int spec__hash( @@ -82,32 +83,32 @@ static inline unsigned int spec__hash( { static unsigned char asso_values[] = { - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 19, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 5, 6, 14, - 10, 0, 15, 24, 0, 5, 42, 17, 2, 8, - 0, 3, 19, 42, 2, 0, 0, 3, 13, 29, - 6, 16, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42 + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 17, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 15, 10, 13, + 9, 0, 11, 13, 0, 5, 47, 8, 2, 8, + 0, 3, 16, 47, 2, 0, 0, 3, 2, 13, + 11, 19, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47 }; register unsigned int hval = n; @@ -162,30 +163,32 @@ _Bool ti_spec_is_reserved(register const char * s, register size_t n) "enum", "union", "time", - "bool", - "date", - "room", - "try", "if", "for", - "any", - "number", - "task", - "bytes", + "room", + "ano", + "bool", + "thing", + "try", "pint", "tuple", - "float", + "task", + "date", + "number", "closure", - "final", - "continue", - "thing", - "break", - "datetime", "regex", - "catch", + "continue", "raw", + "bytes", + "utf8", + "float", + "any", + "final", "timeval", - "utf8" + "break", + "", "", "", "", + "datetime", + "catch" }; if (n <= MAX_WORD_LENGTH && n >= MIN_WORD_LENGTH) @@ -405,6 +408,8 @@ ti_spec_rval_enum ti__spec_check_nested_val(uint16_t spec, ti_val_t * val) : ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val) ? 0 : TI_SPEC_RVAL_TEL_ERROR; + case TI_SPEC_ANO: + return ti_val_is_ano(val) ? 0 : TI_SPEC_RVAL_TYPE_ERROR; case TI_SPEC_REMATCH: case TI_SPEC_INT_RANGE: case TI_SPEC_FLOAT_RANGE: @@ -501,6 +506,8 @@ _Bool ti__spec_maps_to_nested_val(uint16_t spec, ti_val_t * val) return ti_val_is_str(val) && ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val); + case TI_SPEC_ANO: + return ti_val_is_ano(val); case TI_SPEC_REMATCH: case TI_SPEC_INT_RANGE: case TI_SPEC_FLOAT_RANGE: @@ -553,6 +560,7 @@ const char * ti_spec_approx_type_str(uint16_t spec) case TI_SPEC_EMAIL: return "email"; case TI_SPEC_URL: return "url"; case TI_SPEC_TEL: return "tel"; + case TI_SPEC_ANO: return "ano"; case TI_SPEC_TYPE: case TI_SPEC_ARR_TYPE: assert(0); /* not possible for wrap-only */ @@ -669,6 +677,7 @@ ti_spec_mod_enum ti_spec_check_mod( case TI_SPEC_EMAIL: case TI_SPEC_URL: case TI_SPEC_TEL: + case TI_SPEC_ANO: return ospec == nspec ? TI_SPEC_MOD_SUCCESS : TI_SPEC_MOD_ERR; case TI_SPEC_REMATCH: return TI_SPEC_MOD_ERR; diff --git a/src/ti/thing.c b/src/ti/thing.c index a6a8b4d0..e2b76ca7 100644 --- a/src/ti/thing.c +++ b/src/ti/thing.c @@ -426,6 +426,7 @@ int ti_thing_p_prop_add_assign( case TI_VAL_TASK: case TI_VAL_ERROR: case TI_VAL_MEMBER: + case TI_VAL_ANO: ti_incref(val); break; case TI_VAL_ARR: @@ -527,6 +528,7 @@ int ti_thing_i_item_add_assign( case TI_VAL_TASK: case TI_VAL_ERROR: case TI_VAL_MEMBER: + case TI_VAL_ANO: ti_incref(val); break; case TI_VAL_ARR: diff --git a/src/ti/type.c b/src/ti/type.c index 48184b00..56320be1 100644 --- a/src/ti/type.c +++ b/src/ti/type.c @@ -94,7 +94,7 @@ ti_type_t * ti_type_create( return type; } -ti_type_t * ti_type_create_unnamed( +ti_type_t * ti_type_create_anonymous( ti_types_t * types, ti_raw_t * name, uint8_t flags) @@ -196,7 +196,7 @@ void ti_type_drop(ti_type_t * type) ti_type_destroy(type); } -void ti_type_drop_unnamed(ti_type_t * type) +void ti_type_drop_anonymous(ti_type_t * type) { if (!type) return; @@ -396,6 +396,38 @@ static int type__init_type_cb(ti_item_t * item, ex_t * e) return e->nr; } +ti_raw_t * ti_type_spec_raw_from_thing(ti_thing_t * thing, ex_t * e) +{ + if (ti_thing_is_dict(thing) && + smap_values(thing->items.smap, (smap_val_cb) type__init_type_cb, e)) + return NULL; + + if (mp_sbuffer_alloc_init(&buffer, vp.size_limit, 0)) + { + ex_set_mem(e); + return NULL; + } + + msgpack_packer_init(&vp.pk, &buffer, msgpack_sbuffer_write); + + if (ti_val_to_client_pk(val, &vp, TI_MAX_DEEP, TI_FLAGS_NO_IDS)) + { + if (buffer.size > vp.size_limit) + ex_set(e, EX_VALUE_ERROR, "wpo type definition too large"); + else + ex_set_mem(e); + goto fail0; + } + + spec_raw = ti_mp_create((const unsigned char *) buffer.data, buffer.size); + if (!spec_raw) + ex_set_mem(e); + +fail0: + msgpack_sbuffer_destroy(&buffer); + return spec_raw; +} + ti_raw_t * ti__type_nested_from_val(ti_type_t * type, ti_val_t * val, ex_t * e) { ti_thing_t * thing; @@ -443,37 +475,7 @@ ti_raw_t * ti__type_nested_from_val(ti_type_t * type, ti_val_t * val, ex_t * e) type->name); return NULL; } - - if (ti_thing_is_dict(thing) && - smap_values(thing->items.smap, (smap_val_cb) type__init_type_cb, e)) - return NULL; - - if (mp_sbuffer_alloc_init(&buffer, vp.size_limit, 0)) - { - ex_set_mem(e); - return NULL; - } - - msgpack_packer_init(&vp.pk, &buffer, msgpack_sbuffer_write); - - if (ti_val_to_client_pk(val, &vp, TI_MAX_DEEP, TI_FLAGS_NO_IDS)) - { - if (buffer.size > vp.size_limit) - ex_set(e, EX_VALUE_ERROR, - "nested type definition on type `%s` too large", - type->name); - else - ex_set_mem(e); - goto fail0; - } - - spec_raw = ti_mp_create((const unsigned char *) buffer.data, buffer.size); - if (!spec_raw) - ex_set_mem(e); - -fail0: - msgpack_sbuffer_destroy(&buffer); - return spec_raw; + return ti_type_spec_raw_from_thing(thing, e); } static inline int type__assign( diff --git a/src/ti/val.c b/src/ti/val.c index 40c93a72..14ed3046 100644 --- a/src/ti/val.c +++ b/src/ti/val.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,9 @@ static ti_val_t * val__empty_bin; static ti_val_t * val__empty_str; static ti_val_t * val__default_closure; +static ti_val_t * val__default_ano; static ti_val_t * val__default_re; +static ti_val_t * val__sano; static ti_val_t * val__sbool; static ti_val_t * val__sbytes; static ti_val_t * val__sclosure; @@ -92,7 +95,7 @@ ti_val_t * val__parent_name; ti_val_t * val__parent_type_name; ti_val_t * val__key_name; ti_val_t * val__key_type_name; -ti_val_t * val__unnamed_name; +ti_val_t * val__anonymous_name; /* string */ ti_val_t * val__sany; @@ -441,6 +444,7 @@ static int val__push(ti_varr_t * varr, ti_val_t * val, ex_t * e) case TI_VAL_ERROR: case TI_VAL_MPDATA: case TI_VAL_CLOSURE: + case TI_VAL_ANO: break; case TI_VAL_ARR: { @@ -699,6 +703,27 @@ ti_val_t * ti_val_from_vup_e(ti_vup_t * vup, ex_t * e) } return (ti_val_t *) name; } + case MPACK_EXT_ANO: + { + ti_ano_t * ano; + if (!vup->collection) + { + ex_set(e, EX_BAD_DATA, + "cannot unpack `anonymous` type without a collection"); + return NULL; + } + ano = ti_ano_create( + vup->collection, + obj.via.ext.data, + obj.via.ext.n); + if (!ano) + { + ex_set(e, EX_BAD_DATA, + "failed to unpack `anonymous`"); + return NULL; + } + return (ti_val_t *) ano; + } } ex_set(e, EX_BAD_DATA, "msgpack extension type %d is not supported by ThingsDB", @@ -720,6 +745,8 @@ int ti_val_init_common(void) }; val__default_closure = \ (ti_val_t *) ti_closure_from_strn(&syntax, "||nil", 5, &e); + val__default_ano = \ + (ti_val_t *) ti_ano_create(&syntax, "\x80", 1, &e); val__empty_bin = (ti_val_t *) ti_bin_create(NULL, 0); val__empty_str = (ti_val_t *) ti_str_from_str(""); val__default_re = (ti_val_t *) ti_regex_from_strn("/.*/", 4, &e); @@ -727,6 +754,7 @@ int ti_val_init_common(void) val__snil = (ti_val_t *) ti_str_from_str(TI_VAL_NIL_S); val__strue = (ti_val_t *) ti_str_from_str("true"); val__sfalse = (ti_val_t *) ti_str_from_str("false"); + val__sano = (ti_val_t *) ti_str_from_str(TI_VAL_ANO_S); val__sbool = (ti_val_t *) ti_str_from_str(TI_VAL_BOOL_S); val__sdatetime = (ti_val_t *) ti_str_from_str(TI_VAL_DATETIME_S); val__stimeval = (ti_val_t *) ti_str_from_str(TI_VAL_TIMEVAL_S); @@ -775,7 +803,7 @@ int ti_val_init_common(void) val__parent_type_name = (ti_val_t *) ti_names_from_str_slow("parent_type"); val__key_name = (ti_val_t *) ti_names_from_str_slow("key"); val__key_type_name = (ti_val_t *) ti_names_from_str_slow("key_type"); - val__unnamed_name = (ti_val_t *) ti_names_from_str_slow("__unnamed__"); + val__anonymous_name = (ti_val_t *) ti_names_from_str_slow("__anonymous__"); val__re_email = (ti_val_t *) ti_regex_from_str("/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$/"); val__re_url = (ti_val_t *) ti_regex_from_str("/^(https?|ftp):\\/\\/[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)$/"); val__re_tel = (ti_val_t *) ti_regex_from_str("/^[\\+]?(\\([0-9]{1,4}\\)[-\\s\\.]?){0,2}([0-9]{1,4}[-\\s]?){3,5}$/"); @@ -795,7 +823,7 @@ int ti_val_init_common(void) !val__key_name || !val__key_type_name || !val__flags_name || !val__data_name || !val__time_name || !val__re_email || !val__smodule || !val__re_url || !val__re_tel || !val__async_name || - !val__unnamed_name) + !val__anonymous_name || !val__default_ano || !val__sano) { return -1; } @@ -807,11 +835,13 @@ void ti_val_drop_common(void) ti_val_drop(val__empty_bin); ti_val_drop(val__empty_str); ti_val_drop(val__default_closure); + ti_val_drop(val__default_ano); ti_val_drop(val__default_re); ti_val_drop(val__sany); ti_val_drop(val__snil); ti_val_drop(val__strue); ti_val_drop(val__sfalse); + ti_val_drop(val__sano); ti_val_drop(val__sbool); ti_val_drop(val__sdatetime); ti_val_drop(val__stimeval); @@ -894,6 +924,12 @@ ti_val_t * ti_val_default_closure(void) return val__default_closure; } +ti_val_t * ti_val_default_ano(void) +{ + ti_incref(val__default_ano); + return val__default_ano; +} + ti_val_t * ti_val_charset_str(void) { ti_incref(val__charset_str); @@ -986,9 +1022,10 @@ int ti_val_convert_to_bytes(ti_val_t ** val, ex_t * e) { case TI_VAL_NAME: case TI_VAL_STR: + case TI_VAL_MPDATA: { ti_raw_t * r = (ti_raw_t *) (*val); - if (r->ref == 1 && r->tp == TI_VAL_STR) + if (r->ref == 1 && r->tp != TI_VAL_NAME) { /* only one reference left we can just change the type */ r->tp = TI_VAL_BYTES; @@ -1010,7 +1047,6 @@ int ti_val_convert_to_bytes(ti_val_t ** val, ex_t * e) case TI_VAL_FLOAT: case TI_VAL_BOOL: case TI_VAL_DATETIME: - case TI_VAL_MPDATA: case TI_VAL_THING: case TI_VAL_WRAP: case TI_VAL_ROOM: @@ -1020,6 +1056,7 @@ int ti_val_convert_to_bytes(ti_val_t ** val, ex_t * e) case TI_VAL_CLOSURE: case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_ANO: case TI_VAL_ERROR: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_BYTES_S"`", @@ -1588,6 +1625,7 @@ ti_val_t * ti_val_strv(ti_val_t * val) 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_ANO: return ti_grab(val__sano); case TI_VAL_TEMPLATE: assert(0); } @@ -1888,3 +1926,9 @@ int ti_val_closure_to_str(ti_val_t ** val, ex_t * e) *val = v; return 0; } +int ti_val_ano_to_str(ti_val_t ** val, ex_t * UNUSED(e)) +{ + ti_val_unsafe_drop(*val); + *val = ti_val_anonymous_name(); + return 0; +} From 3b44f40c4873afb1d8877a2daf75e2de855a3208 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Fri, 7 Nov 2025 20:36:48 +0100 Subject: [PATCH 02/13] Work on ano type --- CHANGELOG.md | 2 +- CMakeLists.txt | 1 + inc/ti/ano.h | 3 +- inc/ti/fn/fn.h | 89 +++++++++++++++ inc/ti/fn/fnano.h | 7 +- inc/ti/fn/fnbase64encode.h | 2 +- inc/ti/fn/fnclosure.h | 3 +- inc/ti/fn/fnmapwrap.h | 44 +++++--- inc/ti/fn/fnsearch.h | 7 +- inc/ti/fn/fnwrap.h | 13 ++- inc/ti/forloop.h | 5 +- inc/ti/spec.t.h | 1 - inc/ti/type.h | 5 +- inc/ti/val.h | 2 + inc/ti/val.inline.h | 75 ++++++++----- inc/ti/val.t.h | 5 +- inc/ti/version.h | 4 +- inc/ti/wano.h | 14 +++ inc/ti/wano.inline.h | 33 ++++++ inc/ti/wano.t.h | 21 ++++ inc/ti/wrap.h | 6 + itest/test_ano.py | 50 +++++++++ src/ti/ano.c | 10 +- src/ti/do.c | 12 +- src/ti/enum.c | 3 +- src/ti/export.c | 60 +++++----- src/ti/field.c | 24 +--- src/ti/index.c | 3 +- src/ti/query.c | 5 +- src/ti/spec.c | 6 - src/ti/thing.c | 2 + src/ti/type.c | 25 +++-- src/ti/val.c | 217 ++++++++++++++++++++++--------------- src/ti/varr.c | 4 + src/ti/wano.c | 25 +++++ src/ti/wrap.c | 27 +++-- 36 files changed, 581 insertions(+), 234 deletions(-) create mode 100644 inc/ti/wano.h create mode 100644 inc/ti/wano.inline.h create mode 100644 inc/ti/wano.t.h create mode 100755 itest/test_ano.py create mode 100644 src/ti/wano.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d71e7f6..fda64dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # v1.8.2-alpha0 -* Allow converting `mpdata` to `bytes, issue #...TODO +* Allow converting `mpdata` to `bytes, issue #427. # v1.8.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 04ef5154..82fdc9e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -227,6 +227,7 @@ set(SOURCES src/ti/vint.c src/ti/vset.c src/ti/vtask.c + src/ti/wano.c src/ti/warn.c src/ti/watch.c src/ti/web.c diff --git a/inc/ti/ano.h b/inc/ti/ano.h index c89bfa31..9390e306 100644 --- a/inc/ti/ano.h +++ b/inc/ti/ano.h @@ -4,13 +4,14 @@ #ifndef TI_ANO_H_ #define TI_ANO_H_ - #include #include #include #include #include +#define ANO_T(__x) ((ti_ano_t *) (__x))->type + ti_ano_t * ti_ano_new(void); int ti_ano_init( ti_ano_t * ano, diff --git a/inc/ti/fn/fn.h b/inc/ti/fn/fn.h index 48840740..d3b779fd 100644 --- a/inc/ti/fn/fn.h +++ b/inc/ti/fn/fn.h @@ -247,6 +247,23 @@ static inline int fn_arg_str( return e->nr; } +static inline int fn_arg_str_or_ano( + const char * name, + const char * doc, + int argn, + ti_val_t * val, + ex_t * e) +{ + if (!ti_val_is_str(val)) + ex_set(e, EX_TYPE_ERROR, + "function `%s` expects argument %d to be of " + "type `"TI_VAL_STR_S"` or `"TI_VAL_ANO_S"` " + "but got type `%s` instead%s", + name, argn, ti_val_str(val), doc); + return e->nr; +} + + static inline int fn_arg_bytes( const char * name, const char * doc, @@ -663,6 +680,72 @@ static int fn_call_w_try_n( return e->nr; } +static int fn_call_wa_try_n( + const char * name, + size_t n, + ti_query_t * query, + cleri_node_t * nd, + ex_t * e) +{ + ti_name_t * name_; + ti_method_t * method; + ti_wano_t * wano = (ti_wano_t *) query->rval; + ti_thing_t * thing = wano->thing; + + name_ = ti_names_weak_get_strn(name, n); + if (!name_) + goto no_method_err; + + method = ti_type_get_method(wano->ano->type, name_); + if (!method) + goto no_method_err; + + ti_incref(thing); + ti_val_unsafe_drop(query->rval); + query->rval = (ti_val_t *) thing; + + return ti_method_call(method, wano->ano->type, query, nd, e); + +no_method_err: + ex_set(e, EX_LOOKUP_ERROR, + "type `%s` has no method `%.*s`", + wano->ano->type->name, (int) n, name); + return e->nr; +} + +static int fn_call_a_try_n( + const char * name, + size_t n, + ti_query_t * query, + cleri_node_t * nd, + ex_t * e) +{ + ti_name_t * name_; + ti_method_t * method; + ti_ano_t * ano = (ti_ano_t *) query->rval; + + name_ = ti_names_weak_get_strn(name, n); + if (!name_) + goto no_method_err; + + method = ti_type_get_method(ano->type, name_); + if (!method) + goto no_method_err; + + + ti_incref(method->closure); + ti_val_unsafe_drop(query->rval); + query->rval = (ti_val_t *) method->closure; + // TODO: ANO: test + return fn_call(query, nd, e); + +no_method_err: + ex_set(e, EX_LOOKUP_ERROR, + "type `%s` has no method `%.*s`", + ano->type->name, (int) n, name); + return e->nr; +} + static int fn_call_f_try_n( const char * name, size_t n, @@ -730,6 +813,12 @@ 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_wano(query->rval)) + return fn_call_wa_try_n(name, n, query, nd, e); + + if (ti_val_is_ano(query->rval)) + return fn_call_a_try_n(name, n, query, nd, e); + if (ti_val_is_module(query->rval)) return fn_call_f_try_n(name, n, query, nd, e); diff --git a/inc/ti/fn/fnano.h b/inc/ti/fn/fnano.h index 80b71ef4..cca80cef 100644 --- a/inc/ti/fn/fnano.h +++ b/inc/ti/fn/fnano.h @@ -11,12 +11,15 @@ static int do__f_ano(ti_query_t * query, cleri_node_t * nd, ex_t * e) fn_arg_thing("ano", DOC_ANO, 1, query->rval, e)) return e->nr; - spec_raw = ti_type_spec_raw_from_thing((ti_thing_t *) query->rval, e); + spec_raw = ti_type_spec_raw_from_thing( + (ti_thing_t *) query->rval, + query->rval, + e); if (!spec_raw) return e->nr; ti_val_unsafe_drop(query->rval); - query->rval = ti_ano_from_raw(nd->data, query->collection, spec_raw, e); + query->rval = (ti_val_t *) ti_ano_from_raw(query->collection, spec_raw, e); ti_val_unsafe_drop((ti_val_t *) spec_raw); return e->nr; diff --git a/inc/ti/fn/fnbase64encode.h b/inc/ti/fn/fnbase64encode.h index 05e97904..25ad1fce 100644 --- a/inc/ti/fn/fnbase64encode.h +++ b/inc/ti/fn/fnbase64encode.h @@ -13,7 +13,7 @@ static int do__f_base64_encode(ti_query_t * query, cleri_node_t * nd, ex_t * e) { ex_set(e, EX_TYPE_ERROR, "function `base64_encode` expects argument 1 to be of " - "type `"TI_VAL_STR_S"` or type `"TI_VAL_BYTES_S"` " + "type `"TI_VAL_STR_S"`, `"TI_VAL_BYTES_S"` or `"TI_VAL_MPDATA_S"` " "but got type `%s` instead"DOC_BASE64_ENCODE, ti_val_str(query->rval)); return e->nr; diff --git a/inc/ti/fn/fnclosure.h b/inc/ti/fn/fnclosure.h index a4f6b41d..00bb8a0a 100644 --- a/inc/ti/fn/fnclosure.h +++ b/inc/ti/fn/fnclosure.h @@ -62,9 +62,10 @@ static int do__f_closure_new(ti_query_t * query, cleri_node_t * nd, ex_t * e) case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_MPDATA: + case TI_VAL_ANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_ANO: + case TI_VAL_WANO: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_CLOSURE_S"`", ti_val_str(query->rval)); diff --git a/inc/ti/fn/fnmapwrap.h b/inc/ti/fn/fnmapwrap.h index 0bccab1e..52d45c24 100644 --- a/inc/ti/fn/fnmapwrap.h +++ b/inc/ti/fn/fnmapwrap.h @@ -3,18 +3,23 @@ typedef struct { ti_type_t * type; + ti_ano_t * ano; ti_varr_t * varr; ex_t * e; } map_wrap__walk_t; static int map_wrap__walk_set(ti_thing_t * thing, map_wrap__walk_t * w) { - ti_wrap_t * wrap; + void * wrap; if (w->type) { wrap = ti_wrap_create(thing, w->type->type_id); } + else if (w->ano) + { + wrap = ti_wano_create(thing, w->ano); + } else if (ti_thing_is_instance(thing)) { wrap = ti_wrap_create(thing, thing->via.type->type_id); @@ -45,6 +50,7 @@ static int do__f_map_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) size_t n; ti_varr_t * varr; ti_type_t * type = NULL; + ti_ano_t * ano = NULL; ti_val_t * iterable; doc = doc_map_wrap(query->rval); @@ -61,21 +67,27 @@ static int do__f_map_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) if (nargs == 1) { if (ti_do_statement(query, nd->children, e) || - fn_arg_str("map_wrap", doc, 1, query->rval, e)) + fn_arg_str_or_ano("map_wrap", doc, 1, query->rval, e)) goto fail0; - type = query->collection - ? ti_types_by_raw( - query->collection->types, - (ti_raw_t *) query->rval) - : NULL; - if (!type) + if (ti_val_is_ano(query->rval)) { - (void) ti_raw_err_not_found((ti_raw_t *) query->rval, "type", e); - goto fail0; + ano = (ti_ano_t *) query->rval; + } + else + { + type = query->collection + ? ti_types_by_raw( + query->collection->types, + (ti_raw_t *) query->rval) + : NULL; + if (!type) + { + (void) ti_raw_err_not_found((ti_raw_t *) query->rval, "type", e); + goto fail0; + } + ti_val_unsafe_drop(query->rval); } - - ti_val_unsafe_drop(query->rval); query->rval = NULL; } @@ -90,7 +102,7 @@ static int do__f_map_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) case TI_VAL_ARR: for (vec_each(VARR(iterable), ti_val_t, val)) { - ti_wrap_t * wrap; + void * wrap; ti_thing_t * thing; if (!ti_val_is_thing(val)) @@ -109,6 +121,10 @@ static int do__f_map_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) { wrap = ti_wrap_create(thing, type->type_id); } + else if (ano) + { + wrap = ti_wano_create(thing, ano); + } else if (ti_thing_is_instance(thing)) { wrap = ti_wrap_create(thing, thing->via.type->type_id); @@ -134,6 +150,7 @@ static int do__f_map_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) { map_wrap__walk_t w = { .type=type, + .ano=ano, .varr=varr, .e=e, }; @@ -151,5 +168,6 @@ static int do__f_map_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) ti_val_unsafe_drop((ti_val_t *) varr); fail0: ti_val_unsafe_drop(iterable); + ti_val_drop((ti_val_t *) ano); return e->nr; } diff --git a/inc/ti/fn/fnsearch.h b/inc/ti/fn/fnsearch.h index 48389127..d03cacbd 100644 --- a/inc/ti/fn/fnsearch.h +++ b/inc/ti/fn/fnsearch.h @@ -202,10 +202,13 @@ static int do__search_thing( }; return imap_walk(VSET(val), (imap_cb) search__walk_set, &ws); } - case TI_VAL_TEMPLATE: + case TI_VAL_ANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_ANO: + return 0; + case TI_VAL_WANO: + return search__do_thing(((ti_wano_t *) val)->thing, root, key, w); + case TI_VAL_TEMPLATE: return 0; } assert(0); diff --git a/inc/ti/fn/fnwrap.h b/inc/ti/fn/fnwrap.h index dbd63f1f..e73db991 100644 --- a/inc/ti/fn/fnwrap.h +++ b/inc/ti/fn/fnwrap.h @@ -3,8 +3,8 @@ static int do__f_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) { const int nargs = fn_get_nargs(nd); - ti_type_t * type; ti_thing_t * thing; + ti_type_t * type; if (!ti_val_is_thing(query->rval)) return fn_call_try("wrap", query, nd, e); @@ -18,9 +18,17 @@ static int do__f_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) if (nargs == 1) { if (ti_do_statement(query, nd->children, e) || - fn_arg_str("wrap", DOC_THING_WRAP, 1, query->rval, e)) + fn_arg_str_or_ano("wrap", DOC_THING_WRAP, 1, query->rval, e)) goto fail0; + if (ti_val_is_ano(query->rval)) + { + ti_ano_t * ano = (ti_ano_t *) query->rval; + query->rval = (ti_val_t *) ti_wano_create(thing, ano); + ti_val_unsafe_drop((ti_val_t *) ano); + goto done; + } + type = query->collection ? ti_types_by_raw(query->collection->types, (ti_raw_t *) query->rval) : NULL; @@ -47,6 +55,7 @@ static int do__f_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) } query->rval = (ti_val_t *) ti_wrap_create(thing, type->type_id); +done: if (!query->rval) ex_set_mem(e); diff --git a/inc/ti/forloop.h b/inc/ti/forloop.h index 24c347f1..4611b039 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[22] = { +static const ti_forloop_t ti_forloop_callbacks[24] = { ti_forloop_no_iter, /* TI_VAL_NIL */ ti_forloop_no_iter, /* TI_VAL_INT */ ti_forloop_no_iter, /* TI_VAL_FLOAT */ @@ -59,9 +59,10 @@ static const ti_forloop_t ti_forloop_callbacks[22] = { ti_forloop_no_iter, /* TI_VAL_MEMBER */ ti_forloop_no_iter, /* TI_VAL_MPDATA */ ti_forloop_no_iter, /* TI_VAL_CLOSURE */ + ti_forloop_no_iter, /* TI_VAL_ANO */ ti_forloop_no_iter, /* TI_VAL_FUTURE */ ti_forloop_no_iter, /* TI_VAL_MODULE */ - ti_forloop_no_iter, /* TI_VAL_ANO */ + ti_forloop_no_iter, /* TI_VAL_WANO */ ti_forloop_no_iter, /* TI_VAL_TEMPLATE */ }; diff --git a/inc/ti/spec.t.h b/inc/ti/spec.t.h index c5048c43..6b645733 100644 --- a/inc/ti/spec.t.h +++ b/inc/ti/spec.t.h @@ -39,7 +39,6 @@ typedef enum TI_SPEC_EMAIL, /* `email` */ TI_SPEC_URL, /* `url` */ TI_SPEC_TEL, /* `tel` */ - TI_SPEC_ANO, /* `ano` */ TI_SPEC_REMATCH=0x5000, /* `/.../` */ TI_SPEC_INT_RANGE, /* `int<:> */ diff --git a/inc/ti/type.h b/inc/ti/type.h index 57c7684f..ed5b6722 100644 --- a/inc/ti/type.h +++ b/inc/ti/type.h @@ -77,7 +77,10 @@ int ti_type_methods_info_to_pk( int ti_type_required_by_non_wpo(ti_type_t * type, ex_t * e); int ti_type_requires_wpo(ti_type_t * type, ex_t * e); int ti_type_rename(ti_type_t * type, ti_raw_t * nname); -ti_raw_t * ti_type_spec_raw_from_thing(ti_thing_t * thing, ex_t * e); +ti_raw_t * ti_type_spec_raw_from_thing( + ti_thing_t * thing, + ti_val_t * val, /* may be equal to thing, or an ti_varr_t */ + ex_t * e); ti_raw_t * ti__type_nested_from_val(ti_type_t * type, ti_val_t * val, ex_t * e); static inline int ti_type_use(ti_type_t * type, ex_t * e) diff --git a/inc/ti/val.h b/inc/ti/val.h index 37bee9e8..87dd5bda 100644 --- a/inc/ti/val.h +++ b/inc/ti/val.h @@ -84,10 +84,12 @@ int ti_val_bytes_to_str(ti_val_t ** val, ex_t * e); int ti_val_regex_to_str(ti_val_t ** val, ex_t * e); int ti_val_thing_to_str(ti_val_t ** val, ex_t * e); int ti_val_wrap_to_str(ti_val_t ** val, ex_t * e); +int ti_val_wano_to_str(ti_val_t ** val, ex_t * e); int ti_val_room_to_str(ti_val_t ** val, ex_t * e); int ti_val_vtask_to_str(ti_val_t ** val, ex_t * e); int ti_val_error_to_str(ti_val_t ** val, ex_t * e); int ti_val_member_to_str(ti_val_t ** val, ex_t * e); int ti_val_closure_to_str(ti_val_t ** val, ex_t * e); +int ti_val_ano_to_str(ti_val_t ** val, ex_t * e); #endif /* TI_VAL_H_ */ diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index 51b9a80a..dbfae511 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -5,6 +5,7 @@ #define TI_VAL_INLINE_H_ #include +#include #include #include #include @@ -29,8 +30,10 @@ #include #include #include +#include #include #include +#include #include static inline int val__str_to_str(ti_val_t ** UNUSED(v), ex_t * UNUSED(e)); @@ -76,6 +79,10 @@ static inline _Bool val__as_bool_wrap(ti_val_t * val) { return !!ti_thing_n(((ti_wrap_t *) val)->thing); } +static inline _Bool val__as_bool_wano(ti_val_t * val) +{ + return !!ti_thing_n(((ti_wano_t *) val)->thing); +} static inline _Bool val__as_bool_room(ti_val_t * val) { return !!((ti_room_t *) val)->id; @@ -177,6 +184,11 @@ static inline const char * val__ano_type_str(ti_val_t * UNUSED(val)) { return TI_VAL_ANO_S; } +static inline const char * val__wano_type_str(ti_val_t * UNUSED(val)) +{ + return TI_VAL_WANO_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); @@ -292,8 +304,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__as_nil_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) { @@ -321,7 +332,7 @@ typedef struct } ti_val_type_t; -static ti_val_type_t ti_val_type_props[22] = { +static ti_val_type_t ti_val_type_props[24] = { /* TI_VAL_NIL */ { .destroy = (ti_val_destroy_cb) free, @@ -531,11 +542,22 @@ static ti_val_type_t ti_val_type_props[22] = { .as_bool = val__as_bool_true, .allowed_as_vtask_arg = false, }, + /* TI_VAL_ANO */ + { + .destroy = (ti_val_destroy_cb) ti_ano_destroy, + .to_str = ti_val_ano_to_str, + .to_arr_cb = val__to_arr_cb, + .to_client_pk = val__ano_to_client_pk, + .to_store_pk = (ti_val_to_store_pk_cb) ti_ano_to_store_pk, + .get_type_str = val__ano_type_str, + .as_bool = val__as_bool_true, + .allowed_as_vtask_arg = false, + }, /* TI_VAL_FUTURE */ { .destroy = (ti_val_destroy_cb) ti_future_destroy, .to_str = val__no_to_str, - .to_arr_cb = val__future_to_arr, + .to_arr_cb = val__as_nil_to_arr, .to_client_pk = (ti_val_to_client_pk_cb) val__future_to_client_pk, .get_type_str = val__future_type_str, .as_bool = val__as_bool_true, @@ -545,21 +567,20 @@ static ti_val_type_t ti_val_type_props[22] = { { .destroy = (ti_val_destroy_cb) ti_module_destroy, .to_str = val__no_to_str, - .to_arr_cb = val__module_to_arr, + .to_arr_cb = val__as_nil_to_arr, .to_client_pk = (ti_val_to_client_pk_cb) val__module_to_client_pk, .get_type_str = val__module_type_str, .as_bool = val__as_bool_true, .allowed_as_vtask_arg = false, }, - /* TI_VAL_ANO */ + /* TI_VAL_WANO */ { - .destroy = (ti_val_destroy_cb) ti_ano_destroy, - .to_str = ti_val_ano_to_str, - .to_arr_cb = val__to_arr_cb, - .to_client_pk = val__ano_to_client_pk, - .to_store_pk = (ti_val_to_store_pk_cb) ti_ano_to_store_pk, - .get_type_str = val__ano_type_str, - .as_bool = val__as_bool_true, + .destroy = (ti_val_destroy_cb) ti_wano_destroy, + .to_str = ti_val_wano_to_str, + .to_arr_cb = val__as_nil_to_arr, + .to_client_pk = (ti_val_to_client_pk_cb) ti_wano_to_client_pk, + .get_type_str = val__wano_type_str, + .as_bool = val__as_bool_wano, .allowed_as_vtask_arg = false, }, /* TI_VAL_TEMPLATE */ @@ -813,6 +834,11 @@ static inline _Bool ti_val_is_wrap(ti_val_t * val) return val->tp == TI_VAL_WRAP; } +static inline _Bool ti_val_is_wano(ti_val_t * val) +{ + return val->tp == TI_VAL_WANO; +} + static inline _Bool ti_val_is_room(ti_val_t * val) { return val->tp == TI_VAL_ROOM; @@ -943,6 +969,11 @@ static inline ti_val_t * ti_val_anonymous_name(void) return ti_incref(val__anonymous_name), val__anonymous_name; } +static inline ti_val_t * ti_val_borrow_anonymous_name(void) +{ + return val__anonymous_name; +} + static inline ti_val_t * ti_val_borrow_async_name(void) { return val__async_name; @@ -1149,9 +1180,10 @@ static inline void ti_val_attach( case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_CLOSURE: + case TI_VAL_ANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_ANO: + case TI_VAL_WANO: return; case TI_VAL_ARR: ((ti_varr_t *) val)->parent = parent; @@ -1222,13 +1254,14 @@ static inline int ti_val_make_assignable( return 0; case TI_VAL_CLOSURE: return ti_closure_unbound((ti_closure_t *) *val, e); + case TI_VAL_ANO: + return 0; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; - case TI_VAL_ANO: - return 0; case TI_VAL_TEMPLATE: break; } @@ -1341,7 +1374,6 @@ static inline _Bool val__spec_enum_eq_to_val(uint16_t spec, ti_val_t * val) * TI_SPEC_EMAIL, * TI_SPEC_URL, * TI_SPEC_TEL, - * TI_SPEC_ANO, */ static ti_val_spec_t ti_val_spec_map[25] = { @@ -1427,14 +1459,7 @@ static inline int val__member_to_arr(ti_val_t ** v, ti_varr_t * varr, ex_t * e) return e->nr; } -static inline int val__future_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; -} - -static inline int val__module_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * UNUSED(e)) +static inline int val__as_nil_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(); diff --git a/inc/ti/val.t.h b/inc/ti/val.t.h index fe25a303..6a02fa96 100644 --- a/inc/ti/val.t.h +++ b/inc/ti/val.t.h @@ -27,6 +27,7 @@ #define TI_VAL_MODULE_S "module" #define TI_VAL_TASK_S "task" #define TI_VAL_ANO_S "anonymous" +#define TI_VAL_WANO_S "" #define TI_KIND_S_INSTANCE "." /* Internally, New typed thing */ #define TI_KIND_S_OBJECT "," /* Internally, New thing */ @@ -67,9 +68,11 @@ typedef enum TI_VAL_MEMBER, /* enum member */ TI_VAL_MPDATA, /* msgpack data */ TI_VAL_CLOSURE, + TI_VAL_ANO, /* anonymous wrap-only type */ + /* future, module and template are never stored */ TI_VAL_FUTURE, /* future */ TI_VAL_MODULE, /* module */ - TI_VAL_ANO, /* anonymous wrap-only type */ + TI_VAL_WANO, /* wrapped with anonymous type */ 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 diff --git a/inc/ti/version.h b/inc/ti/version.h index d6af9504..33a68c1e 100644 --- a/inc/ti/version.h +++ b/inc/ti/version.h @@ -6,7 +6,7 @@ #define TI_VERSION_MAJOR 1 #define TI_VERSION_MINOR 8 -#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/inc/ti/wano.h b/inc/ti/wano.h new file mode 100644 index 00000000..82b2803e --- /dev/null +++ b/inc/ti/wano.h @@ -0,0 +1,14 @@ +/* + * ti/wano.h + */ +#ifndef TI_WANO_H_ +#define TI_WANO_H_ + +#include +#include +#include + +ti_wano_t * ti_wano_create(ti_thing_t * thing, ti_ano_t * ano); +void ti_wano_destroy(ti_wano_t * wano); + +#endif /* TI_WANO_H_ */ diff --git a/inc/ti/wano.inline.h b/inc/ti/wano.inline.h new file mode 100644 index 00000000..36909a06 --- /dev/null +++ b/inc/ti/wano.inline.h @@ -0,0 +1,33 @@ +/* + * ti/wano.inline.h + */ +#ifndef TI_WANO_INLINE_H_ +#define TI_WANO_INLINE_H_ + +#include +#include +#include +#include +#include + +static inline ti_raw_t * ti_wano_str(ti_wano_t * wano) +{ + return wano->thing->id + ? ti_str_from_fmt(TI_VAL_WANO_S":%"PRIu64, wano->thing->id) + : ti_str_from_str(TI_VAL_WANO_S":nil"); +} + +static inline int ti_wano_to_client_pk( + ti_wano_t * wano, + ti_vp_t * vp, + int deep, + int flags) +{ + return deep > 0 + ? ti_wrap_field_thing_type(wano->thing, vp, wano->ano->type, deep, flags) + : (!wano->thing->id || (flags & TI_FLAGS_NO_IDS)) + ? ti_thing_empty_to_client_pk(&vp->pk) + : ti_thing_id_to_client_pk(wano->thing, &vp->pk); +} + +#endif /* TI_WANO_INLINE_H_ */ diff --git a/inc/ti/wano.t.h b/inc/ti/wano.t.h new file mode 100644 index 00000000..a5566f6b --- /dev/null +++ b/inc/ti/wano.t.h @@ -0,0 +1,21 @@ +/* + * ti/wano.t.h + */ +#ifndef TI_WANO_T_H_ +#define TI_WANO_T_H_ + +typedef struct ti_wano_s ti_wano_t; + +#include +#include + +struct ti_wano_s +{ + uint32_t ref; + uint8_t tp; + int:24; + ti_ano_t * ano; /* with reference */ + ti_thing_t * thing; /* with reference */ +}; + +#endif /* TI_WANO_T_H_ */ diff --git a/inc/ti/wrap.h b/inc/ti/wrap.h index b1a17b73..f93c3fdc 100644 --- a/inc/ti/wrap.h +++ b/inc/ti/wrap.h @@ -21,6 +21,12 @@ int ti__wrap_field_thing( uint16_t spec, int deep, int flags); +int ti_wrap_field_thing_type( + ti_thing_t * thing, + ti_vp_t * vp, + ti_type_t * t_type, + int deep, + int flags); int ti_wrap_cp(ti_query_t * query, uint8_t deep, ex_t * e); int ti_wrap_copy(ti_wrap_t ** wrap, uint8_t deep); int ti_wrap_dup(ti_wrap_t ** wrap, uint8_t deep); diff --git a/itest/test_ano.py b/itest/test_ano.py new file mode 100755 index 00000000..b479d2ad --- /dev/null +++ b/itest/test_ano.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +import asyncio +import pickle +import time +from lib import run_test +from lib import default_test_setup +from lib.testbase import TestBase +from lib.client import get_client +from thingsdb.exceptions import AssertionError +from thingsdb.exceptions import ValueError +from thingsdb.exceptions import TypeError +from thingsdb.exceptions import NumArgumentsError +from thingsdb.exceptions import BadDataError +from thingsdb.exceptions import LookupError +from thingsdb.exceptions import OverflowError +from thingsdb.exceptions import ZeroDivisionError +from thingsdb.exceptions import OperationError + + +class TestAno(TestBase): + + title = 'Test anonymous type' + + @default_test_setup(num_nodes=1, seed=1, threshold_full_storage=10) + async def async_run(self): + + await self.node0.init_and_run() + + client = await get_client(self.node0) + client.set_default_scope('//stuff') + + await self.run_tests(client) + + client.close() + await client.wait_closed() + + async def test_ano_err(self, client): + + with self.assertRaisesRegex( + ValueError, + r'xxx'): + await client.query("""//ti + ... + """) + + # TODO : test len(ano type) + + +if __name__ == '__main__': + run_test(TestAno()) diff --git a/src/ti/ano.c b/src/ti/ano.c index 831bae3c..bfce50df 100644 --- a/src/ti/ano.c +++ b/src/ti/ano.c @@ -73,8 +73,8 @@ int ti_ano_init( } type = ti_type_create_anonymous( - field->type->types, - field->type->rname, + collection->types, + (ti_raw_t *) ti_val_borrow_anonymous_name(), flags); if (!type) { @@ -101,7 +101,7 @@ ti_ano_t * ti_ano_from_raw( ti_raw_t * spec_raw, ex_t * e) { - ano = ti_ano_new(); + ti_ano_t * ano = ti_ano_new(); if (!ano) { ex_set_mem(e); @@ -133,9 +133,7 @@ ti_ano_t * ti_ano_create( void ti_ano_destroy(ti_ano_t * ano) { - if (!ano) - return; - ti_val_drop(ano->spec_raw); + ti_val_drop((ti_val_t *) ano->spec_raw); ti_type_drop_anonymous(ano->type); free(ano); } diff --git a/src/ti/do.c b/src/ti/do.c index 1461192d..a4950606 100644 --- a/src/ti/do.c +++ b/src/ti/do.c @@ -1240,11 +1240,8 @@ static int do__thing( */ assert(e->nr == 0); - ti_thing_t * thing; cleri_node_t * child; - uintptr_t sz = (uintptr_t) nd->data; - - thing = ti_thing_o_create(0, sz, query->collection); + ti_thing_t * thing = ti_thing_o_create(0, sz, query->collection); if (!thing) goto failed_save; @@ -1334,7 +1331,10 @@ static int do__ano(ti_query_t * query, cleri_node_t * nd, ex_t * e) if (do__thing(query, nd, e, 7)) return e->nr; - spec_raw = ti_type_spec_raw_from_thing((ti_thing_t *) query->rval, e); + spec_raw = ti_type_spec_raw_from_thing( + (ti_thing_t *) query->rval, + query->rval, + e); if (!spec_raw) return e->nr; @@ -2029,7 +2029,7 @@ int ti_do_expression(ti_query_t * query, cleri_node_t * nd, ex_t * e) } break; case CLERI_GID_THING: - if (do__thing(query, nd, e, (uintptr_t) nd->data);) + if (do__thing(query, nd, e, (uintptr_t) nd->data)) return e->nr; break; case CLERI_GID_ARRAY: diff --git a/src/ti/enum.c b/src/ti/enum.c index cab850a9..da92bec0 100644 --- a/src/ti/enum.c +++ b/src/ti/enum.c @@ -728,9 +728,10 @@ ti_member_t * ti_enum_member_by_val_e( case TI_VAL_CLOSURE: case TI_VAL_ERROR: case TI_VAL_MEMBER: + case TI_VAL_ANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_TEMPLATE: break; diff --git a/src/ti/export.c b/src/ti/export.c index cdfd3fb6..0941197f 100644 --- a/src/ti/export.c +++ b/src/ti/export.c @@ -362,17 +362,6 @@ static int export__val(ti_fmt_t * fmt, ti_val_t * val) switch((ti_val_enum) val->tp) { - case TI_VAL_NAME: - case TI_VAL_STR: - return ti_fmt_ti_string(fmt, (ti_raw_t *) val); - case TI_VAL_MPDATA: - case TI_VAL_BYTES: - return buf_append_str(buf, "bytes() /* WARN: not exported */"); - case TI_VAL_REGEX: - { - ti_raw_t * pattern = ((ti_regex_t *) val)->pattern; - return buf_append(buf, (const char *) pattern->data, pattern->n); - } case TI_VAL_NIL: return buf_append_str(buf, "nil"); case TI_VAL_INT: @@ -385,6 +374,16 @@ static int export__val(ti_fmt_t * fmt, ti_val_t * val) : buf_append_str(buf, "false"); case TI_VAL_DATETIME: return buf_append_fmt(buf, "datetime(%ld)", DATETIME(val)); + case TI_VAL_NAME: + case TI_VAL_STR: + return ti_fmt_ti_string(fmt, (ti_raw_t *) val); + case TI_VAL_BYTES: + return buf_append_str(buf, "bytes() /* WARN: not exported */"); + case TI_VAL_REGEX: + { + ti_raw_t * pattern = ((ti_regex_t *) val)->pattern; + return buf_append(buf, (const char *) pattern->data, pattern->n); + } case TI_VAL_THING: return export__thing(fmt, (ti_thing_t *) val); case TI_VAL_WRAP: @@ -428,34 +427,38 @@ static int export__val(ti_fmt_t * fmt, ti_val_t * val) buf_write(buf, ')') ); } - case TI_VAL_CLOSURE: - return ti_fmt_nd(fmt, ((ti_closure_t * ) val)->node); - case TI_VAL_FUTURE: - return buf_append_str(buf, "future(||nil) /* WARN: not exported */"); - case TI_VAL_MODULE: + case TI_VAL_ERROR: + return buf_append_str(buf, "error() /* WARN: not exported */"); + case TI_VAL_MEMBER: { - ti_module_t * module = (ti_module_t *) val; + ti_member_t * member = (ti_member_t *) val; return buf_append_fmt( buf, - "%.*s /* WARN: module must be installed */", - module->name->n, module->name->str); + "%s{%.*s}", + member->enum_->name, + member->name->n, member->name->str); } + case TI_VAL_MPDATA: + return buf_append_str(buf, "bytes() /* WARN: not exported */"); + case TI_VAL_CLOSURE: + return ti_fmt_nd(fmt, ((ti_closure_t * ) val)->node); case TI_VAL_ANO: return -( buf_write(buf, '&') || export__thing(fmt, (ti_thing_t *) val) ); - case TI_VAL_ERROR: - return buf_append_str(buf, "error() /* WARN: not exported */"); - case TI_VAL_MEMBER: + case TI_VAL_FUTURE: + return buf_append_str(buf, "future(||nil) /* WARN: not exported */"); + case TI_VAL_MODULE: { - ti_member_t * member = (ti_member_t *) val; + ti_module_t * module = (ti_module_t *) val; return buf_append_fmt( buf, - "%s{%.*s}", - member->enum_->name, - member->name->n, member->name->str); + "%.*s /* WARN: module must be installed */", + module->name->n, module->name->str); } + case TI_VAL_WANO: + return buf_append_str(buf, "&{}.wrap() /* WARN: not exported */"); case TI_VAL_TEMPLATE: assert(0); } @@ -498,12 +501,13 @@ static int export__set_enum_cb(ti_enum_t * enum_, ti_fmt_t * fmt) case TI_VAL_TASK: case TI_VAL_ARR: case TI_VAL_SET: - case TI_VAL_CLOSURE: case TI_VAL_ERROR: case TI_VAL_MEMBER: + case TI_VAL_CLOSURE: + case TI_VAL_ANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_TEMPLATE: assert(0); break; diff --git a/src/ti/field.c b/src/ti/field.c index 31362f8b..53512bfa 100644 --- a/src/ti/field.c +++ b/src/ti/field.c @@ -247,11 +247,6 @@ static ti_val_t * field__dval_room(ti_field_t * field) return (ti_val_t *) ti_room_create(0, field->type->types->collection); } -static ti_val_t * field__dval_ano(ti_field_t * UNUSED(field)) -{ - return ti_val_default_ano(); -} - static ti_val_t * field__dval_task(ti_field_t * UNUSED(field)) { return (ti_val_t *) ti_vtask_nil(); @@ -398,7 +393,6 @@ ti_field_map_t field__mapping[TOTAL_KEYWORDS] = { {.name="email", .spec=TI_SPEC_EMAIL, .dval_cb=field__dval_str}, {.name="url", .spec=TI_SPEC_URL, .dval_cb=field__dval_str}, {.name="tel", .spec=TI_SPEC_TEL, .dval_cb=field__dval_str}, - {.name="ano", .spec=TI_SPEC_ANO, .dval_cb=field__dval_ano}, }; static ti_field_map_t * field__map[MAX_HASH_VALUE+1]; @@ -1844,10 +1838,12 @@ int ti_field_make_assignable( break; case TI_VAL_CLOSURE: return ti_closure_unbound((ti_closure_t *) *val, e); + case TI_VAL_ANO: + break; case TI_VAL_FUTURE: case TI_VAL_MODULE: - goto future_module_error; - case TI_VAL_ANO: + case TI_VAL_WANO: + goto future_module_wano_error; case TI_VAL_TEMPLATE: break; } @@ -1964,10 +1960,6 @@ int ti_field_make_assignable( (ti_raw_t *) *val)) goto tel_error; return 0; - case TI_SPEC_ANO: - if (ti_val_is_ano(*val)) - return 0; - goto type_error; case TI_SPEC_ARR: if (ti_val_is_array(*val)) return field__varr_assign(field, (ti_varr_t **) val, parent, e); @@ -2028,11 +2020,11 @@ int ti_field_make_assignable( goto type_error; -future_module_error: +future_module_wano_error: ex_set(e, EX_TYPE_ERROR, "mismatch in type `%s`; " "property `%s` allows `any` type with the exception " - "of the `future` and `module` type", + "of the `future`, `module` or `` type", field->type->name, field->name->str); return e->nr; @@ -2273,8 +2265,6 @@ _Bool ti_field_maps_to_val(ti_field_t * field, ti_val_t * val) return ti_val_is_str(val) && ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val); - case TI_SPEC_ANO: - return ti_val_is_ano(val); case TI_SPEC_ARR: /* we can map a set to an array */ return (( @@ -2398,7 +2388,6 @@ static _Bool field__maps_to_nested(ti_field_t * t_field, ti_field_t * f_field) case TI_SPEC_EMAIL: case TI_SPEC_URL: case TI_SPEC_TEL: - case TI_SPEC_ANO: case TI_SPEC_ARR: case TI_SPEC_SET: case TI_SPEC_REMATCH: @@ -2523,7 +2512,6 @@ _Bool ti_field_maps_to_field(ti_field_t * t_field, ti_field_t * f_field) case TI_SPEC_EMAIL: case TI_SPEC_URL: case TI_SPEC_TEL: - case TI_SPEC_ANO: return f_spec == t_spec; case TI_SPEC_ARR: return ( diff --git a/src/ti/index.c b/src/ti/index.c index 32cb5923..3e38de1c 100644 --- a/src/ti/index.c +++ b/src/ti/index.c @@ -673,9 +673,10 @@ int ti_index(ti_query_t * query, cleri_node_t * nd, ex_t * e) case TI_VAL_MEMBER: case TI_VAL_MPDATA: case TI_VAL_CLOSURE: + case TI_VAL_ANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_ANO: + case TI_VAL_WANO: if (do_slice) goto slice_error; goto index_error; diff --git a/src/ti/query.c b/src/ti/query.c index b19e74ce..5ad052a2 100644 --- a/src/ti/query.c +++ b/src/ti/query.c @@ -1491,11 +1491,14 @@ static int query__get_things(ti_val_t * val, imap_t * imap) case TI_VAL_MEMBER: /* things as a member have an id */ case TI_VAL_MPDATA: case TI_VAL_CLOSURE: + case TI_VAL_ANO: break; case TI_VAL_FUTURE: return VFUT(val) ? query__get_things(VFUT(val), imap) : 0; case TI_VAL_MODULE: - case TI_VAL_ANO: + break; + case TI_VAL_WANO: + return query__var_walk_thing(((ti_wano_t *) val)->thing, imap); case TI_VAL_TEMPLATE: break; } diff --git a/src/ti/spec.c b/src/ti/spec.c index 8e8ba627..f300b14f 100644 --- a/src/ti/spec.c +++ b/src/ti/spec.c @@ -408,8 +408,6 @@ ti_spec_rval_enum ti__spec_check_nested_val(uint16_t spec, ti_val_t * val) : ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val) ? 0 : TI_SPEC_RVAL_TEL_ERROR; - case TI_SPEC_ANO: - return ti_val_is_ano(val) ? 0 : TI_SPEC_RVAL_TYPE_ERROR; case TI_SPEC_REMATCH: case TI_SPEC_INT_RANGE: case TI_SPEC_FLOAT_RANGE: @@ -506,8 +504,6 @@ _Bool ti__spec_maps_to_nested_val(uint16_t spec, ti_val_t * val) return ti_val_is_str(val) && ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val); - case TI_SPEC_ANO: - return ti_val_is_ano(val); case TI_SPEC_REMATCH: case TI_SPEC_INT_RANGE: case TI_SPEC_FLOAT_RANGE: @@ -560,7 +556,6 @@ const char * ti_spec_approx_type_str(uint16_t spec) case TI_SPEC_EMAIL: return "email"; case TI_SPEC_URL: return "url"; case TI_SPEC_TEL: return "tel"; - case TI_SPEC_ANO: return "ano"; case TI_SPEC_TYPE: case TI_SPEC_ARR_TYPE: assert(0); /* not possible for wrap-only */ @@ -677,7 +672,6 @@ ti_spec_mod_enum ti_spec_check_mod( case TI_SPEC_EMAIL: case TI_SPEC_URL: case TI_SPEC_TEL: - case TI_SPEC_ANO: return ospec == nspec ? TI_SPEC_MOD_SUCCESS : TI_SPEC_MOD_ERR; case TI_SPEC_REMATCH: return TI_SPEC_MOD_ERR; diff --git a/src/ti/thing.c b/src/ti/thing.c index e2b76ca7..fca0e8a3 100644 --- a/src/ti/thing.c +++ b/src/ti/thing.c @@ -456,6 +456,7 @@ int ti_thing_p_prop_add_assign( break; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: val = (ti_val_t *) ti_nil_get(); break; case TI_VAL_TEMPLATE: @@ -558,6 +559,7 @@ int ti_thing_i_item_add_assign( break; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: val = (ti_val_t *) ti_nil_get(); break; case TI_VAL_TEMPLATE: diff --git a/src/ti/type.c b/src/ti/type.c index 56320be1..c734d52f 100644 --- a/src/ti/type.c +++ b/src/ti/type.c @@ -108,7 +108,8 @@ ti_type_t * ti_type_create_anonymous( type->type_id = TI_SPEC_TYPE; type->flags = TI_TYPE_FLAG_WRAP_ONLY|flags; type->name = strndup((const char *) name->data, name->n); - type->rname = ti_grab(name); /* name must be equal to the master type; + type->rname = ti_grab(name); /* for nested structure, name must be equal + to the master type; in fields.c, this is compared for circular references */ type->wname = NULL; @@ -396,8 +397,19 @@ static int type__init_type_cb(ti_item_t * item, ex_t * e) return e->nr; } -ti_raw_t * ti_type_spec_raw_from_thing(ti_thing_t * thing, ex_t * e) +ti_raw_t * ti_type_spec_raw_from_thing( + ti_thing_t * thing, + ti_val_t * val, + ex_t * e) { + ti_raw_t * spec_raw = NULL; + msgpack_sbuffer buffer; + ti_vp_t vp = { + .query=NULL, + .size_limit=0x4000, /* we do not expect much and since we use deep + nesting, set a low size limit */ + }; + if (ti_thing_is_dict(thing) && smap_values(thing->items.smap, (smap_val_cb) type__init_type_cb, e)) return NULL; @@ -431,13 +443,6 @@ ti_raw_t * ti_type_spec_raw_from_thing(ti_thing_t * thing, ex_t * e) ti_raw_t * ti__type_nested_from_val(ti_type_t * type, ti_val_t * val, ex_t * e) { ti_thing_t * thing; - ti_raw_t * spec_raw = NULL; - msgpack_sbuffer buffer; - ti_vp_t vp = { - .query=NULL, - .size_limit=0x4000, /* we do not expect much and since we use deep - nesting, set a low size limit */ - }; if (ti_val_is_array(val)) { @@ -475,7 +480,7 @@ ti_raw_t * ti__type_nested_from_val(ti_type_t * type, ti_val_t * val, ex_t * e) type->name); return NULL; } - return ti_type_spec_raw_from_thing(thing, e); + return ti_type_spec_raw_from_thing(thing, val, e); } static inline int type__assign( diff --git a/src/ti/val.c b/src/ti/val.c index 14ed3046..8eeb0007 100644 --- a/src/ti/val.c +++ b/src/ti/val.c @@ -48,9 +48,9 @@ static ti_val_t * val__empty_bin; static ti_val_t * val__empty_str; static ti_val_t * val__default_closure; -static ti_val_t * val__default_ano; static ti_val_t * val__default_re; static ti_val_t * val__sano; +static ti_val_t * val__swano; static ti_val_t * val__sbool; static ti_val_t * val__sbytes; static ti_val_t * val__sclosure; @@ -469,6 +469,7 @@ static int val__push(ti_varr_t * varr, ti_val_t * val, ex_t * e) break; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: case TI_VAL_TEMPLATE: assert(0); return e->nr; @@ -715,13 +716,10 @@ ti_val_t * ti_val_from_vup_e(ti_vup_t * vup, ex_t * e) ano = ti_ano_create( vup->collection, obj.via.ext.data, - obj.via.ext.n); + obj.via.ext.n, + e); if (!ano) - { - ex_set(e, EX_BAD_DATA, - "failed to unpack `anonymous`"); return NULL; - } return (ti_val_t *) ano; } } @@ -745,8 +743,6 @@ int ti_val_init_common(void) }; val__default_closure = \ (ti_val_t *) ti_closure_from_strn(&syntax, "||nil", 5, &e); - val__default_ano = \ - (ti_val_t *) ti_ano_create(&syntax, "\x80", 1, &e); val__empty_bin = (ti_val_t *) ti_bin_create(NULL, 0); val__empty_str = (ti_val_t *) ti_str_from_str(""); val__default_re = (ti_val_t *) ti_regex_from_strn("/.*/", 4, &e); @@ -755,6 +751,7 @@ int ti_val_init_common(void) val__strue = (ti_val_t *) ti_str_from_str("true"); val__sfalse = (ti_val_t *) ti_str_from_str("false"); val__sano = (ti_val_t *) ti_str_from_str(TI_VAL_ANO_S); + val__swano = (ti_val_t *) ti_str_from_str(TI_VAL_WANO_S); val__sbool = (ti_val_t *) ti_str_from_str(TI_VAL_BOOL_S); val__sdatetime = (ti_val_t *) ti_str_from_str(TI_VAL_DATETIME_S); val__stimeval = (ti_val_t *) ti_str_from_str(TI_VAL_TIMEVAL_S); @@ -823,7 +820,7 @@ int ti_val_init_common(void) !val__key_name || !val__key_type_name || !val__flags_name || !val__data_name || !val__time_name || !val__re_email || !val__smodule || !val__re_url || !val__re_tel || !val__async_name || - !val__anonymous_name || !val__default_ano || !val__sano) + !val__anonymous_name || !val__sano || !val__swano) { return -1; } @@ -835,13 +832,13 @@ void ti_val_drop_common(void) ti_val_drop(val__empty_bin); ti_val_drop(val__empty_str); ti_val_drop(val__default_closure); - ti_val_drop(val__default_ano); ti_val_drop(val__default_re); ti_val_drop(val__sany); ti_val_drop(val__snil); ti_val_drop(val__strue); ti_val_drop(val__sfalse); ti_val_drop(val__sano); + ti_val_drop(val__swano); ti_val_drop(val__sbool); ti_val_drop(val__sdatetime); ti_val_drop(val__stimeval); @@ -924,12 +921,6 @@ ti_val_t * ti_val_default_closure(void) return val__default_closure; } -ti_val_t * ti_val_default_ano(void) -{ - ti_incref(val__default_ano); - return val__default_ano; -} - ti_val_t * ti_val_charset_str(void) { ti_incref(val__charset_str); @@ -1022,7 +1013,7 @@ int ti_val_convert_to_bytes(ti_val_t ** val, ex_t * e) { case TI_VAL_NAME: case TI_VAL_STR: - case TI_VAL_MPDATA: + case TI_VAL_MPDATA: /* allow mpdata, issue #427 */ { ti_raw_t * r = (ti_raw_t *) (*val); if (r->ref == 1 && r->tp != TI_VAL_NAME) @@ -1054,9 +1045,10 @@ int ti_val_convert_to_bytes(ti_val_t ** val, ex_t * e) case TI_VAL_ARR: case TI_VAL_SET: case TI_VAL_CLOSURE: + case TI_VAL_ANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_ERROR: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_BYTES_S"`", @@ -1085,23 +1077,6 @@ int ti_val_convert_to_int(ti_val_t ** val, ex_t * e) int64_t i = 0; switch((ti_val_enum) (*val)->tp) { - case TI_VAL_NIL: - case TI_VAL_REGEX: - case TI_VAL_THING: - case TI_VAL_WRAP: - case TI_VAL_ROOM: - case TI_VAL_TASK: - case TI_VAL_ARR: - 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, - "cannot convert type `%s` to `"TI_VAL_INT_S"`", - ti_val_str(*val)); - return e->nr; case TI_VAL_INT: return 0; case TI_VAL_FLOAT: @@ -1162,6 +1137,25 @@ int ti_val_convert_to_int(ti_val_t ** val, ex_t * e) *val = v; return 0; } + case TI_VAL_NIL: + case TI_VAL_REGEX: + case TI_VAL_THING: + case TI_VAL_WRAP: + case TI_VAL_ROOM: + case TI_VAL_TASK: + case TI_VAL_ARR: + case TI_VAL_SET: + case TI_VAL_CLOSURE: + case TI_VAL_ANO: + case TI_VAL_FUTURE: + case TI_VAL_MODULE: + case TI_VAL_WANO: + case TI_VAL_MPDATA: + case TI_VAL_BYTES: + ex_set(e, EX_TYPE_ERROR, + "cannot convert type `%s` to `"TI_VAL_INT_S"`", + ti_val_str(*val)); + return e->nr; case TI_VAL_TEMPLATE: assert(0); } @@ -1181,23 +1175,6 @@ int ti_val_convert_to_float(ti_val_t ** val, ex_t * e) double d = 0.0; switch((ti_val_enum) (*val)->tp) { - case TI_VAL_NIL: - case TI_VAL_REGEX: - case TI_VAL_THING: - case TI_VAL_WRAP: - case TI_VAL_ROOM: - case TI_VAL_TASK: - case TI_VAL_ARR: - 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, - "cannot convert type `%s` to `"TI_VAL_FLOAT_S"`", - ti_val_str(*val)); - return e->nr; case TI_VAL_INT: d = (double) VINT(*val); break; @@ -1259,6 +1236,25 @@ int ti_val_convert_to_float(ti_val_t ** val, ex_t * e) *val = v; return 0; } + case TI_VAL_NIL: + case TI_VAL_REGEX: + case TI_VAL_THING: + case TI_VAL_WRAP: + case TI_VAL_ROOM: + case TI_VAL_TASK: + case TI_VAL_ARR: + case TI_VAL_SET: + case TI_VAL_CLOSURE: + case TI_VAL_ANO: + case TI_VAL_FUTURE: + case TI_VAL_MODULE: + case TI_VAL_WANO: + case TI_VAL_MPDATA: + case TI_VAL_BYTES: + ex_set(e, EX_TYPE_ERROR, + "cannot convert type `%s` to `"TI_VAL_FLOAT_S"`", + ti_val_str(*val)); + return e->nr; case TI_VAL_TEMPLATE: assert(0); } @@ -1292,12 +1288,14 @@ int ti_val_convert_to_array(ti_val_t ** val, ex_t * e) case TI_VAL_THING: case TI_VAL_WRAP: case TI_VAL_ROOM: + case TI_VAL_ERROR: case TI_VAL_TASK: case TI_VAL_CLOSURE: - case TI_VAL_ERROR: + case TI_VAL_ANO: case TI_VAL_MEMBER: case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_LIST_S"`", ti_val_str(*val)); @@ -1312,28 +1310,6 @@ int ti_val_convert_to_set(ti_val_t ** val, ex_t * e) { 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: - case TI_VAL_WRAP: - case TI_VAL_ROOM: - case TI_VAL_TASK: - case TI_VAL_CLOSURE: - 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)); - break; case TI_VAL_THING: { ti_vset_t * vset = ti_vset_create(); @@ -1372,6 +1348,30 @@ int ti_val_convert_to_set(ti_val_t ** val, ex_t * e) } case TI_VAL_SET: break; + 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: + case TI_VAL_WRAP: + case TI_VAL_ROOM: + case TI_VAL_TASK: + case TI_VAL_CLOSURE: + case TI_VAL_ANO: + case TI_VAL_ERROR: + case TI_VAL_MEMBER: + case TI_VAL_FUTURE: + case TI_VAL_MODULE: + case TI_VAL_WANO: + ex_set(e, EX_TYPE_ERROR, + "cannot convert type `%s` to `"TI_VAL_SET_S"`", + ti_val_str(*val)); + break; case TI_VAL_TEMPLATE: assert(0); } @@ -1412,10 +1412,18 @@ size_t ti_val_get_len(ti_val_t * val) return VSET(val)->n; case TI_VAL_CLOSURE: break; + case TI_VAL_ANO: + return ( + ((ti_ano_t *) val)->type->fields->n + + ((ti_ano_t *) val)->type->methods->n + + !!((ti_ano_t *) val)->type->idname); case TI_VAL_MEMBER: return ti_val_get_len(VMEMBER(val)); case TI_VAL_FUTURE: case TI_VAL_MODULE: + break; + case TI_VAL_WANO: + return ti_thing_n(((ti_wano_t *) val)->thing); case TI_VAL_ERROR: break; } @@ -1445,22 +1453,11 @@ int ti_val_gen_ids(ti_val_t * val) 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: - case TI_VAL_TASK: - case TI_VAL_MEMBER: - /* enum can be skipped; even a thing on an enum is guaranteed to - * have an ID since they are triggered when creating or changing the - * enumerator. - * - * task can be skipped as id's for task are created immediately on - * the creation of a task. - */ break; - case TI_VAL_THING: if (!((ti_thing_t *) val)->id) return ti_thing_gen_id((ti_thing_t *) val); @@ -1481,6 +1478,8 @@ int ti_val_gen_ids(ti_val_t * val) if (!((ti_room_t *) val)->id) return ti_room_gen_id((ti_room_t *) val); break; + case TI_VAL_TASK: + break; case TI_VAL_ARR: /* * Here the code really benefits from the `may-have-things` flag since @@ -1493,11 +1492,23 @@ int ti_val_gen_ids(ti_val_t * val) break; case TI_VAL_SET: return imap_walk(VSET(val), (imap_cb) val__walk_gen_id_set, NULL); - case TI_VAL_CLOSURE: + case TI_VAL_ERROR: + case TI_VAL_MEMBER: + /* enum can be skipped; even a thing on an enum is guaranteed to + * have an ID since they are triggered when creating or changing the + * enumerator. + * + * task can be skipped as id's for task are created immediately on + * the creation of a task. + */ + case TI_VAL_MPDATA: + case TI_VAL_CLOSURE: + case TI_VAL_ANO: break; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: case TI_VAL_TEMPLATE: assert(0); } @@ -1537,10 +1548,13 @@ _Bool ti_val_has_ids(ti_val_t * val) case TI_VAL_SET: return imap_walk(VSET(val), (imap_cb) val__walk_has_id_set, NULL); case TI_VAL_CLOSURE: + case TI_VAL_ANO: case TI_VAL_ERROR: case TI_VAL_FUTURE: case TI_VAL_MODULE: return false; + case TI_VAL_WANO: + return ti_thing_has_id(((ti_wano_t *) val)->thing); case TI_VAL_TEMPLATE: assert(0); } @@ -1574,6 +1588,8 @@ size_t ti_val_alloc_size(ti_val_t * val) return 65536; case TI_VAL_CLOSURE: return 4096; + case TI_VAL_ANO: + return ((ti_ano_t *) val)->spec_raw->n + 9; case TI_VAL_ERROR: return ((ti_verror_t *) val)->msg_n + 128; case TI_VAL_MEMBER: @@ -1582,6 +1598,8 @@ size_t ti_val_alloc_size(ti_val_t * val) return VFUT(val) ? ti_val_alloc_size(VFUT(val)) : 64; case TI_VAL_MODULE: return 64; + case TI_VAL_WANO: + return 65536; case TI_VAL_TEMPLATE: assert(0); } @@ -1601,7 +1619,6 @@ ti_val_t * ti_val_strv(ti_val_t * val) return ti_datetime_is_timeval((ti_datetime_t *) val) ? ti_grab(val__stimeval) : ti_grab(val__sdatetime); - case TI_VAL_MPDATA: return ti_grab(val__smpdata); case TI_VAL_NAME: case TI_VAL_STR: return ti_grab(val__sstr); case TI_VAL_BYTES: return ti_grab(val__sbytes); @@ -1619,13 +1636,15 @@ ti_val_t * ti_val_strv(ti_val_t * val) ? ti_grab(val__slist) : ti_grab(val__stuple); case TI_VAL_SET: return ti_grab(val__sset); - case TI_VAL_CLOSURE: return ti_grab(val__sclosure); case TI_VAL_ERROR: return ti_grab(val__serror); case TI_VAL_MEMBER: return (ti_val_t *) ti_member_enum_get_rname((ti_member_t *) val); + case TI_VAL_MPDATA: return ti_grab(val__smpdata); + case TI_VAL_CLOSURE: return ti_grab(val__sclosure); + case TI_VAL_ANO: return ti_grab(val__sano); case TI_VAL_FUTURE: return ti_grab(val__sfuture); case TI_VAL_MODULE: return ti_grab(val__smodule); - case TI_VAL_ANO: return ti_grab(val__sano); + case TI_VAL_WANO: return ti_grab(val__swano); case TI_VAL_TEMPLATE: assert(0); } @@ -1680,8 +1699,11 @@ int ti_val_copy(ti_val_t ** val, ti_thing_t * parent, void * key, uint8_t deep) ex_t e = {0}; return ti_closure_unbound((ti_closure_t * ) *val, &e); } + case TI_VAL_ANO: + return 0; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; @@ -1739,8 +1761,11 @@ int ti_val_dup(ti_val_t ** val, ti_thing_t * parent, void * key, uint8_t deep) ex_t e = {0}; return ti_closure_unbound((ti_closure_t * ) *val, &e); } + case TI_VAL_ANO: + return 0; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; @@ -1863,6 +1888,18 @@ int ti_val_wrap_to_str(ti_val_t ** val, ex_t * e) *val = v; return 0; } +int ti_val_wano_to_str(ti_val_t ** val, ex_t * e) +{ + ti_val_t * v = (ti_val_t *) ti_wano_str((ti_wano_t *) *val); + if (!v) + { + ex_set_mem(e); + return e->nr; + } + ti_val_unsafe_drop(*val); + *val = v; + return 0; +} int ti_val_room_to_str(ti_val_t ** val, ex_t * e) { ti_val_t * v = (ti_val_t *) ti_room_str((ti_room_t *) *val); diff --git a/src/ti/varr.c b/src/ti/varr.c index f41671b5..eef7cf2e 100644 --- a/src/ti/varr.c +++ b/src/ti/varr.c @@ -340,6 +340,7 @@ static int varr__copy(ti_val_t ** val, uint8_t deep) case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_CLOSURE: + case TI_VAL_ANO: return 0; case TI_VAL_THING: return ti_thing_copy((ti_thing_t **) val, deep); @@ -356,6 +357,7 @@ static int varr__copy(ti_val_t ** val, uint8_t deep) return 0; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: case TI_VAL_SET: case TI_VAL_TEMPLATE: break; @@ -383,6 +385,7 @@ static int varr__dup(ti_val_t ** val, uint8_t deep) case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_CLOSURE: + case TI_VAL_ANO: return 0; case TI_VAL_THING: return ti_thing_dup((ti_thing_t **) val, deep); @@ -399,6 +402,7 @@ static int varr__dup(ti_val_t ** val, uint8_t deep) return 0; case TI_VAL_FUTURE: case TI_VAL_MODULE: + case TI_VAL_WANO: case TI_VAL_SET: case TI_VAL_TEMPLATE: break; diff --git a/src/ti/wano.c b/src/ti/wano.c new file mode 100644 index 00000000..7489001c --- /dev/null +++ b/src/ti/wano.c @@ -0,0 +1,25 @@ +/* + * ti/wano.c + */ +#include +#include + + +ti_wano_t * ti_wano_create(ti_thing_t * thing, ti_ano_t * ano) +{ + ti_wano_t * wano = malloc(sizeof(ti_wano_t)); + if (!wano) + return NULL; + wano->ano = ano; + wano->thing = thing; + ti_incref(ano); + ti_incref(thing); + return wano; +} + +void ti_wano_destroy(ti_wano_t * wano) +{ + ti_val_unsafe_drop((ti_val_t *) wano->ano); + ti_val_unsafe_gc_drop((ti_val_t *) wano->thing); + free(wano); +} diff --git a/src/ti/wrap.c b/src/ti/wrap.c index f8aca5cb..507dd260 100644 --- a/src/ti/wrap.c +++ b/src/ti/wrap.c @@ -3,6 +3,7 @@ */ #include #include +#include #include #include #include @@ -26,13 +27,6 @@ #include #include -static int wrap__field_thing_type( - ti_thing_t * thing, - ti_vp_t * vp, - ti_type_t * t_type, - int deep, - int flags); - ti_wrap_t * ti_wrap_create(ti_thing_t * thing, uint16_t type_id) { @@ -81,7 +75,7 @@ typedef struct static int wrap__walk_with_type(ti_thing_t * thing, wrap__walk_with_type_t * w) { - return wrap__field_thing_type(thing, w->vp, w->t_type, w->deep, w->flags); + return ti_wrap_field_thing_type(thing, w->vp, w->t_type, w->deep, w->flags); } static int wrap__set( @@ -174,7 +168,7 @@ static int wrap__field_val( return ti_regex_to_client_pk((ti_regex_t *) val, &vp->pk); case TI_VAL_THING: return ((*spec & TI_SPEC_MASK_NILLABLE) == TI_SPEC_TYPE) - ? wrap__field_thing_type( + ? ti_wrap_field_thing_type( (ti_thing_t *) val, vp, t_field->condition.type, @@ -188,8 +182,8 @@ static int wrap__field_val( flags); case TI_VAL_WRAP: return ((*spec & TI_SPEC_MASK_NILLABLE) == TI_SPEC_TYPE) - ? wrap__field_thing_type( - (ti_thing_t *) val, + ? ti_wrap_field_thing_type( + ((ti_wrap_t *) val)->thing, vp, t_field->condition.type, deep, @@ -246,6 +240,8 @@ static int wrap__field_val( return ti_raw_mpdata_to_client_pk((ti_raw_t *) val, &vp->pk); case TI_VAL_CLOSURE: return ti_closure_to_client_pk((ti_closure_t *) val, &vp->pk); + case TI_VAL_ANO: + return ti_ano_to_client_pk((ti_ano_t * ) val, &vp->pk); case TI_VAL_FUTURE: return VFUT(val) ? wrap__field_val( @@ -258,6 +254,13 @@ static int wrap__field_val( : msgpack_pack_nil(&vp->pk); case TI_VAL_MODULE: return msgpack_pack_nil(&vp->pk); + case TI_VAL_WANO: + return ti_wrap_field_thing_type( + ((ti_wano_t *) val)->thing, + vp, + ((ti_wano_t *) val)->ano->type, + deep, + flags); case TI_VAL_TEMPLATE: break; } @@ -595,7 +598,7 @@ static int wrap__field_thing( return -1; } -static int wrap__field_thing_type( +int ti_wrap_field_thing_type( ti_thing_t * thing, ti_vp_t * vp, ti_type_t * t_type, From 2a972a04ad5c3dbe7fd31921d7a39fe067faa796 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Fri, 7 Nov 2025 21:02:21 +0100 Subject: [PATCH 03/13] Work on ano type --- CHANGELOG.md | 3 ++- inc/ti/fn/fn.h | 2 +- inc/ti/val.inline.h | 7 +++++++ itest/test_advanced.py | 7 ++++--- itest/test_ano.py | 19 +++++++++++++------ itest/test_wrap_tree.py | 2 +- src/ti/field.c | 2 +- src/ti/wano.c | 2 ++ 8 files changed, 31 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fda64dec..5afb60c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # v1.8.2-alpha0 * Allow converting `mpdata` to `bytes, issue #427. - +* Add _anonymous_ wrap only type syntax (`&{..}`), pr +* Added `ano()` function, pr #405. # v1.8.1 diff --git a/inc/ti/fn/fn.h b/inc/ti/fn/fn.h index d3b779fd..0c1f44ab 100644 --- a/inc/ti/fn/fn.h +++ b/inc/ti/fn/fn.h @@ -254,7 +254,7 @@ static inline int fn_arg_str_or_ano( ti_val_t * val, ex_t * e) { - if (!ti_val_is_str(val)) + if (!ti_val_is_str_ano(val)) ex_set(e, EX_TYPE_ERROR, "function `%s` expects argument %d to be of " "type `"TI_VAL_STR_S"` or `"TI_VAL_ANO_S"` " diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index dbfae511..4e37d76f 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -774,6 +774,13 @@ static inline _Bool ti_val_is_str_nil(ti_val_t * val) val->tp == TI_VAL_NIL; } +static inline _Bool ti_val_is_str_ano(ti_val_t * val) +{ + return val->tp == TI_VAL_STR || + val->tp == TI_VAL_NAME || + val->tp == TI_VAL_ANO; +} + static inline _Bool ti_val_is_str_regex(ti_val_t * val) { return val->tp == TI_VAL_STR || diff --git a/itest/test_advanced.py b/itest/test_advanced.py index 2d791fcb..bad14e1c 100755 --- a/itest/test_advanced.py +++ b/itest/test_advanced.py @@ -1873,15 +1873,16 @@ async def test_closure_as_type_val(self, client): thing({id}).func(); // requires a change """) - async def test_future_to_type(self, client): + async def test_future_or_wrap_ano_to_type(self, client): await client.query(r"""//ti set_type('A', {x: 'any'}); """) with self.assertRaisesRegex( TypeError, - r'mismatch in type `A`; property `x` allows `any` type ' - r"with the exception of the `future` and `module` type"): + r'mismatch in type `A`; property `x` allows `any` type with ' + r'the exception of the `future`, `module` ' + r'and `` type'): await client.query("""//ti A{ x: future(||nil) diff --git a/itest/test_ano.py b/itest/test_ano.py index b479d2ad..8a65920d 100755 --- a/itest/test_ano.py +++ b/itest/test_ano.py @@ -29,18 +29,25 @@ async def async_run(self): client = await get_client(self.node0) client.set_default_scope('//stuff') - await self.run_tests(client) + await self.run_tests(client.query) client.close() await client.wait_closed() - async def test_ano_err(self, client): + async def test_ano_err(self, q): + await q(r"""//ti + set_type('A', {x: 'any'}); + """) with self.assertRaisesRegex( - ValueError, - r'xxx'): - await client.query("""//ti - ... + TypeError, + r'mismatch in type `A`; property `x` allows `any` type with ' + r'the exception of the `future`, `module` ' + r'and `` type'): + await q("""//ti + A{ + x: {}.wrap(&{}) + }; """) # TODO : test len(ano type) diff --git a/itest/test_wrap_tree.py b/itest/test_wrap_tree.py index 31e4dcae..7213a2d3 100755 --- a/itest/test_wrap_tree.py +++ b/itest/test_wrap_tree.py @@ -96,7 +96,7 @@ async def test_define_err(self, client): with self.assertRaisesRegex( ValueError, - r'nested type definition on type `W` too large'): + r'wpo type definition too large'): await client.query("""//ti nested = {}; range(2000).map(|x| {nested[`key{x}`] = {x: 'int'}}); diff --git a/src/ti/field.c b/src/ti/field.c index 53512bfa..c1d899e9 100644 --- a/src/ti/field.c +++ b/src/ti/field.c @@ -2024,7 +2024,7 @@ int ti_field_make_assignable( ex_set(e, EX_TYPE_ERROR, "mismatch in type `%s`; " "property `%s` allows `any` type with the exception " - "of the `future`, `module` or `` type", + "of the `future`, `module` and `` type", field->type->name, field->name->str); return e->nr; diff --git a/src/ti/wano.c b/src/ti/wano.c index 7489001c..0ebeb98b 100644 --- a/src/ti/wano.c +++ b/src/ti/wano.c @@ -10,6 +10,8 @@ ti_wano_t * ti_wano_create(ti_thing_t * thing, ti_ano_t * ano) ti_wano_t * wano = malloc(sizeof(ti_wano_t)); if (!wano) return NULL; + wano->ref = 1; + wano->tp = TI_VAL_WANO; wano->ano = ano; wano->thing = thing; ti_incref(ano); From 78b61624b27a033014f8dc3f923e863266cd4c24 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Sat, 8 Nov 2025 16:35:51 +0100 Subject: [PATCH 04/13] work on ano --- inc/doc.inline.h | 2 + inc/ti/ano.h | 2 +- inc/ti/collection.t.h | 1 + inc/ti/fn/fn.h | 3 +- inc/ti/fn/fnano.h | 16 ++++- inc/ti/fn/fnclosure.h | 2 +- inc/ti/fn/fncopy.h | 5 +- inc/ti/fn/fndup.h | 3 +- inc/ti/fn/fnid.h | 22 +++++++ inc/ti/fn/fnmapid.h | 5 ++ inc/ti/fn/fnmapwrap.h | 3 +- inc/ti/fn/fnsearch.h | 4 +- inc/ti/fn/fnunwrap.h | 6 +- inc/ti/fn/fnwrap.h | 2 +- inc/ti/forloop.h | 2 +- inc/ti/opr/oprinc.h | 70 ++++++++++++++++++++- inc/ti/val.inline.h | 34 +++++++---- inc/ti/val.t.h | 10 +-- inc/ti/wano.h | 2 + inc/ti/wano.inline.h | 11 ++++ inc/ti/wano.t.h | 2 +- inc/ti/wrap.h | 2 +- itest/test_advanced.py | 3 +- itest/test_ano.py | 136 +++++++++++++++++++++++++++++++++++++++-- src/ti/ano.c | 29 +++++++-- src/ti/collection.c | 11 +++- src/ti/do.c | 3 +- src/ti/enum.c | 2 +- src/ti/export.c | 4 +- src/ti/field.c | 8 +-- src/ti/index.c | 2 +- src/ti/opr.c | 10 +++ src/ti/query.c | 4 +- src/ti/thing.c | 4 +- src/ti/val.c | 101 +++++++++++++++++++++++------- src/ti/varr.c | 6 +- src/ti/wano.c | 35 +++++++++++ src/ti/wrap.c | 27 ++++---- 38 files changed, 495 insertions(+), 99 deletions(-) diff --git a/inc/doc.inline.h b/inc/doc.inline.h index 9059226c..d0bb3db5 100644 --- a/inc/doc.inline.h +++ b/inc/doc.inline.h @@ -145,6 +145,7 @@ static inline const char * doc_copy(ti_val_t * val) case TI_VAL_WRAP: return DOC_WTYPE_COPY; case TI_VAL_ARR: return DOC_LIST_COPY; case TI_VAL_SET: return DOC_SET_COPY; + case TI_VAL_WANO: return DOC_WTYPE_COPY; default: return NULL; } } @@ -157,6 +158,7 @@ static inline const char * doc_dup(ti_val_t * val) case TI_VAL_WRAP: return DOC_WTYPE_DUP; case TI_VAL_ARR: return DOC_LIST_DUP; case TI_VAL_SET: return DOC_SET_DUP; + case TI_VAL_WANO: return DOC_WTYPE_DUP; default: return NULL; } } diff --git a/inc/ti/ano.h b/inc/ti/ano.h index 9390e306..d899a16b 100644 --- a/inc/ti/ano.h +++ b/inc/ti/ano.h @@ -38,7 +38,7 @@ static inline int ti_ano_to_client_pk( static inline _Bool ti_ano_uninitialized(ti_ano_t * ano) { - return !!ano->spec_raw; + return !ano->spec_raw; } static inline int ti_ano_to_store_pk( diff --git a/inc/ti/collection.t.h b/inc/ti/collection.t.h index 994d5b54..11e78147 100644 --- a/inc/ti/collection.t.h +++ b/inc/ti/collection.t.h @@ -34,6 +34,7 @@ struct ti_collection_s vec_t * access; /* ti_auth_t */ smap_t * procedures; /* ti_procedure_t */ smap_t * named_rooms; /* weak map for ti_room_t (only named rooms) */ + smap_t * ano_types; /* weak map for ti_ano_t */ ti_thing_t * root; /* without extra reference */ ti_types_t * types; ti_enums_t * enums; diff --git a/inc/ti/fn/fn.h b/inc/ti/fn/fn.h index 0c1f44ab..1507b58f 100644 --- a/inc/ti/fn/fn.h +++ b/inc/ti/fn/fn.h @@ -247,7 +247,7 @@ static inline int fn_arg_str( return e->nr; } -static inline int fn_arg_str_or_ano( +static inline int fn_arg_str_ano( const char * name, const char * doc, int argn, @@ -736,7 +736,6 @@ static int fn_call_a_try_n( ti_incref(method->closure); ti_val_unsafe_drop(query->rval); query->rval = (ti_val_t *) method->closure; - // TODO: ANO: test return fn_call(query, nd, e); no_method_err: diff --git a/inc/ti/fn/fnano.h b/inc/ti/fn/fnano.h index cca80cef..cc7c1e45 100644 --- a/inc/ti/fn/fnano.h +++ b/inc/ti/fn/fnano.h @@ -19,8 +19,20 @@ static int do__f_ano(ti_query_t * query, cleri_node_t * nd, ex_t * e) return e->nr; ti_val_unsafe_drop(query->rval); - query->rval = (ti_val_t *) ti_ano_from_raw(query->collection, spec_raw, e); - ti_val_unsafe_drop((ti_val_t *) spec_raw); + /* first try cache for equal ano */ + query->rval = smap_getn( + query->collection->ano_types, + (const char *) spec_raw->data, + spec_raw->n); + + /* if no success, try new one */ + if (!query->rval) + query->rval = (ti_val_t *) ti_ano_from_raw( + query->collection, + spec_raw, + e); + + ti_val_unsafe_drop((ti_val_t *) spec_raw); return e->nr; } diff --git a/inc/ti/fn/fnclosure.h b/inc/ti/fn/fnclosure.h index 00bb8a0a..699ee241 100644 --- a/inc/ti/fn/fnclosure.h +++ b/inc/ti/fn/fnclosure.h @@ -63,9 +63,9 @@ 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_ANO: + case TI_VAL_WANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_CLOSURE_S"`", ti_val_str(query->rval)); diff --git a/inc/ti/fn/fncopy.h b/inc/ti/fn/fncopy.h index 97e9c5b9..16dcacf4 100644 --- a/inc/ti/fn/fncopy.h +++ b/inc/ti/fn/fncopy.h @@ -5,7 +5,8 @@ static int do__f_copy(ti_query_t * query, cleri_node_t * nd, ex_t * e) const char * doc; const int nargs = fn_get_nargs(nd); ti_val_t * val; - uint8_t deep = !(query->rval->tp & 0x4); /* THING/WRAP: 1, ARR/SET: 0 */ + /* use deep value of 0 for arr and set, 1 for thing, wrap, wano */ + uint8_t deep = !(ti_val_is_arr(query->rval) || ti_val_is_set(query->rval)); doc = doc_copy(query->rval); if (!doc) @@ -27,7 +28,7 @@ static int do__f_copy(ti_query_t * query, cleri_node_t * nd, ex_t * e) query->rval = val; } - if (ti_val_is_wrap(query->rval) && ti_wrap_cp(query, deep, e)) + if (ti_val_is_wrap_wano(query->rval) && ti_wrap_cp(query, deep, e)) return e->nr; /* quit without fail0, e is set*/ else if (ti_val_copy(&query->rval, NULL, NULL, deep)) ex_set_mem(e); diff --git a/inc/ti/fn/fndup.h b/inc/ti/fn/fndup.h index b16285a7..2e1b05b6 100644 --- a/inc/ti/fn/fndup.h +++ b/inc/ti/fn/fndup.h @@ -5,7 +5,8 @@ static int do__f_dup(ti_query_t * query, cleri_node_t * nd, ex_t * e) const char * doc; const int nargs = fn_get_nargs(nd); ti_val_t * val; - uint8_t deep = !(query->rval->tp & 0x4); /* THING/WRAP: 1, ARR/SET: 0 */ + /* use deep value of 0 for arr and set, 1 for thing, wrap, wano */ + uint8_t deep = !(ti_val_is_arr(query->rval) || ti_val_is_set(query->rval)); doc = doc_dup(query->rval); if (!doc) diff --git a/inc/ti/fn/fnid.h b/inc/ti/fn/fnid.h index 04db515a..98eb32f8 100644 --- a/inc/ti/fn/fnid.h +++ b/inc/ti/fn/fnid.h @@ -61,6 +61,26 @@ static int do__f_id_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) return e->nr; } +static int do__f_id_wano(ti_query_t * query, cleri_node_t * nd, ex_t * e) +{ + const int nargs = fn_get_nargs(nd); + ti_wano_t * wtype; + + if (fn_nargs("id", DOC_WTYPE_ID, 0, nargs, e)) + return e->nr; + + wtype = (ti_wano_t *) query->rval; + query->rval = wtype->thing->id + ? (ti_val_t *) ti_vint_create((int64_t) wtype->thing->id) + : (ti_val_t *) ti_nil_get(); + + if (!query->rval) + ex_set_mem(e); + + ti_val_unsafe_drop((ti_val_t *) wtype); + return e->nr; +} + static int do__f_id_task(ti_query_t * query, cleri_node_t * nd, ex_t * e) { const int nargs = fn_get_nargs(nd); @@ -89,6 +109,8 @@ static inline int do__f_id(ti_query_t * query, cleri_node_t * nd, ex_t * e) ? do__f_id_room(query, nd, e) : ti_val_is_wrap(query->rval) ? do__f_id_wrap(query, nd, e) + : ti_val_is_wano(query->rval) + ? do__f_id_wano(query, nd, e) : ti_val_is_task(query->rval) ? do__f_id_task(query, nd, e) : fn_call_try("id", query, nd, e); diff --git a/inc/ti/fn/fnmapid.h b/inc/ti/fn/fnmapid.h index 6edff9ff..55450e21 100644 --- a/inc/ti/fn/fnmapid.h +++ b/inc/ti/fn/fnmapid.h @@ -47,6 +47,11 @@ static int do__f_map_id(ti_query_t * query, cleri_node_t * nd, ex_t * e) ti_wrap_t * wtype = (ti_wrap_t *) val; id = wtype->thing->id; } + else if (ti_val_is_wano(val)) + { + ti_wano_t * wtype = (ti_wano_t *) val; + id = wtype->thing->id; + } else if (ti_val_is_room(val)) { ti_room_t * room = (ti_room_t *) val; diff --git a/inc/ti/fn/fnmapwrap.h b/inc/ti/fn/fnmapwrap.h index 52d45c24..96954c78 100644 --- a/inc/ti/fn/fnmapwrap.h +++ b/inc/ti/fn/fnmapwrap.h @@ -67,7 +67,7 @@ static int do__f_map_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) if (nargs == 1) { if (ti_do_statement(query, nd->children, e) || - fn_arg_str_or_ano("map_wrap", doc, 1, query->rval, e)) + fn_arg_str_ano("map_wrap", doc, 1, query->rval, e)) goto fail0; if (ti_val_is_ano(query->rval)) @@ -162,6 +162,7 @@ static int do__f_map_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) ti_val_unsafe_drop(iterable); query->rval = (ti_val_t *) varr; + ti_val_drop((ti_val_t *) ano); return e->nr; fail1: diff --git a/inc/ti/fn/fnsearch.h b/inc/ti/fn/fnsearch.h index d03cacbd..61df6e7b 100644 --- a/inc/ti/fn/fnsearch.h +++ b/inc/ti/fn/fnsearch.h @@ -203,11 +203,11 @@ static int do__search_thing( return imap_walk(VSET(val), (imap_cb) search__walk_set, &ws); } case TI_VAL_ANO: - case TI_VAL_FUTURE: - case TI_VAL_MODULE: return 0; case TI_VAL_WANO: return search__do_thing(((ti_wano_t *) val)->thing, root, key, w); + case TI_VAL_FUTURE: + case TI_VAL_MODULE: case TI_VAL_TEMPLATE: return 0; } diff --git a/inc/ti/fn/fnunwrap.h b/inc/ti/fn/fnunwrap.h index 4f2a277c..45ef3cbf 100644 --- a/inc/ti/fn/fnunwrap.h +++ b/inc/ti/fn/fnunwrap.h @@ -5,13 +5,15 @@ static int do__f_unwrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) const int nargs = fn_get_nargs(nd); ti_thing_t * thing; - if (!ti_val_is_wrap(query->rval)) + if (!ti_val_is_wrap_wano(query->rval)) return fn_call_try("unwrap", query, nd, e); if (fn_nargs("unwrap", DOC_WTYPE_UNWRAP, 0, nargs, e)) return e->nr; - thing = ((ti_wrap_t *) query->rval)->thing; + thing = ti_val_is_wrap(query->rval) + ? ((ti_wrap_t *) query->rval)->thing + : ((ti_wano_t *) query->rval)->thing; ti_incref(thing); ti_val_unsafe_drop(query->rval); query->rval = (ti_val_t *) thing; diff --git a/inc/ti/fn/fnwrap.h b/inc/ti/fn/fnwrap.h index e73db991..c601aed4 100644 --- a/inc/ti/fn/fnwrap.h +++ b/inc/ti/fn/fnwrap.h @@ -18,7 +18,7 @@ static int do__f_wrap(ti_query_t * query, cleri_node_t * nd, ex_t * e) if (nargs == 1) { if (ti_do_statement(query, nd->children, e) || - fn_arg_str_or_ano("wrap", DOC_THING_WRAP, 1, query->rval, e)) + fn_arg_str_ano("wrap", DOC_THING_WRAP, 1, query->rval, e)) goto fail0; if (ti_val_is_ano(query->rval)) diff --git a/inc/ti/forloop.h b/inc/ti/forloop.h index 4611b039..5e899ab7 100644 --- a/inc/ti/forloop.h +++ b/inc/ti/forloop.h @@ -60,9 +60,9 @@ static const ti_forloop_t ti_forloop_callbacks[24] = { ti_forloop_no_iter, /* TI_VAL_MPDATA */ ti_forloop_no_iter, /* TI_VAL_CLOSURE */ ti_forloop_no_iter, /* TI_VAL_ANO */ + ti_forloop_no_iter, /* TI_VAL_WANO */ ti_forloop_no_iter, /* TI_VAL_FUTURE */ ti_forloop_no_iter, /* TI_VAL_MODULE */ - ti_forloop_no_iter, /* TI_VAL_WANO */ ti_forloop_no_iter, /* TI_VAL_TEMPLATE */ }; diff --git a/inc/ti/opr/oprinc.h b/inc/ti/opr/oprinc.h index f4c211e8..41a26d3d 100644 --- a/inc/ti/opr/oprinc.h +++ b/inc/ti/opr/oprinc.h @@ -35,6 +35,8 @@ typedef enum OPR_NIL_SET =TI_VAL_NIL<<5|TI_VAL_SET, OPR_NIL_ERROR =TI_VAL_NIL<<5|TI_VAL_ERROR, OPR_NIL_MEMBER =TI_VAL_NIL<<5|TI_VAL_MEMBER, + OPR_NIL_ANO =TI_VAL_NIL<<5|TI_VAL_ANO, + OPR_NIL_WANO =TI_VAL_NIL<<5|TI_VAL_WANO, OPR_INT_NIL =TI_VAL_INT<<5|TI_VAL_NIL, OPR_INT_INT =TI_VAL_INT<<5|TI_VAL_INT, @@ -51,6 +53,8 @@ typedef enum OPR_INT_SET =TI_VAL_INT<<5|TI_VAL_SET, OPR_INT_ERROR =TI_VAL_INT<<5|TI_VAL_ERROR, OPR_INT_MEMBER =TI_VAL_INT<<5|TI_VAL_MEMBER, + OPR_INT_ANO =TI_VAL_INT<<5|TI_VAL_ANO, + OPR_INT_WANO =TI_VAL_INT<<5|TI_VAL_WANO, OPR_FLOAT_NIL =TI_VAL_FLOAT<<5|TI_VAL_NIL, OPR_FLOAT_INT =TI_VAL_FLOAT<<5|TI_VAL_INT, @@ -67,6 +71,8 @@ typedef enum OPR_FLOAT_SET =TI_VAL_FLOAT<<5|TI_VAL_SET, OPR_FLOAT_ERROR =TI_VAL_FLOAT<<5|TI_VAL_ERROR, OPR_FLOAT_MEMBER =TI_VAL_FLOAT<<5|TI_VAL_MEMBER, + OPR_FLOAT_ANO =TI_VAL_FLOAT<<5|TI_VAL_ANO, + OPR_FLOAT_WANO =TI_VAL_FLOAT<<5|TI_VAL_WANO, OPR_BOOL_NIL =TI_VAL_BOOL<<5|TI_VAL_NIL, OPR_BOOL_INT =TI_VAL_BOOL<<5|TI_VAL_INT, @@ -83,6 +89,8 @@ typedef enum OPR_BOOL_SET =TI_VAL_BOOL<<5|TI_VAL_SET, OPR_BOOL_ERROR =TI_VAL_BOOL<<5|TI_VAL_ERROR, OPR_BOOL_MEMBER =TI_VAL_BOOL<<5|TI_VAL_MEMBER, + OPR_BOOL_ANO =TI_VAL_BOOL<<5|TI_VAL_ANO, + OPR_BOOL_WANO =TI_VAL_BOOL<<5|TI_VAL_WANO, OPR_DATETIME_NIL =TI_VAL_DATETIME<<5|TI_VAL_NIL, OPR_DATETIME_INT =TI_VAL_DATETIME<<5|TI_VAL_INT, @@ -99,6 +107,8 @@ typedef enum OPR_DATETIME_SET =TI_VAL_DATETIME<<5|TI_VAL_SET, OPR_DATETIME_ERROR =TI_VAL_DATETIME<<5|TI_VAL_ERROR, OPR_DATETIME_MEMBER =TI_VAL_DATETIME<<5|TI_VAL_MEMBER, + OPR_DATETIME_ANO =TI_VAL_DATETIME<<5|TI_VAL_ANO, + OPR_DATETIME_WANO =TI_VAL_DATETIME<<5|TI_VAL_WANO, OPR_NAME_NIL =TI_VAL_NAME<<5|TI_VAL_NIL, OPR_NAME_INT =TI_VAL_NAME<<5|TI_VAL_INT, @@ -115,6 +125,8 @@ typedef enum OPR_NAME_SET =TI_VAL_NAME<<5|TI_VAL_SET, OPR_NAME_ERROR =TI_VAL_NAME<<5|TI_VAL_ERROR, OPR_NAME_MEMBER =TI_VAL_NAME<<5|TI_VAL_MEMBER, + OPR_NAME_ANO =TI_VAL_NAME<<5|TI_VAL_ANO, + OPR_NAME_WANO =TI_VAL_NAME<<5|TI_VAL_WANO, OPR_STR_NIL =TI_VAL_STR<<5|TI_VAL_NIL, OPR_STR_INT =TI_VAL_STR<<5|TI_VAL_INT, @@ -131,6 +143,9 @@ typedef enum OPR_STR_SET =TI_VAL_STR<<5|TI_VAL_SET, OPR_STR_ERROR =TI_VAL_STR<<5|TI_VAL_ERROR, OPR_STR_MEMBER =TI_VAL_STR<<5|TI_VAL_MEMBER, + OPR_STR_ANO =TI_VAL_STR<<5|TI_VAL_ANO, + OPR_STR_WANO =TI_VAL_STR<<5|TI_VAL_WANO, + OPR_BYTES_NIL =TI_VAL_BYTES<<5|TI_VAL_NIL, OPR_BYTES_INT =TI_VAL_BYTES<<5|TI_VAL_INT, @@ -146,7 +161,9 @@ typedef enum OPR_BYTES_ARR =TI_VAL_BYTES<<5|TI_VAL_ARR, OPR_BYTES_SET =TI_VAL_BYTES<<5|TI_VAL_SET, OPR_BYTES_ERROR =TI_VAL_BYTES<<5|TI_VAL_ERROR, - OPR_BYTES_MEMBER =TI_VAL_BYTES<<5|TI_VAL_MEMBER, + OPR_BYTES_MEMBER =TI_VAL_BYTES<<5|TI_VAL_MEMBER, + OPR_BYTES_ANO =TI_VAL_BYTES<<5|TI_VAL_ANO, + OPR_BYTES_WANO =TI_VAL_BYTES<<5|TI_VAL_WANO, OPR_REGEX_NIL =TI_VAL_REGEX<<5|TI_VAL_NIL, OPR_REGEX_INT =TI_VAL_REGEX<<5|TI_VAL_INT, @@ -164,6 +181,8 @@ typedef enum OPR_REGEX_SET =TI_VAL_REGEX<<5|TI_VAL_SET, OPR_REGEX_ERROR =TI_VAL_REGEX<<5|TI_VAL_ERROR, OPR_REGEX_MEMBER =TI_VAL_REGEX<<5|TI_VAL_MEMBER, + OPR_REGEX_ANO =TI_VAL_REGEX<<5|TI_VAL_ANO, + OPR_REGEX_WANO =TI_VAL_REGEX<<5|TI_VAL_WANO, OPR_THING_NIL =TI_VAL_THING<<5|TI_VAL_NIL, OPR_THING_INT =TI_VAL_THING<<5|TI_VAL_INT, @@ -180,6 +199,8 @@ typedef enum OPR_THING_SET =TI_VAL_THING<<5|TI_VAL_SET, OPR_THING_ERROR =TI_VAL_THING<<5|TI_VAL_ERROR, OPR_THING_MEMBER =TI_VAL_THING<<5|TI_VAL_MEMBER, + OPR_THING_ANO =TI_VAL_THING<<5|TI_VAL_ANO, + OPR_THING_WANO =TI_VAL_THING<<5|TI_VAL_WANO, OPR_WRAP_NIL =TI_VAL_WRAP<<5|TI_VAL_NIL, OPR_WRAP_INT =TI_VAL_WRAP<<5|TI_VAL_INT, @@ -197,6 +218,8 @@ typedef enum OPR_WRAP_SET =TI_VAL_WRAP<<5|TI_VAL_SET, OPR_WRAP_ERROR =TI_VAL_WRAP<<5|TI_VAL_ERROR, OPR_WRAP_MEMBER =TI_VAL_WRAP<<5|TI_VAL_MEMBER, + OPR_WRAP_ANO =TI_VAL_WRAP<<5|TI_VAL_ANO, + OPR_WRAP_WANO =TI_VAL_WRAP<<5|TI_VAL_WANO, OPR_ARR_NIL =TI_VAL_ARR<<5|TI_VAL_NIL, OPR_ARR_INT =TI_VAL_ARR<<5|TI_VAL_INT, @@ -213,6 +236,8 @@ typedef enum OPR_ARR_SET =TI_VAL_ARR<<5|TI_VAL_SET, OPR_ARR_ERROR =TI_VAL_ARR<<5|TI_VAL_ERROR, OPR_ARR_MEMBER =TI_VAL_ARR<<5|TI_VAL_MEMBER, + OPR_ARR_ANO =TI_VAL_ARR<<5|TI_VAL_ANO, + OPR_ARR_WANO =TI_VAL_ARR<<5|TI_VAL_WANO, OPR_SET_NIL =TI_VAL_SET<<5|TI_VAL_NIL, OPR_SET_INT =TI_VAL_SET<<5|TI_VAL_INT, @@ -229,6 +254,8 @@ typedef enum OPR_SET_SET =TI_VAL_SET<<5|TI_VAL_SET, OPR_SET_ERROR =TI_VAL_SET<<5|TI_VAL_ERROR, OPR_SET_MEMBER =TI_VAL_SET<<5|TI_VAL_MEMBER, + OPR_SET_ANO =TI_VAL_SET<<5|TI_VAL_ANO, + OPR_SET_WANO =TI_VAL_SET<<5|TI_VAL_WANO, OPR_ERROR_NIL =TI_VAL_ERROR<<5|TI_VAL_NIL, OPR_ERROR_INT =TI_VAL_ERROR<<5|TI_VAL_INT, @@ -246,6 +273,8 @@ typedef enum OPR_ERROR_SET =TI_VAL_ERROR<<5|TI_VAL_SET, OPR_ERROR_ERROR =TI_VAL_ERROR<<5|TI_VAL_ERROR, OPR_ERROR_MEMBER =TI_VAL_ERROR<<5|TI_VAL_MEMBER, + OPR_ERROR_ANO =TI_VAL_ERROR<<5|TI_VAL_ANO, + OPR_ERROR_WANO =TI_VAL_ERROR<<5|TI_VAL_WANO, OPR_MEMBER_NIL =TI_VAL_MEMBER<<5|TI_VAL_NIL, OPR_MEMBER_INT =TI_VAL_MEMBER<<5|TI_VAL_INT, @@ -262,6 +291,45 @@ typedef enum OPR_MEMBER_SET =TI_VAL_MEMBER<<5|TI_VAL_SET, OPR_MEMBER_ERROR =TI_VAL_MEMBER<<5|TI_VAL_ERROR, OPR_MEMBER_MEMBER =TI_VAL_MEMBER<<5|TI_VAL_MEMBER, + OPR_MEMBER_ANO =TI_VAL_MEMBER<<5|TI_VAL_ANO, + OPR_MEMBER_WANO =TI_VAL_MEMBER<<5|TI_VAL_WANO, + + OPR_ANO_NIL =TI_VAL_ANO<<5|TI_VAL_NIL, + OPR_ANO_INT =TI_VAL_ANO<<5|TI_VAL_INT, + OPR_ANO_FLOAT =TI_VAL_ANO<<5|TI_VAL_FLOAT, + OPR_ANO_BOOL =TI_VAL_ANO<<5|TI_VAL_BOOL, + OPR_ANO_DATETIME =TI_VAL_ANO<<5|TI_VAL_DATETIME, + OPR_ANO_NAME =TI_VAL_ANO<<5|TI_VAL_NAME, + OPR_ANO_STR =TI_VAL_ANO<<5|TI_VAL_STR, + OPR_ANO_BYTES =TI_VAL_ANO<<5|TI_VAL_BYTES, + OPR_ANO_REGEX =TI_VAL_ANO<<5|TI_VAL_REGEX, + OPR_ANO_THING =TI_VAL_ANO<<5|TI_VAL_THING, + OPR_ANO_WRAP =TI_VAL_ANO<<5|TI_VAL_WRAP, + OPR_ANO_ARR =TI_VAL_ANO<<5|TI_VAL_ARR, + OPR_ANO_SET =TI_VAL_ANO<<5|TI_VAL_SET, + OPR_ANO_ERROR =TI_VAL_ANO<<5|TI_VAL_ERROR, + OPR_ANO_MEMBER =TI_VAL_ANO<<5|TI_VAL_MEMBER, + OPR_ANO_ANO =TI_VAL_ANO<<5|TI_VAL_ANO, + OPR_ANO_WANO =TI_VAL_ANO<<5|TI_VAL_WANO, + + OPR_WANO_NIL =TI_VAL_WANO<<5|TI_VAL_NIL, + OPR_WANO_INT =TI_VAL_WANO<<5|TI_VAL_INT, + OPR_WANO_FLOAT =TI_VAL_WANO<<5|TI_VAL_FLOAT, + OPR_WANO_BOOL =TI_VAL_WANO<<5|TI_VAL_BOOL, + OPR_WANO_DATETIME =TI_VAL_WANO<<5|TI_VAL_DATETIME, + OPR_WANO_NAME =TI_VAL_WANO<<5|TI_VAL_NAME, + OPR_WANO_STR =TI_VAL_WANO<<5|TI_VAL_STR, + OPR_WANO_BYTES =TI_VAL_WANO<<5|TI_VAL_BYTES, + OPR_WANO_REGEX =TI_VAL_WANO<<5|TI_VAL_REGEX, + OPR_WANO_THING =TI_VAL_WANO<<5|TI_VAL_THING, + OPR_WANO_WRAP =TI_VAL_WANO<<5|TI_VAL_WRAP, + OPR_WANO_ARR =TI_VAL_WANO<<5|TI_VAL_ARR, + OPR_WANO_SET =TI_VAL_WANO<<5|TI_VAL_SET, + OPR_WANO_ERROR =TI_VAL_WANO<<5|TI_VAL_ERROR, + OPR_WANO_MEMBER =TI_VAL_WANO<<5|TI_VAL_MEMBER, + OPR_WANO_ANO =TI_VAL_WANO<<5|TI_VAL_ANO, + OPR_WANO_WANO =TI_VAL_WANO<<5|TI_VAL_WANO, + } ti_opr_perm_t; #endif /* TI_OPR_OPRINC_H_ */ diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index 4e37d76f..69a28883 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -279,6 +279,11 @@ static inline int val__wrap_to_arr(ti_val_t ** UNUSED(v), ti_varr_t * varr, ex_t return varr->flags |= TI_VARR_FLAG_MHT, 0; } +static inline int val__wano_to_arr(ti_val_t ** UNUSED(v), ti_varr_t * varr, ex_t * UNUSED(e)) +{ + return varr->flags |= TI_VARR_FLAG_MHT, 0; +} + static inline int val__room_to_arr(ti_val_t ** UNUSED(v), ti_varr_t * varr, ex_t * UNUSED(e)) { return varr->flags |= TI_VARR_FLAG_MHR, 0; @@ -553,6 +558,18 @@ static ti_val_type_t ti_val_type_props[24] = { .as_bool = val__as_bool_true, .allowed_as_vtask_arg = false, }, + /* TI_VAL_WANO */ + { + .destroy = (ti_val_destroy_cb) ti_wano_destroy, + .to_str = ti_val_wano_to_str, + .to_arr_cb = val__wano_to_arr, + .to_client_pk = (ti_val_to_client_pk_cb) ti_wano_to_client_pk, + .to_store_pk = (ti_val_to_store_pk_cb) ti_wano_to_store_pk, + .get_type_str = val__wano_type_str, + .as_bool = val__as_bool_wano, + .allowed_as_vtask_arg = false, + }, + /* TI_VAL_FUTURE */ { .destroy = (ti_val_destroy_cb) ti_future_destroy, @@ -573,16 +590,6 @@ static ti_val_type_t ti_val_type_props[24] = { .as_bool = val__as_bool_true, .allowed_as_vtask_arg = false, }, - /* TI_VAL_WANO */ - { - .destroy = (ti_val_destroy_cb) ti_wano_destroy, - .to_str = ti_val_wano_to_str, - .to_arr_cb = val__as_nil_to_arr, - .to_client_pk = (ti_val_to_client_pk_cb) ti_wano_to_client_pk, - .get_type_str = val__wano_type_str, - .as_bool = val__as_bool_wano, - .allowed_as_vtask_arg = false, - }, /* TI_VAL_TEMPLATE */ { .destroy = (ti_val_destroy_cb) ti_template_destroy, @@ -841,6 +848,11 @@ static inline _Bool ti_val_is_wrap(ti_val_t * val) return val->tp == TI_VAL_WRAP; } +static inline _Bool ti_val_is_wrap_wano(ti_val_t * val) +{ + return val->tp == TI_VAL_WRAP || val->tp == TI_VAL_WANO; +} + static inline _Bool ti_val_is_wano(ti_val_t * val) { return val->tp == TI_VAL_WANO; @@ -1188,9 +1200,9 @@ static inline void ti_val_attach( case TI_VAL_MEMBER: case TI_VAL_CLOSURE: case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: return; case TI_VAL_ARR: ((ti_varr_t *) val)->parent = parent; diff --git a/inc/ti/val.t.h b/inc/ti/val.t.h index 6a02fa96..9f77fed1 100644 --- a/inc/ti/val.t.h +++ b/inc/ti/val.t.h @@ -26,8 +26,8 @@ #define TI_VAL_FUTURE_S "future" #define TI_VAL_MODULE_S "module" #define TI_VAL_TASK_S "task" -#define TI_VAL_ANO_S "anonymous" -#define TI_VAL_WANO_S "" +#define TI_VAL_ANO_S "" +#define TI_VAL_WANO_S "<>" #define TI_KIND_S_INSTANCE "." /* Internally, New typed thing */ #define TI_KIND_S_OBJECT "," /* Internally, New thing */ @@ -35,6 +35,7 @@ #define TI_KIND_S_SET "$" /* Internally, Set */ #define TI_KIND_S_ERROR "!" /* Internally, Error */ #define TI_KIND_S_WRAP "&" /* Internally, Wrapped thing */ +#define TI_KIND_S_WANO " " /* Internally, Wrapped ano thing */ #define TI_KIND_S_MEMBER "%%" /* Internally, Enum member */ #define TI_KIND_S_DATETIME "'" /* Internally, Date/Time */ #define TI_KIND_S_TIMEVAL "\"" /* Internally, Time value */ @@ -42,8 +43,6 @@ #define TI_KIND_S_REGEX_OBSOLETE_ "*" /* - * Both copy() and dup() use the following code to set the default deep value: - * !(type & 0x4); THING/WRAP: 1 ARR/SET: 0 * Be careful when changing the order in the enumerator. * The ti_forloop_t also depends on the order in this enumerator; */ @@ -69,10 +68,10 @@ typedef enum TI_VAL_MPDATA, /* msgpack data */ TI_VAL_CLOSURE, TI_VAL_ANO, /* anonymous wrap-only type */ + TI_VAL_WANO, /* wrapped with anonymous type */ /* future, module and template are never stored */ TI_VAL_FUTURE, /* future */ TI_VAL_MODULE, /* module */ - TI_VAL_WANO, /* wrapped with anonymous type */ 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 @@ -102,6 +101,7 @@ typedef enum TI_KIND_C_MEMBER ='%', TI_KIND_C_DATETIME ='\'', TI_KIND_C_TIMEVAL ='"', + TI_KIND_C_WANO =' ', /* Obsolete, but still required for backwards compatibility */ TI_KIND_C_THING_OBSOLETE_ ='#', TI_KIND_C_CLOSURE_OBSOLETE_ ='/', diff --git a/inc/ti/wano.h b/inc/ti/wano.h index 82b2803e..caf28f39 100644 --- a/inc/ti/wano.h +++ b/inc/ti/wano.h @@ -10,5 +10,7 @@ ti_wano_t * ti_wano_create(ti_thing_t * thing, ti_ano_t * ano); void ti_wano_destroy(ti_wano_t * wano); +int ti_wano_copy(ti_wano_t ** wano, uint8_t deep); +int ti_wano_dup(ti_wano_t ** wano, uint8_t deep); #endif /* TI_WANO_H_ */ diff --git a/inc/ti/wano.inline.h b/inc/ti/wano.inline.h index 36909a06..aef5658c 100644 --- a/inc/ti/wano.inline.h +++ b/inc/ti/wano.inline.h @@ -30,4 +30,15 @@ static inline int ti_wano_to_client_pk( : ti_thing_id_to_client_pk(wano->thing, &vp->pk); } +static inline int ti_wano_to_store_pk(ti_wano_t * wano, msgpack_packer * pk) +{ + return -( + msgpack_pack_map(pk, 1) || + mp_pack_strn(pk, TI_KIND_S_WANO, 1) || + msgpack_pack_array(pk, 2) || + mp_pack_bin(pk, wano->ano->spec_raw->data, wano->ano->spec_raw->n) || + ti_thing_to_store_pk(wano->thing, pk) + ); +} + #endif /* TI_WANO_INLINE_H_ */ diff --git a/inc/ti/wano.t.h b/inc/ti/wano.t.h index a5566f6b..4363e758 100644 --- a/inc/ti/wano.t.h +++ b/inc/ti/wano.t.h @@ -14,8 +14,8 @@ struct ti_wano_s uint32_t ref; uint8_t tp; int:24; - ti_ano_t * ano; /* with reference */ ti_thing_t * thing; /* with reference */ + ti_ano_t * ano; /* with reference */ }; #endif /* TI_WANO_T_H_ */ diff --git a/inc/ti/wrap.h b/inc/ti/wrap.h index f93c3fdc..84b32753 100644 --- a/inc/ti/wrap.h +++ b/inc/ti/wrap.h @@ -35,7 +35,7 @@ struct ti_wrap_s { uint32_t ref; uint8_t tp; - uint8_t unused_flags; + int:8; uint16_t type_id; ti_thing_t * thing; /* with reference */ }; diff --git a/itest/test_advanced.py b/itest/test_advanced.py index bad14e1c..29eac937 100755 --- a/itest/test_advanced.py +++ b/itest/test_advanced.py @@ -1881,8 +1881,7 @@ async def test_future_or_wrap_ano_to_type(self, client): with self.assertRaisesRegex( TypeError, r'mismatch in type `A`; property `x` allows `any` type with ' - r'the exception of the `future`, `module` ' - r'and `` type'): + r'the exception of the `future` and `module` type'): await client.query("""//ti A{ x: future(||nil) diff --git a/itest/test_ano.py b/itest/test_ano.py index 8a65920d..a5a47172 100755 --- a/itest/test_ano.py +++ b/itest/test_ano.py @@ -39,18 +39,142 @@ async def test_ano_err(self, q): set_type('A', {x: 'any'}); """) + res = await q("""//ti + .x = {}.wrap(&{}); + .x; + """) + self.assertIs(res, None) + + with self.assertRaisesRegex( + LookupError, + r'function `ano` is undefined in the `@thingsdb` scope; ' + r'you might want to query a `@collection` scope\?;'): + await q("""//ti + ano({}); + """, scope='/t') + + with self.assertRaisesRegex( + NumArgumentsError, + r'function `ano` takes 1 argument but 0 were given'): + await q("""//ti + ano(); + """) + + with self.assertRaisesRegex( + TypeError, + r'function `ano` expects argument 1 to be of ' + r'type `thing` but got type `nil` instead;'): + await q("""//ti + ano(nil); + """) + with self.assertRaisesRegex( TypeError, - r'mismatch in type `A`; property `x` allows `any` type with ' - r'the exception of the `future`, `module` ' - r'and `` type'): + r'expecting a nested structure \(`list` or `thing`\), ' \ + r'a method of type `closure` or a definition ' + r'of type `str` but got type `int` instead'): + await q( + """//ti + ano({ + x: 0 + }); + """) + + with self.assertRaisesRegex( + LookupError, + r'anonymous types are not supported in the the `@thingsdb` ' + r'scope'): await q("""//ti - A{ - x: {}.wrap(&{}) + &{}; + """, scope='/t') + + async def test_more_ano_props(self, q): + r = await q("""//ti + .a = &{ + id: '#', + a: 'int', + b: 'str', + f: |a, b| a + b, + }; + .a.f(20, 22); + """) + self.assertEqual(r, 42) + r1, r2 = await q("""//ti + o = { + name: 'Iris', + numbers: [{ + x: 1, + y: 2, + }, { + x: 4, + }, { + y: 5, + }] }; + [ + o.wrap(&{ + name: |this| this.name.upper(), + numbers: [{ + x: 'int' + }] + }), + o.wrap(ano({ + name: |this| this.name.upper(), + numbers: [{ + x: 'int' + }] + })), + ]; + """ + ) + self.assertEqual(r1, { + "name": "IRIS", + "numbers": [{"x": 1,}, {"x": 4}, {}] + }) + self.assertEqual(r1, r2) + await q("""//ti + o = { + name: 'Iris', + numbers: [{ + x: 1, + y: 2, + }, { + x: 4, + }, { + y: 5, + }] + }; + .wano = [ + o.wrap(&{ + name: |this| this.name.upper(), + numbers: [{ + x: 'int' + }] + }), + o.wrap(ano({ + name: |this| this.name.upper(), + numbers: [{ + x: 'int' + }] + })), + ]; + """ + ) + r1, r2 = await q("""//ti + .wano; + """) + self.assertEqual(r1, { + "name": "IRIS", + "numbers": [{"x": 1,}, {"x": 4}, {}] + }) + self.assertEqual(r1, r2) + r = await q( + """//ti + .wano[0] == .wano[1] """) + self.assertTrue(r) + - # TODO : test len(ano type) if __name__ == '__main__': diff --git a/src/ti/ano.c b/src/ti/ano.c index bfce50df..0a171ddd 100644 --- a/src/ti/ano.c +++ b/src/ti/ano.c @@ -5,7 +5,7 @@ #include #include #include - +#include ti_ano_t * ti_ano_new(void) { @@ -90,7 +90,6 @@ int ti_ano_init( ano->spec_raw = spec_raw; ti_incref(spec_raw); } - fail0: ti_val_unsafe_drop(val); return e->nr; @@ -112,6 +111,17 @@ ti_ano_t * ti_ano_from_raw( ti_ano_destroy(ano); return NULL; } + /* This is used for quickly loading equal ano from cache, its a weak + * ref and the call is not critical; It should be done here, and not + * init as we want to cache ano(..) calls, and loading from changes/stored + * on disk, but not from syntax in queries as they are cached as immutable + * variable; */ + (void) smap_addn( + collection->ano_types, + (const char *) spec_raw->data, + spec_raw->n, + ano); + return ano; } @@ -121,8 +131,14 @@ ti_ano_t * ti_ano_create( size_t n, ex_t * e) { - ti_ano_t * ano; - ti_raw_t * spec_raw = ti_bin_create(bin, n); + ti_raw_t * spec_raw; + ti_ano_t * ano = smap_getn(collection->ano_types, (const char *) bin, n); + if (ano) + { + ti_incref(ano); + return ano; + } + spec_raw = ti_bin_create(bin, n); if (!spec_raw) return NULL; @@ -133,6 +149,11 @@ ti_ano_t * ti_ano_create( void ti_ano_destroy(ti_ano_t * ano) { + if (ano->spec_raw) + (void) smap_popn( + ano->type->types->collection->ano_types, + (const char *) ano->spec_raw->data, + ano->spec_raw->n); ti_val_drop((ti_val_t *) ano->spec_raw); ti_type_drop_anonymous(ano->type); free(ano); diff --git a/src/ti/collection.c b/src/ti/collection.c index ac2e018c..7e929b67 100644 --- a/src/ti/collection.c +++ b/src/ti/collection.c @@ -61,6 +61,7 @@ ti_collection_t * ti_collection_create( collection->gc = queue_new(20); collection->access = vec_new(1); collection->procedures = smap_create(); + collection->ano_types = smap_create(); collection->types = ti_types_create(collection); collection->enums = ti_enums_create(collection); collection->lock = malloc(sizeof(uv_mutex_t)); @@ -77,7 +78,7 @@ ti_collection_t * ti_collection_create( !collection->access || !collection->procedures || !collection->lock || !collection->types || !collection->enums || !collection->futures || !collection->rooms || !collection->named_rooms || - uv_mutex_init(collection->lock)) + !collection->ano_types || uv_mutex_init(collection->lock)) { ti_collection_drop(collection); return NULL; @@ -104,6 +105,7 @@ void ti_collection_destroy(ti_collection_t * collection) vec_destroy(collection->commits, (vec_destroy_cb) ti_commit_destroy); smap_destroy(collection->procedures, (smap_destroy_cb) ti_procedure_destroy); smap_destroy(collection->named_rooms, NULL); + smap_destroy(collection->ano_types, NULL); ti_types_destroy(collection->types); ti_enums_destroy(collection->enums); uv_mutex_destroy(collection->lock); @@ -132,7 +134,7 @@ void ti_collection_drop(ti_collection_t * collection) int ti_collection_to_pk(ti_collection_t * collection, msgpack_packer * pk) { return -( - msgpack_pack_map(pk, 8) || + msgpack_pack_map(pk, 9) || mp_pack_str(pk, "collection_id") || msgpack_pack_uint64(pk, collection->id) || @@ -158,7 +160,10 @@ int ti_collection_to_pk(ti_collection_t * collection, msgpack_packer * pk) mp_pack_str(pk, "commit_history") || (collection->commits ? msgpack_pack_uint32(pk, collection->commits->n) - : mp_pack_str(pk, "disabled")) + : mp_pack_str(pk, "disabled")) || + + mp_pack_str(pk, "ano_types") || + msgpack_pack_uint64(pk, collection->ano_types->n) ); } diff --git a/src/ti/do.c b/src/ti/do.c index a4950606..860a59cb 100644 --- a/src/ti/do.c +++ b/src/ti/do.c @@ -1322,7 +1322,7 @@ static int do__ano(ti_query_t * query, cleri_node_t * nd, ex_t * e) ti_raw_t * spec_raw; if (!query->collection) { - ex_set(e, EX_OPERATION, + ex_set(e, EX_LOOKUP_ERROR, "anonymous types are not supported in the the `%s` scope", ti_query_scope_name(query)); return e->nr; @@ -1343,6 +1343,7 @@ static int do__ano(ti_query_t * query, cleri_node_t * nd, ex_t * e) if (ti_ano_init(nd->data, query->collection, spec_raw, e)) return e->nr; + ti_val_unsafe_drop((ti_val_t *) spec_raw); } query->rval = nd->data; ti_incref(query->rval); diff --git a/src/ti/enum.c b/src/ti/enum.c index da92bec0..5c2390d9 100644 --- a/src/ti/enum.c +++ b/src/ti/enum.c @@ -729,9 +729,9 @@ ti_member_t * ti_enum_member_by_val_e( case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: case TI_VAL_TEMPLATE: break; diff --git a/src/ti/export.c b/src/ti/export.c index 0941197f..c04109f8 100644 --- a/src/ti/export.c +++ b/src/ti/export.c @@ -447,6 +447,8 @@ static int export__val(ti_fmt_t * fmt, ti_val_t * val) buf_write(buf, '&') || export__thing(fmt, (ti_thing_t *) val) ); + case TI_VAL_WANO: + return buf_append_str(buf, "&{}.wrap() /* WARN: not exported */"); case TI_VAL_FUTURE: return buf_append_str(buf, "future(||nil) /* WARN: not exported */"); case TI_VAL_MODULE: @@ -457,8 +459,6 @@ static int export__val(ti_fmt_t * fmt, ti_val_t * val) "%.*s /* WARN: module must be installed */", module->name->n, module->name->str); } - case TI_VAL_WANO: - return buf_append_str(buf, "&{}.wrap() /* WARN: not exported */"); case TI_VAL_TEMPLATE: assert(0); } diff --git a/src/ti/field.c b/src/ti/field.c index c1d899e9..7959ab52 100644 --- a/src/ti/field.c +++ b/src/ti/field.c @@ -1839,11 +1839,11 @@ int ti_field_make_assignable( case TI_VAL_CLOSURE: return ti_closure_unbound((ti_closure_t *) *val, e); case TI_VAL_ANO: + case TI_VAL_WANO: break; case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: - goto future_module_wano_error; + goto future_module_error; case TI_VAL_TEMPLATE: break; } @@ -2020,11 +2020,11 @@ int ti_field_make_assignable( goto type_error; -future_module_wano_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`, `module` and `` type", + "of the `"TI_VAL_FUTURE_S"` and `"TI_VAL_MODULE_S"` type", field->type->name, field->name->str); return e->nr; diff --git a/src/ti/index.c b/src/ti/index.c index 3e38de1c..f29b1387 100644 --- a/src/ti/index.c +++ b/src/ti/index.c @@ -674,9 +674,9 @@ 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_ANO: + case TI_VAL_WANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: if (do_slice) goto slice_error; goto index_error; diff --git a/src/ti/opr.c b/src/ti/opr.c index c7354c59..05be313c 100644 --- a/src/ti/opr.c +++ b/src/ti/opr.c @@ -108,6 +108,16 @@ _Bool ti__opr_eq_(ti_val_t * a, ti_val_t * b) return ti_vset_eq((ti_vset_t *) a, (ti_vset_t *) b); case OPR_ERROR_ERROR: return ((ti_verror_t *) a)->code == ((ti_verror_t *) b)->code; + case OPR_ANO_ANO: + return ti_raw_eq( + ((ti_ano_t *) a)->spec_raw, + ((ti_ano_t *) b)->spec_raw); + case OPR_WANO_WANO: + return + ((ti_wano_t *) a)->thing == ((ti_wano_t *) b)->thing && + ti_raw_eq( + ((ti_wano_t *) a)->ano->spec_raw, + ((ti_wano_t *) b)->ano->spec_raw); } return false; } diff --git a/src/ti/query.c b/src/ti/query.c index 5ad052a2..70c407d2 100644 --- a/src/ti/query.c +++ b/src/ti/query.c @@ -1493,12 +1493,12 @@ static int query__get_things(ti_val_t * val, imap_t * imap) case TI_VAL_CLOSURE: case TI_VAL_ANO: break; + case TI_VAL_WANO: + return query__var_walk_thing(((ti_wano_t *) val)->thing, imap); case TI_VAL_FUTURE: return VFUT(val) ? query__get_things(VFUT(val), imap) : 0; case TI_VAL_MODULE: break; - case TI_VAL_WANO: - return query__var_walk_thing(((ti_wano_t *) val)->thing, imap); case TI_VAL_TEMPLATE: break; } diff --git a/src/ti/thing.c b/src/ti/thing.c index fca0e8a3..144ecc87 100644 --- a/src/ti/thing.c +++ b/src/ti/thing.c @@ -427,6 +427,7 @@ int ti_thing_p_prop_add_assign( case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_ANO: + case TI_VAL_WANO: ti_incref(val); break; case TI_VAL_ARR: @@ -456,7 +457,6 @@ int ti_thing_p_prop_add_assign( break; case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: val = (ti_val_t *) ti_nil_get(); break; case TI_VAL_TEMPLATE: @@ -530,6 +530,7 @@ int ti_thing_i_item_add_assign( case TI_VAL_ERROR: case TI_VAL_MEMBER: case TI_VAL_ANO: + case TI_VAL_WANO: ti_incref(val); break; case TI_VAL_ARR: @@ -559,7 +560,6 @@ int ti_thing_i_item_add_assign( break; case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: 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 8eeb0007..d0d8212f 100644 --- a/src/ti/val.c +++ b/src/ti/val.c @@ -254,6 +254,53 @@ static ti_val_t * val__unp_map(ti_vup_t * vup, size_t sz, ex_t * e) ex_set_mem(e); return (ti_val_t *) wrap; } + case TI_KIND_C_WANO: + { + mp_obj_t mp_spec_raw; + ti_val_t * vthing; + ti_ano_t * ano; + ti_wano_t * wano; + + if (sz != 1 || + mp_next(vup->up, &mp_val) != MP_ARR || mp_val.via.sz != 2 || + mp_next(vup->up, &mp_spec_raw) != MP_BIN) + { + ex_set(e, EX_BAD_DATA, + "wano type must be written according the " + "following syntax: {\""TI_KIND_S_WANO"\": [spec_raw, {...}]"); + return NULL; + } + + vthing = ti_val_from_vup_e(vup, e); + if (!vthing) + return NULL; + + if (!ti_val_is_thing(vthing)) + { + ex_set(e, EX_BAD_DATA, + "wano type is expecting a wrapped `"TI_VAL_THING_S"` but " + "got type `%s` instead", + ti_val_str(vthing)); + ti_val_unsafe_drop(vthing); + return NULL; + } + ano = ti_ano_create( + vup->collection, + mp_spec_raw.via.bin.data, + mp_spec_raw.via.bin.n, + e); + if (!ano) + { + ti_val_unsafe_drop(vthing); + return NULL; + } + wano = ti_wano_create((ti_thing_t *) vthing, ano); + if (!wano) + ex_set_mem(e); + ti_val_unsafe_drop(vthing); + ti_val_unsafe_drop((ti_val_t *) ano); + return (ti_val_t *) wano; + } case TI_KIND_C_MEMBER: { mp_obj_t mp_enum_id, mp_idx; @@ -446,6 +493,9 @@ static int val__push(ti_varr_t * varr, ti_val_t * val, ex_t * e) case TI_VAL_CLOSURE: case TI_VAL_ANO: break; + case TI_VAL_WANO: + varr->flags |= TI_VARR_FLAG_MHT; + break; case TI_VAL_ARR: { /* Make sure the arr is converted to a `tuple` and copy the @@ -469,7 +519,6 @@ static int val__push(ti_varr_t * varr, ti_val_t * val, ex_t * e) break; case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: case TI_VAL_TEMPLATE: assert(0); return e->nr; @@ -800,9 +849,9 @@ int ti_val_init_common(void) val__parent_type_name = (ti_val_t *) ti_names_from_str_slow("parent_type"); val__key_name = (ti_val_t *) ti_names_from_str_slow("key"); val__key_type_name = (ti_val_t *) ti_names_from_str_slow("key_type"); - val__anonymous_name = (ti_val_t *) ti_names_from_str_slow("__anonymous__"); - val__re_email = (ti_val_t *) ti_regex_from_str("/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$/"); - val__re_url = (ti_val_t *) ti_regex_from_str("/^(https?|ftp):\\/\\/[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)$/"); + val__anonymous_name = (ti_val_t *) ti_names_from_str_slow(""); + val__re_email = (ti_val_t *) ti_regex_from_str("/^[a-zA-Z0-9.!#$%%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$/"); + val__re_url = (ti_val_t *) ti_regex_from_str("/^(https?|ftp):\\/\\/[-a-zA-Z0-9@:%%._\\+~#=]{1,256}\\b([-a-zA-Z0-9@:%%_\\+.~#?&//=]*)$/"); val__re_tel = (ti_val_t *) ti_regex_from_str("/^[\\+]?(\\([0-9]{1,4}\\)[-\\s\\.]?){0,2}([0-9]{1,4}[-\\s]?){3,5}$/"); if (!val__empty_bin || !val__empty_str || !val__snil || !val__strue || @@ -1046,9 +1095,9 @@ int ti_val_convert_to_bytes(ti_val_t ** val, ex_t * e) case TI_VAL_SET: case TI_VAL_CLOSURE: case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: case TI_VAL_ERROR: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_BYTES_S"`", @@ -1147,9 +1196,9 @@ int ti_val_convert_to_int(ti_val_t ** val, ex_t * e) case TI_VAL_SET: case TI_VAL_CLOSURE: case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: case TI_VAL_MPDATA: case TI_VAL_BYTES: ex_set(e, EX_TYPE_ERROR, @@ -1246,9 +1295,9 @@ int ti_val_convert_to_float(ti_val_t ** val, ex_t * e) case TI_VAL_SET: case TI_VAL_CLOSURE: case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: case TI_VAL_MPDATA: case TI_VAL_BYTES: ex_set(e, EX_TYPE_ERROR, @@ -1292,10 +1341,10 @@ int ti_val_convert_to_array(ti_val_t ** val, ex_t * e) case TI_VAL_TASK: case TI_VAL_CLOSURE: case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_MEMBER: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_LIST_S"`", ti_val_str(*val)); @@ -1361,13 +1410,13 @@ int ti_val_convert_to_set(ti_val_t ** val, ex_t * e) case TI_VAL_WRAP: case TI_VAL_ROOM: case TI_VAL_TASK: - case TI_VAL_CLOSURE: - case TI_VAL_ANO: case TI_VAL_ERROR: case TI_VAL_MEMBER: + case TI_VAL_CLOSURE: + case TI_VAL_ANO: + case TI_VAL_WANO: case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: ex_set(e, EX_TYPE_ERROR, "cannot convert type `%s` to `"TI_VAL_SET_S"`", ti_val_str(*val)); @@ -1417,13 +1466,13 @@ size_t ti_val_get_len(ti_val_t * val) ((ti_ano_t *) val)->type->fields->n + ((ti_ano_t *) val)->type->methods->n + !!((ti_ano_t *) val)->type->idname); + case TI_VAL_WANO: + return ti_thing_n(((ti_wano_t *) val)->thing); case TI_VAL_MEMBER: return ti_val_get_len(VMEMBER(val)); case TI_VAL_FUTURE: case TI_VAL_MODULE: break; - case TI_VAL_WANO: - return ti_thing_n(((ti_wano_t *) val)->thing); case TI_VAL_ERROR: break; } @@ -1506,9 +1555,16 @@ int ti_val_gen_ids(ti_val_t * val) case TI_VAL_CLOSURE: case TI_VAL_ANO: break; + case TI_VAL_WANO: + if (!((ti_wano_t *) val)->thing->id) + return ti_thing_gen_id(((ti_wano_t *) val)->thing); + /* + * New things 'under' an existing thing will get their own task, + * so here we do not need recursion. + */ + break; case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: case TI_VAL_TEMPLATE: assert(0); } @@ -1549,12 +1605,13 @@ _Bool ti_val_has_ids(ti_val_t * val) return imap_walk(VSET(val), (imap_cb) val__walk_has_id_set, NULL); case TI_VAL_CLOSURE: case TI_VAL_ANO: + return false; + case TI_VAL_WANO: + return ti_thing_has_id(((ti_wano_t *) val)->thing); case TI_VAL_ERROR: case TI_VAL_FUTURE: case TI_VAL_MODULE: return false; - case TI_VAL_WANO: - return ti_thing_has_id(((ti_wano_t *) val)->thing); case TI_VAL_TEMPLATE: assert(0); } @@ -1590,6 +1647,8 @@ size_t ti_val_alloc_size(ti_val_t * val) return 4096; case TI_VAL_ANO: return ((ti_ano_t *) val)->spec_raw->n + 9; + case TI_VAL_WANO: + return 65536; case TI_VAL_ERROR: return ((ti_verror_t *) val)->msg_n + 128; case TI_VAL_MEMBER: @@ -1598,8 +1657,6 @@ size_t ti_val_alloc_size(ti_val_t * val) return VFUT(val) ? ti_val_alloc_size(VFUT(val)) : 64; case TI_VAL_MODULE: return 64; - case TI_VAL_WANO: - return 65536; case TI_VAL_TEMPLATE: assert(0); } @@ -1642,9 +1699,9 @@ ti_val_t * ti_val_strv(ti_val_t * val) case TI_VAL_MPDATA: return ti_grab(val__smpdata); case TI_VAL_CLOSURE: return ti_grab(val__sclosure); case TI_VAL_ANO: return ti_grab(val__sano); + case TI_VAL_WANO: return ti_grab(val__swano); case TI_VAL_FUTURE: return ti_grab(val__sfuture); case TI_VAL_MODULE: return ti_grab(val__smodule); - case TI_VAL_WANO: return ti_grab(val__swano); case TI_VAL_TEMPLATE: assert(0); } @@ -1701,9 +1758,10 @@ int ti_val_copy(ti_val_t ** val, ti_thing_t * parent, void * key, uint8_t deep) } case TI_VAL_ANO: return 0; + case TI_VAL_WANO: + return ti_wano_copy((ti_wano_t **) val, deep); case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; @@ -1763,9 +1821,10 @@ int ti_val_dup(ti_val_t ** val, ti_thing_t * parent, void * key, uint8_t deep) } case TI_VAL_ANO: return 0; + case TI_VAL_WANO: + return ti_wano_dup((ti_wano_t **) val, deep); case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: 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 eef7cf2e..ada9f8e0 100644 --- a/src/ti/varr.c +++ b/src/ti/varr.c @@ -355,9 +355,10 @@ static int varr__copy(ti_val_t ** val, uint8_t deep) if (varr__copy(v, deep)) return -1; return 0; + case TI_VAL_WANO: + return ti_wano_copy((ti_wano_t **) val, deep); case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: case TI_VAL_SET: case TI_VAL_TEMPLATE: break; @@ -400,9 +401,10 @@ static int varr__dup(ti_val_t ** val, uint8_t deep) if (varr__dup(v, deep)) return -1; return 0; + case TI_VAL_WANO: + return ti_wano_dup((ti_wano_t **) val, deep); case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: case TI_VAL_SET: case TI_VAL_TEMPLATE: break; diff --git a/src/ti/wano.c b/src/ti/wano.c index 0ebeb98b..722b843f 100644 --- a/src/ti/wano.c +++ b/src/ti/wano.c @@ -25,3 +25,38 @@ void ti_wano_destroy(ti_wano_t * wano) ti_val_unsafe_gc_drop((ti_val_t *) wano->thing); free(wano); } + +int ti_wano_copy(ti_wano_t ** wano, uint8_t deep) +{ + ti_thing_t * thing = (*wano)->thing; + ti_wano_t * _wano = ti_wano_create(thing, (*wano)->ano); + if (!_wano) + return -1; + + if (ti_thing_copy(&_wano->thing, deep)) + { + ti_val_unsafe_drop((ti_val_t *) _wano); + return -1; + } + ti_val_unsafe_drop((ti_val_t *) *wano); + *wano = _wano; + return 0; +} + +int ti_wano_dup(ti_wano_t ** wano, uint8_t deep) +{ + assert(deep); + ti_wano_t * _wano = ti_wano_create((*wano)->thing, (*wano)->ano); + if (!_wano) + return -1; + + if (ti_thing_dup(&_wano->thing, deep)) + { + ti_wano_destroy(_wano); + return -1; + } + + ti_val_unsafe_drop((ti_val_t *) *wano); + *wano = _wano; + return 0; +} \ No newline at end of file diff --git a/src/ti/wrap.c b/src/ti/wrap.c index 507dd260..315633fa 100644 --- a/src/ti/wrap.c +++ b/src/ti/wrap.c @@ -242,6 +242,13 @@ static int wrap__field_val( return ti_closure_to_client_pk((ti_closure_t *) val, &vp->pk); case TI_VAL_ANO: return ti_ano_to_client_pk((ti_ano_t * ) val, &vp->pk); + case TI_VAL_WANO: + return ti_wrap_field_thing_type( + ((ti_wano_t *) val)->thing, + vp, + ((ti_wano_t *) val)->ano->type, + deep, + flags); case TI_VAL_FUTURE: return VFUT(val) ? wrap__field_val( @@ -254,13 +261,6 @@ static int wrap__field_val( : msgpack_pack_nil(&vp->pk); case TI_VAL_MODULE: return msgpack_pack_nil(&vp->pk); - case TI_VAL_WANO: - return ti_wrap_field_thing_type( - ((ti_wano_t *) val)->thing, - vp, - ((ti_wano_t *) val)->ano->type, - deep, - flags); case TI_VAL_TEMPLATE: break; } @@ -688,6 +688,7 @@ int ti__wrap_field_thing( return wrap__field_thing(thing, vp, t_type, deep, flags); } +/* works with both ti_wrap_t and ti_wano_t */ int ti_wrap_cp(ti_query_t * query, uint8_t deep, ex_t * e) { ti_val_t * val; @@ -703,7 +704,7 @@ int ti_wrap_cp(ti_query_t * query, uint8_t deep, ex_t * e) .up = &up, }; - assert(ti_val_is_wrap(query->rval)); + assert(ti_val_is_wrap_wano(query->rval)); if (mp_sbuffer_alloc_init(&buffer, ti_val_alloc_size(query->rval), 0)) { @@ -754,17 +755,17 @@ int ti_wrap_copy(ti_wrap_t ** wrap, uint8_t deep) int ti_wrap_dup(ti_wrap_t ** wrap, uint8_t deep) { assert(deep); - ti_wrap_t * nwrap = ti_wrap_create((*wrap)->thing, (*wrap)->type_id); - if (!nwrap) + ti_wrap_t * _wrap = ti_wrap_create((*wrap)->thing, (*wrap)->type_id); + if (!_wrap) return -1; - if (ti_thing_dup(&nwrap->thing, deep)) + if (ti_thing_dup(&_wrap->thing, deep)) { - ti_wrap_destroy(nwrap); + ti_wrap_destroy(_wrap); return -1; } ti_val_unsafe_drop((ti_val_t *) *wrap); - *wrap = nwrap; + *wrap = _wrap; return 0; } From 7cf774c7feb147bc0ab08dea8b4c81415272a0cf Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Sat, 8 Nov 2025 17:03:08 +0100 Subject: [PATCH 05/13] val --- inc/ti/val.inline.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index 69a28883..330176bb 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -1395,7 +1395,7 @@ static inline _Bool val__spec_enum_eq_to_val(uint16_t spec, ti_val_t * val) * TI_SPEC_TEL, */ -static ti_val_spec_t ti_val_spec_map[25] = { +static ti_val_spec_t ti_val_spec_map[24] = { {.is_spec=ti_val_is_thing}, {.is_spec=ti_val_is_raw}, {.is_spec=ti_val_is_str}, @@ -1420,7 +1420,6 @@ static ti_val_spec_t ti_val_spec_map[25] = { {.is_spec=ti_val_is_email}, {.is_spec=ti_val_is_url}, {.is_spec=ti_val_is_tel}, - {.is_spec=ti_val_is_ano}, }; static inline _Bool ti_val_is_spec(ti_val_t * val, uint16_t spec) From 73a66aa22517c7aed51e2ca9e458519fffde8a6f Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Sat, 8 Nov 2025 23:07:47 +0100 Subject: [PATCH 06/13] global `enum` definition --- CHANGELOG.md | 1 + inc/ti/spec.t.h | 1 + inc/ti/val.inline.h | 4 ++- itest/test_type.py | 43 ++++++++++++++++++++++++++++ src/ti/field.c | 69 +++++++++++++++++++++++++++------------------ src/ti/spec.c | 12 ++++++++ 6 files changed, 101 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f5eedba..1089d21c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Allow converting `mpdata` to `bytes, issue #427. * Fixed: map cache for nested structure not cleared, issue #428. +* Add global `enum` definition, issue #429. * Add _anonymous_ wrap only type syntax (`&{..}`), pr * Added `ano()` function, pr diff --git a/inc/ti/spec.t.h b/inc/ti/spec.t.h index 6b645733..037b5d9a 100644 --- a/inc/ti/spec.t.h +++ b/inc/ti/spec.t.h @@ -39,6 +39,7 @@ typedef enum TI_SPEC_EMAIL, /* `email` */ TI_SPEC_URL, /* `url` */ TI_SPEC_TEL, /* `tel` */ + TI_SPEC_ENUM, /* `enum` */ TI_SPEC_REMATCH=0x5000, /* `/.../` */ TI_SPEC_INT_RANGE, /* `int<:> */ diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index b3fe2ce9..ba631db0 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -1393,9 +1393,10 @@ static inline _Bool val__spec_enum_eq_to_val(uint16_t spec, ti_val_t * val) * TI_SPEC_EMAIL, * TI_SPEC_URL, * TI_SPEC_TEL, + * TI_SPEC_ENUM, */ -static ti_val_spec_t ti_val_spec_map[24] = { +static ti_val_spec_t ti_val_spec_map[25] = { {.is_spec=ti_val_is_thing}, {.is_spec=ti_val_is_raw}, {.is_spec=ti_val_is_str}, @@ -1420,6 +1421,7 @@ static ti_val_spec_t ti_val_spec_map[24] = { {.is_spec=ti_val_is_email}, {.is_spec=ti_val_is_url}, {.is_spec=ti_val_is_tel}, + {.is_spec=ti_val_is_member}, }; static inline _Bool ti_val_is_spec(ti_val_t * val, uint16_t spec) diff --git a/itest/test_type.py b/itest/test_type.py index 3042a010..457a6afe 100755 --- a/itest/test_type.py +++ b/itest/test_type.py @@ -1185,6 +1185,7 @@ async def test_type_definitions(self, client): set_type('_Email', {test: 'email'}); set_type('_Url', {test: 'url'}); set_type('_Tel', {test: 'tel'}); + set_type('_Enum', {test: 'enum'}); set_type('_Any', {test: 'any'}); ''') @@ -2330,6 +2331,48 @@ async def test_to_type_no_store(self, client0): """) self.assertEqual(r, "default") + async def test_global_enum(self, client): + await client.query( + """//ti + set_enum('E', {A: 0}); + set_type('T', { + e: 'E' + }); + set_type('F', { + e: 'enum' + }); + """) + res = await client.query( + """//ti + .t = T{}; + .f = F{}; + [.t.e, .f.e]; + """) + self.assertEqual(res, [0, None]) + res = await client.query( + """//ti + .t = T{}; + .f = F{}; + return [.t.wrap('F'), .f.wrap('T')], 1, NO_IDS; + """) + self.assertEqual(res, [{'e': 0}, {}]) + res = await client.query( + """//ti + .f.e = nil; + .f.e = E{A}; + """) + self.assertEqual(res, 0) + + with self.assertRaisesRegex( + OperationError, + r'cannot apply type declaration `E` to `e` on type `F` ' + r'without a closure to migrate existing instances; ' + r'the old declaration `enum` is not compatible with ' + r'the new declaration;'): + await client.query("""//ti + mod_type('F', 'mod', 'e', 'E'); + """) + if __name__ == '__main__': run_test(TestType()) diff --git a/src/ti/field.c b/src/ti/field.c index 7959ab52..d7b22ca8 100644 --- a/src/ti/field.c +++ b/src/ti/field.c @@ -294,11 +294,11 @@ static inline void field__set_cb(ti_field_t * field, ti_field_dval_cb cb) */ enum { - TOTAL_KEYWORDS = 25, + TOTAL_KEYWORDS = 26, MIN_WORD_LENGTH = 2, MAX_WORD_LENGTH = 8, MIN_HASH_VALUE = 2, - MAX_HASH_VALUE = 29 + MAX_HASH_VALUE = 27 }; static inline unsigned int field__hash( @@ -307,32 +307,32 @@ static inline unsigned int field__hash( { static unsigned short asso_values[] = { - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 13, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 8, 30, 8, 30, 30, 30, 9, 6, 0, - 0, 4, 3, 1, 9, 0, 30, 4, 0, 4, - 1, 0, 9, 30, 0, 8, 0, 0, 0, 0, - 1, 0, 30, 0, 30, 0, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30 + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 14, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 11, 28, 11, 28, 28, 28, 8, 1, 6, + 0, 1, 8, 6, 4, 3, 28, 0, 0, 6, + 1, 0, 9, 28, 0, 8, 0, 0, 0, 3, + 5, 1, 28, 0, 28, 0, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28 }; register unsigned int hval = n; @@ -393,6 +393,7 @@ ti_field_map_t field__mapping[TOTAL_KEYWORDS] = { {.name="email", .spec=TI_SPEC_EMAIL, .dval_cb=field__dval_str}, {.name="url", .spec=TI_SPEC_URL, .dval_cb=field__dval_str}, {.name="tel", .spec=TI_SPEC_TEL, .dval_cb=field__dval_str}, + {.name="enum", .spec=TI_SPEC_ENUM, .dval_cb=field__dval_nil}, }; static ti_field_map_t * field__map[MAX_HASH_VALUE+1]; @@ -1960,6 +1961,10 @@ int ti_field_make_assignable( (ti_raw_t *) *val)) goto tel_error; return 0; + case TI_SPEC_ENUM: + if (ti_val_is_member(*val) || ti_val_is_nil(*val)) + return 0; + goto type_error; case TI_SPEC_ARR: if (ti_val_is_array(*val)) return field__varr_assign(field, (ti_varr_t **) val, parent, e); @@ -2265,6 +2270,8 @@ _Bool ti_field_maps_to_val(ti_field_t * field, ti_val_t * val) return ti_val_is_str(val) && ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val); + case TI_SPEC_ENUM: + return (ti_val_is_member(val) || ti_val_is_nil(val)); case TI_SPEC_ARR: /* we can map a set to an array */ return (( @@ -2337,6 +2344,8 @@ static _Bool field__maps_to_nested(ti_field_t * t_field, ti_field_t * f_field) f_field->type->types->collection->enums, f_spec & TI_ENUM_ID_MASK); f_spec = ti_enum_spec(enum_); + if (t_spec == TI_SPEC_ENUM) + return true; } if (t_spec == f_spec) @@ -2388,6 +2397,7 @@ static _Bool field__maps_to_nested(ti_field_t * t_field, ti_field_t * f_field) case TI_SPEC_EMAIL: case TI_SPEC_URL: case TI_SPEC_TEL: + case TI_SPEC_ENUM: case TI_SPEC_ARR: case TI_SPEC_SET: case TI_SPEC_REMATCH: @@ -2433,6 +2443,8 @@ _Bool ti_field_maps_to_field(ti_field_t * t_field, ti_field_t * f_field) f_field->type->types->collection->enums, f_spec & TI_ENUM_ID_MASK); f_spec = ti_enum_spec(enum_); + if (t_spec == TI_SPEC_ENUM) + return true; } switch ((ti_spec_enum_t) t_spec) @@ -2512,6 +2524,7 @@ _Bool ti_field_maps_to_field(ti_field_t * t_field, ti_field_t * f_field) case TI_SPEC_EMAIL: case TI_SPEC_URL: case TI_SPEC_TEL: + case TI_SPEC_ENUM: return f_spec == t_spec; case TI_SPEC_ARR: return ( diff --git a/src/ti/spec.c b/src/ti/spec.c index f300b14f..2e6fec21 100644 --- a/src/ti/spec.c +++ b/src/ti/spec.c @@ -408,6 +408,10 @@ ti_spec_rval_enum ti__spec_check_nested_val(uint16_t spec, ti_val_t * val) : ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val) ? 0 : TI_SPEC_RVAL_TEL_ERROR; + case TI_SPEC_ENUM: + return (ti_val_is_member(val) || ti_val_is_nil(val)) + ? 0 + : TI_SPEC_RVAL_TYPE_ERROR; case TI_SPEC_REMATCH: case TI_SPEC_INT_RANGE: case TI_SPEC_FLOAT_RANGE: @@ -504,6 +508,8 @@ _Bool ti__spec_maps_to_nested_val(uint16_t spec, ti_val_t * val) return ti_val_is_str(val) && ti_regex_test_or_empty( (ti_regex_t *) ti_val_borrow_re_tel(), (ti_raw_t *) val); + case TI_SPEC_ENUM: + return (ti_val_is_member(val) || ti_val_is_nil(val)); case TI_SPEC_REMATCH: case TI_SPEC_INT_RANGE: case TI_SPEC_FLOAT_RANGE: @@ -556,6 +562,7 @@ const char * ti_spec_approx_type_str(uint16_t spec) case TI_SPEC_EMAIL: return "email"; case TI_SPEC_URL: return "url"; case TI_SPEC_TEL: return "tel"; + case TI_SPEC_ENUM: return "enum"; case TI_SPEC_TYPE: case TI_SPEC_ARR_TYPE: assert(0); /* not possible for wrap-only */ @@ -673,6 +680,11 @@ ti_spec_mod_enum ti_spec_check_mod( case TI_SPEC_URL: case TI_SPEC_TEL: return ospec == nspec ? TI_SPEC_MOD_SUCCESS : TI_SPEC_MOD_ERR; + case TI_SPEC_ENUM: + return ( + ospec == TI_SPEC_ENUM || + ti_spec_is_enum(ospec) + ) ? TI_SPEC_MOD_SUCCESS : TI_SPEC_MOD_ERR; case TI_SPEC_REMATCH: return TI_SPEC_MOD_ERR; case TI_SPEC_INT_RANGE: From a2f8dd0f377d511a7a4f1e5a527c482047037d9a Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Sun, 9 Nov 2025 08:59:22 +0100 Subject: [PATCH 07/13] Upd tests, memleak for modules test --- CHANGELOG.md | 4 ++-- itest/lib/vars.py | 16 +++++++++++++++- itest/test_collection_functions.py | 4 ++-- itest/test_thingsdb_functions.py | 4 +++- memleak.supp | 8 +++++++- src/langdef/translate.c | 2 ++ 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1089d21c..7639f4bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,8 @@ * Allow converting `mpdata` to `bytes, issue #427. * Fixed: map cache for nested structure not cleared, issue #428. * Add global `enum` definition, issue #429. -* Add _anonymous_ wrap only type syntax (`&{..}`), pr -* Added `ano()` function, pr +* Add _anonymous_ wrap only type syntax (`&{..}`), pr #430. +* Added `ano()` function, pr #430. # v1.8.1 diff --git a/itest/lib/vars.py b/itest/lib/vars.py index f508b2cc..1660f90e 100644 --- a/itest/lib/vars.py +++ b/itest/lib/vars.py @@ -53,7 +53,7 @@ f'--suppressions={MEMLEAK_SUPP}', '--errors-for-leak-kinds=all', ], - # full and vebose memcheck + # full and verbose memcheck [ 'valgrind', '--tool=memcheck', @@ -66,6 +66,20 @@ '--errors-for-leak-kinds=all', '-v', ], + # full, verbose memcheck and gen suppressions + [ + 'valgrind', + '--tool=memcheck', + '--error-exitcode=1', + '--leak-check=full', + '--show-leak-kinds=all', + '--track-origins=yes', + '--show-reachable=yes', + '--gen-suppressions=all', + f'--suppressions={MEMLEAK_SUPP}', + '--errors-for-leak-kinds=all', + '-v', + ], ][int(os.environ.get('THINGSDB_MEMCHECK', 1))] except ValueError: diff --git a/itest/test_collection_functions.py b/itest/test_collection_functions.py index 37d71d68..b80c3835 100755 --- a/itest/test_collection_functions.py +++ b/itest/test_collection_functions.py @@ -503,7 +503,7 @@ async def test_base64_encode(self, client): with self.assertRaisesRegex( TypeError, r'function `base64_encode` expects argument 1 to be of ' - r'type `str` or type `bytes` but got type `int` instead'): + r'type `str`, `bytes` or `mpdata` but got type `int` instead'): await client.query('base64_encode(1);') self.assertEqual(await client.query('base64_encode("");'), '') @@ -2630,7 +2630,7 @@ async def test_map_wrap(self, client): with self.assertRaisesRegex( TypeError, r'function `map_wrap` expects argument 1 to be of ' - r'type `str` but got type `nil` instead;'): + r'type `str` or `` but got type `nil` instead;'): await client.query('[].map_wrap(nil);') with self.assertRaisesRegex( diff --git a/itest/test_thingsdb_functions.py b/itest/test_thingsdb_functions.py index fe06fe39..e76e420f 100755 --- a/itest/test_thingsdb_functions.py +++ b/itest/test_thingsdb_functions.py @@ -118,7 +118,7 @@ async def test_collections_info(self, client): collections = await client.query('collections_info();') self.assertEqual(len(collections), 1) - self.assertEqual(len(collections[0]), 8) + self.assertEqual(len(collections[0]), 9) self.assertIn("collection_id", collections[0]) self.assertIn("next_free_id", collections[0]) @@ -127,6 +127,7 @@ async def test_collections_info(self, client): self.assertIn("created_at", collections[0]) self.assertIn("time_zone", collections[0]) self.assertIn("default_deep", collections[0]) + self.assertIn("ano_types", collections[0]) self.assertIn("commit_history", collections[0]) self.assertTrue(isinstance(collections[0]["collection_id"], int)) @@ -136,6 +137,7 @@ async def test_collections_info(self, client): self.assertTrue(isinstance(collections[0]["created_at"], int)) self.assertTrue(isinstance(collections[0]["time_zone"], str)) self.assertTrue(isinstance(collections[0]["default_deep"], int)) + self.assertTrue(isinstance(collections[0]["ano_types"], int)) self.assertEqual(collections[0]["commit_history"], "disabled") # at least one info should be checked for a correct created_at info diff --git a/memleak.supp b/memleak.supp index 9ca9fd03..a5179e2d 100644 --- a/memleak.supp +++ b/memleak.supp @@ -88,4 +88,10 @@ fun:lws_create_context ... } - +{ + + Memcheck:Leak + ... + obj:/usr/lib/x86_64-linux-gnu/libcrypto.so* + ... +} diff --git a/src/langdef/translate.c b/src/langdef/translate.c index 98334c3c..9822bff5 100644 --- a/src/langdef/translate.c +++ b/src/langdef/translate.c @@ -19,11 +19,13 @@ const char * langdef_translate(cleri_t * elem) case CLERI_GID_OPR6_COMPARE: case CLERI_GID_OPR7_CMP_AND: case CLERI_GID_OPR8_CMP_OR: + case CLERI_GID_T_ANO: case CLERI_GID_T_FALSE: case CLERI_GID_T_INT: case CLERI_GID_T_NIL: case CLERI_GID_T_STRING: case CLERI_GID_T_TRUE: + case CLERI_GID_X_ANO: case CLERI_GID_X_ARRAY: case CLERI_GID_X_ASSIGN: case CLERI_GID_X_BLOCK: From e28301bae513d481061aee789af9c8c8211cbd47 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 10 Nov 2025 08:39:46 +0100 Subject: [PATCH 08/13] Upd test --- inc/ti/val.inline.h | 2 +- itest/test_ano.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/inc/ti/val.inline.h b/inc/ti/val.inline.h index ba631db0..1cad777e 100644 --- a/inc/ti/val.inline.h +++ b/inc/ti/val.inline.h @@ -1274,10 +1274,10 @@ static inline int ti_val_make_assignable( case TI_VAL_CLOSURE: return ti_closure_unbound((ti_closure_t *) *val, e); case TI_VAL_ANO: + case TI_VAL_WANO: return 0; case TI_VAL_FUTURE: case TI_VAL_MODULE: - case TI_VAL_WANO: ti_val_unsafe_drop(*val); *val = (ti_val_t *) ti_nil_get(); return 0; diff --git a/itest/test_ano.py b/itest/test_ano.py index 34c32f87..e7c64f3a 100755 --- a/itest/test_ano.py +++ b/itest/test_ano.py @@ -39,12 +39,6 @@ async def test_ano_err(self, q, r): set_type('A', {x: 'any'}); """) - res = await q("""//ti - .x = {}.wrap(&{}); - .x; - """) - self.assertIs(res, None) - with self.assertRaisesRegex( LookupError, r'function `ano` is undefined in the `@thingsdb` scope; ' @@ -275,6 +269,12 @@ async def test_after_mod(self, q, r): {'age': 1, 'upper': 'PERSON1'}, {'age': 2, 'upper': 'PERSON2'}]) + await q("""//ti + t = &{name: 'str'}; + .w = {nested: {t: {name: 'foo'}}}.wrap(&{nested: {t:,}}); + """) + res = await q('.w;') + self.assertEqual(res, {"nested": {'t': {'name': 'foo'}}}) From 9109a4ecf46ff26b57be616641469e36f2bdce28 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 10 Nov 2025 12:13:40 +0100 Subject: [PATCH 09/13] Fixed #431 --- CHANGELOG.md | 3 +- inc/ti/spec.h | 3 +- inc/ti/spec.inline.h | 8 +-- inc/ti/version.h | 2 +- itest/test_advanced.py | 1 - itest/test_ano.py | 125 ++++++++++++++++++++--------------------- itest/test_enum.py | 65 +++++++++++++++++++++ itest/test_wrap.py | 1 - src/ti/field.c | 48 +++++++++++----- src/ti/spec.c | 12 +++- 10 files changed, 180 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7639f4bc..8e9392bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,11 @@ -# v1.8.2-alpha0 +# v1.8.2-alpha3 * Allow converting `mpdata` to `bytes, issue #427. * Fixed: map cache for nested structure not cleared, issue #428. * Add global `enum` definition, issue #429. * Add _anonymous_ wrap only type syntax (`&{..}`), pr #430. * Added `ano()` function, pr #430. +* Definition `*str` now exposes enumerator keys, issue #431. # v1.8.1 diff --git a/inc/ti/spec.h b/inc/ti/spec.h index cc20c567..6fe56fba 100644 --- a/inc/ti/spec.h +++ b/inc/ti/spec.h @@ -10,9 +10,10 @@ #include #include #include +#include ti_spec_rval_enum ti__spec_check_nested_val(uint16_t spec, ti_val_t * val); -_Bool ti__spec_maps_to_nested_val(uint16_t spec, ti_val_t * val); +_Bool ti__spec_maps_to_nested_val(ti_field_t * field, ti_val_t * val); const char * ti_spec_approx_type_str(uint16_t spec); ti_spec_mod_enum ti_spec_check_mod( diff --git a/inc/ti/spec.inline.h b/inc/ti/spec.inline.h index 9c6f923f..74f4e2e8 100644 --- a/inc/ti/spec.inline.h +++ b/inc/ti/spec.inline.h @@ -36,12 +36,12 @@ static inline ti_spec_rval_enum ti_spec_check_nested_val( : ti__spec_check_nested_val(spec & TI_SPEC_MASK_NILLABLE, val); } -static inline _Bool ti_spec_maps_to_nested_val(uint16_t spec, ti_val_t * val) +static inline _Bool ti_spec_maps_to_nested_val(ti_field_t * field, ti_val_t * val) { return ( - spec == TI_SPEC_ANY || - ((spec & TI_SPEC_NILLABLE) && ti_val_is_nil(val)) || - ti__spec_maps_to_nested_val(spec & TI_SPEC_MASK_NILLABLE, val) + field->nested_spec == TI_SPEC_ANY || + ((field->nested_spec & TI_SPEC_NILLABLE) && ti_val_is_nil(val)) || + ti__spec_maps_to_nested_val(field, val) ); } diff --git a/inc/ti/version.h b/inc/ti/version.h index 96d001b8..58637dd1 100644 --- a/inc/ti/version.h +++ b/inc/ti/version.h @@ -25,7 +25,7 @@ * "-rc0" * "" */ -#define TI_VERSION_PRE_RELEASE "-alpha2" +#define TI_VERSION_PRE_RELEASE "-alpha3" #define TI_MAINTAINER \ "Jeroen van der Heijden " diff --git a/itest/test_advanced.py b/itest/test_advanced.py index 256f2ead..529afe6a 100755 --- a/itest/test_advanced.py +++ b/itest/test_advanced.py @@ -2928,6 +2928,5 @@ async def test_mod_nested(self, client): }) - if __name__ == '__main__': run_test(TestAdvanced()) diff --git a/itest/test_ano.py b/itest/test_ano.py index e7c64f3a..80030237 100755 --- a/itest/test_ano.py +++ b/itest/test_ano.py @@ -64,7 +64,7 @@ async def test_ano_err(self, q, r): with self.assertRaisesRegex( TypeError, - r'expecting a nested structure \(`list` or `thing`\), ' \ + r'expecting a nested structure \(`list` or `thing`\), ' r'a method of type `closure` or a definition ' r'of type `str` but got type `int` instead'): await q( @@ -103,81 +103,81 @@ async def test_more_ano_props(self, q, r): .a.f(20, 22); """) self.assertEqual(res, 42) - r1, r2 = await q("""//ti - o = { - name: 'Iris', + r1, r2 = await q( + """//ti + o = { + name: 'Iris', + numbers: [{ + x: 1, + y: 2, + }, { + x: 4, + }, { + y: 5, + }] + }; + [ + o.wrap(&{ + name: |this| this.name.upper(), numbers: [{ - x: 1, - y: 2, - }, { - x: 4, - }, { - y: 5, + x: 'int' }] - }; - [ - o.wrap(&{ - name: |this| this.name.upper(), - numbers: [{ - x: 'int' - }] - }), - o.wrap(ano({ - name: |this| this.name.upper(), - numbers: [{ - x: 'int' - }] - })), - ]; - """ - ) + }), + o.wrap(ano({ + name: |this| this.name.upper(), + numbers: [{ + x: 'int' + }] + })), + ]; + """) self.assertEqual(r1, { "name": "IRIS", - "numbers": [{"x": 1,}, {"x": 4}, {}] + "numbers": [{"x": 1}, {"x": 4}, {}] }) self.assertEqual(r1, r2) - await q("""//ti - o = { - name: 'Iris', - numbers: [{ - x: 1, - y: 2, - }, { - x: 4, - }, { - y: 5, - }] - }; - .a1 = &{ + await q( + """//ti + o = { + name: 'Iris', + numbers: [{ + x: 1, + y: 2, + }, { + x: 4, + }, { + y: 5, + }] + }; + .a1 = &{ + name: |this| this.name.upper(), + numbers: [{ + x: 'int' + }] + }; + .a2 = ano({ + name: |this| this.name.upper(), + numbers: [{ + x: 'int' + }] + }); + .wano = [ + o.wrap(&{ name: |this| this.name.upper(), numbers: [{ x: 'int' }] - }; - .a2 = ano({ + }), + o.wrap(ano({ name: |this| this.name.upper(), numbers: [{ x: 'int' }] - }); - .wano = [ - o.wrap(&{ - name: |this| this.name.upper(), - numbers: [{ - x: 'int' - }] - }), - o.wrap(ano({ - name: |this| this.name.upper(), - numbers: [{ - x: 'int' - }] - })), - o.wrap(.a1), - o.wrap(.a2), - ]; - """ - ) + })), + o.wrap(.a1), + o.wrap(.a2), + ]; + """) r1, r2, r3, r4 = await q("""//ti .wano; """) @@ -277,6 +277,5 @@ async def test_after_mod(self, q, r): self.assertEqual(res, {"nested": {'t': {'name': 'foo'}}}) - if __name__ == '__main__': run_test(TestAno()) diff --git a/itest/test_enum.py b/itest/test_enum.py index b470fd95..d5f69fad 100755 --- a/itest/test_enum.py +++ b/itest/test_enum.py @@ -1117,6 +1117,71 @@ async def test_def_max_enum(self, client): 'reached the maximum number of enumerators'): await client.query(r'''set_enum('E', {X: 0});''') + async def test_wrap_enum_name_str(self, client): + # bug #431 + await client.query( + """//ti + set_enum('E', {A: 41, B: 42}); + .e = E{B}; + """) + res = await client.query("""//ti + .wrap(&{e: 'str'}) + """) + self.assertEqual(res, {}) + res = await client.query("""//ti + .wrap(&{e: '*str'}) + """) + self.assertEqual(res, {"e": 'B'}) + res = await client.query("""//ti + .wrap(&{e: 'int'}) + """) + self.assertEqual(res, {"e": 42}) + res = await client.query("""//ti + .wrap(&{e: '*int'}) + """) + self.assertEqual(res, {}) + res = await client.query("""//ti + .wrap(&{e: 'enum'}) + """) + self.assertEqual(res, {"e": 42}) + res = await client.query("""//ti + .wrap(&{e: '*enum'}) + """) + self.assertEqual(res, {"e": 'B'}) + + async def test_wrap_enum_name_str_on_type(self, client): + # bug #431 (like above, but then a type mapping) + await client.query( + """//ti + set_enum('E', {A: 41, B: 42}); + set_type('R', {e: 'E'}); + .to_type('R'); + """) + res = await client.query("""//ti + .wrap(&{e: 'str'}) + """) + self.assertEqual(res, {}) + res = await client.query("""//ti + .wrap(&{e: '*str'}) + """) + self.assertEqual(res, {"e": 'A'}) + res = await client.query("""//ti + .wrap(&{e: 'int'}) + """) + self.assertEqual(res, {"e": 41}) + res = await client.query("""//ti + .wrap(&{e: '*int'}) + """) + self.assertEqual(res, {}) + res = await client.query("""//ti + .wrap(&{e: 'enum'}) + """) + self.assertEqual(res, {"e": 41}) + res = await client.query("""//ti + .wrap(&{e: '*enum'}) + """) + self.assertEqual(res, {"e": 'A'}) + if __name__ == '__main__': run_test(TestEnum()) diff --git a/itest/test_wrap.py b/itest/test_wrap.py index 3d5d6da4..33e533c5 100755 --- a/itest/test_wrap.py +++ b/itest/test_wrap.py @@ -136,7 +136,6 @@ async def test_wrap_err(self, client): nil.map_wrap(&{}); ''') - async def test_wrap_method(self, client): res = await client.query(r''' set_type('Math', { diff --git a/src/ti/field.c b/src/ti/field.c index d7b22ca8..3facd838 100644 --- a/src/ti/field.c +++ b/src/ti/field.c @@ -931,7 +931,6 @@ static int field__init(ti_field_t * field, ex_t * e) DOC_T_TYPE, field->name->str, field->type->name, field->spec_raw->n, (const char *) field->spec_raw->data); - return e->nr; circular_dep: @@ -1699,7 +1698,7 @@ static _Bool field__maps_arr_to_arr(ti_field_t * field, ti_varr_t * varr) return true; for (vec_each(varr->vec, ti_val_t, val)) - if (!ti_spec_maps_to_nested_val(field->nested_spec, val)) + if (!ti_spec_maps_to_nested_val(field, val)) return false; return true; @@ -1715,7 +1714,7 @@ static _Bool field__maps_arr_to_type(ti_varr_t * varr) static int field__map_restrict_cb(ti_prop_t * prop, ti_field_t * field) { - return !ti_spec_maps_to_nested_val(field->nested_spec, prop->val); + return !ti_spec_maps_to_nested_val(field, prop->val); } static _Bool field__maps_restricted(ti_field_t * field, ti_thing_t * thing) @@ -1736,7 +1735,7 @@ static _Bool field__maps_restricted(ti_field_t * field, ti_thing_t * thing) field); for (vec_each(thing->items.vec, ti_prop_t, prop)) - if (!ti_spec_maps_to_nested_val(field->nested_spec, prop->val)) + if (!ti_spec_maps_to_nested_val(field, prop->val)) return false; return true; @@ -2211,7 +2210,14 @@ _Bool ti_field_maps_to_val(ti_field_t * field, ti_val_t * val) return ti_spec_enum_eq_to_val(spec, val); if (ti_val_is_member(val)) - val = VMEMBER(val); + { + if (spec == TI_SPEC_ENUM) + return true; + + val = (field->flags & TI_FIELD_FLAG_ENAME) + ? (ti_val_t *) ((ti_member_t *) val)->name + : VMEMBER(val); + } switch ((ti_spec_enum_t) spec) { @@ -2340,12 +2346,20 @@ static _Bool field__maps_to_nested(ti_field_t * t_field, ti_field_t * f_field) if (f_spec >= TI_ENUM_ID_FLAG) { - ti_enum_t * enum_ = ti_enums_by_id( - f_field->type->types->collection->enums, - f_spec & TI_ENUM_ID_MASK); - f_spec = ti_enum_spec(enum_); if (t_spec == TI_SPEC_ENUM) return true; + + if (t_field->flags & TI_FIELD_FLAG_ENAME) + { + f_spec = TI_SPEC_STR; + } + else + { + ti_enum_t * enum_ = ti_enums_by_id( + f_field->type->types->collection->enums, + f_spec & TI_ENUM_ID_MASK); + f_spec = ti_enum_spec(enum_); + } } if (t_spec == f_spec) @@ -2439,12 +2453,20 @@ _Bool ti_field_maps_to_field(ti_field_t * t_field, ti_field_t * f_field) if (f_spec >= TI_ENUM_ID_FLAG) { - ti_enum_t * enum_ = ti_enums_by_id( - f_field->type->types->collection->enums, - f_spec & TI_ENUM_ID_MASK); - f_spec = ti_enum_spec(enum_); if (t_spec == TI_SPEC_ENUM) return true; + + if (t_field->flags & TI_FIELD_FLAG_ENAME) + { + f_spec = TI_SPEC_STR; + } + else + { + ti_enum_t * enum_ = ti_enums_by_id( + f_field->type->types->collection->enums, + f_spec & TI_ENUM_ID_MASK); + f_spec = ti_enum_spec(enum_); + } } switch ((ti_spec_enum_t) t_spec) diff --git a/src/ti/spec.c b/src/ti/spec.c index 2e6fec21..a054da87 100644 --- a/src/ti/spec.c +++ b/src/ti/spec.c @@ -436,15 +436,21 @@ ti_spec_rval_enum ti__spec_check_nested_val(uint16_t spec, ti_val_t * val) : TI_SPEC_RVAL_TYPE_ERROR; } -_Bool ti__spec_maps_to_nested_val(uint16_t spec, ti_val_t * val) +_Bool ti__spec_maps_to_nested_val(ti_field_t * field, ti_val_t * val) { - assert(~spec & TI_SPEC_NILLABLE); + uint16_t spec = field->nested_spec & TI_SPEC_MASK_NILLABLE; if (spec >= TI_ENUM_ID_FLAG) return ti_spec_enum_eq_to_val(spec, val); if (ti_val_is_member(val)) - val = VMEMBER(val); + { + if (spec == TI_SPEC_ENUM) + return true; + val = (field->flags & TI_FIELD_FLAG_ENAME) + ? (ti_val_t *) ((ti_member_t *) val)->name + : VMEMBER(val); + } switch ((ti_spec_enum_t) spec) { From 442c8754ae6baeafdc05f30c0c74d6a6e696b719 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 10 Nov 2025 12:22:18 +0100 Subject: [PATCH 10/13] added test with invalid type keys --- itest/test_ano.py | 9 +++++++++ src/ti/ano.c | 7 ------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/itest/test_ano.py b/itest/test_ano.py index 80030237..f003f5ce 100755 --- a/itest/test_ano.py +++ b/itest/test_ano.py @@ -92,6 +92,15 @@ async def test_ano_err(self, q, r): &{nested: {t: 'T'}}; """) + with self.assertRaisesRegex( + ValueError, + r'type keys must follow the naming rules'): + await q("""//ti + t = {}; + t['key with spaces'] = 'str'; + ano(t); + """) + async def test_more_ano_props(self, q, r): res = await q("""//ti .a = &{ diff --git a/src/ti/ano.c b/src/ti/ano.c index d53fa0fe..7f492e3a 100644 --- a/src/ti/ano.c +++ b/src/ti/ano.c @@ -128,13 +128,6 @@ ti_ano_t * ti_ano_from_raw( ti_ano_destroy(ano); return NULL; } - /* This is used for quickly loading equal ano from cache, its a weak - * ref and the call is not critical; It should be done here, and not - * init as we want to cache ano(..) calls, and loading from changes/stored - * on disk, but not from syntax in queries as they are cached as immutable - * variable; */ - - return ano; } From 22bd34dbc986d1bf01a771b9adbac3bfe364712b Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 10 Nov 2025 12:25:47 +0100 Subject: [PATCH 11/13] add comment --- src/ti/ano.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ti/ano.c b/src/ti/ano.c index 7f492e3a..06a7f365 100644 --- a/src/ti/ano.c +++ b/src/ti/ano.c @@ -55,6 +55,7 @@ int ti_ano_init( goto fail0; } + /* can't be a dict; this is not allowed by the &{..} and ano() function */ for (vec_each(((ti_thing_t *) val)->items.vec, ti_prop_t, prop)) { ti_raw_t * sr = (ti_raw_t *) prop->val; From 3cfd4a07013e934bd74fb711f2e6416d1ca43239 Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 10 Nov 2025 12:28:59 +0100 Subject: [PATCH 12/13] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e9392bc..1776787d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # v1.8.2-alpha3 -* Allow converting `mpdata` to `bytes, issue #427. +* Allow converting `mpdata` to `bytes`, issue #427. * Fixed: map cache for nested structure not cleared, issue #428. * Add global `enum` definition, issue #429. * Add _anonymous_ wrap only type syntax (`&{..}`), pr #430. From ef34053df1f833a89e78f1ada3f5d3317c6172ab Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Mon, 10 Nov 2025 13:41:16 +0100 Subject: [PATCH 13/13] Added tests --- itest/test_ano.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/itest/test_ano.py b/itest/test_ano.py index f003f5ce..cefc5179 100755 --- a/itest/test_ano.py +++ b/itest/test_ano.py @@ -284,7 +284,20 @@ async def test_after_mod(self, q, r): """) res = await q('.w;') self.assertEqual(res, {"nested": {'t': {'name': 'foo'}}}) - + res = await q("""//ti + c = .w.copy(); + assert(is_thing(c)); + assert(is_nil(c.id())); + return c, 3; + """) + self.assertEqual(res, {"nested": {'t': {'name': 'foo'}}}) + res = await q("""//ti + c = .w.dup(); + assert(is_thing(c.unwrap())); + assert(is_nil(c.id())); + c; + """) + self.assertEqual(res, {"nested": {'t': {'name': 'foo'}}}) if __name__ == '__main__': run_test(TestAno())