From f741f72b9afbaff2ddc2e86c93d789ba41bbd248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:00:53 +0100 Subject: [PATCH 01/10] filterx: refactor _set_subscript_eval() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- lib/filterx/expr-set-subscript.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/filterx/expr-set-subscript.c b/lib/filterx/expr-set-subscript.c index aabecd849..f29834999 100644 --- a/lib/filterx/expr-set-subscript.c +++ b/lib/filterx/expr-set-subscript.c @@ -35,27 +35,22 @@ typedef struct _FilterXSetSubscript } FilterXSetSubscript; static FilterXObject * -_eval(FilterXExpr *s) +_set_subscript_eval(FilterXExpr *s) { FilterXSetSubscript *self = (FilterXSetSubscript *) s; FilterXObject *result = NULL; - FilterXObject *new_value = NULL, *key = NULL, *object = NULL; - object = filterx_expr_eval_typed(self->object); + FilterXObject *object = filterx_expr_eval_typed(self->object); if (!object) return NULL; + FilterXObject *key = NULL; if (self->key) { key = filterx_expr_eval(self->key); if (!key) goto exit; } - else - { - /* append */ - key = NULL; - } if (object->readonly) { @@ -63,7 +58,7 @@ _eval(FilterXExpr *s) goto exit; } - new_value = filterx_expr_eval(self->new_value); + FilterXObject *new_value = filterx_expr_eval(self->new_value); if (!new_value) goto exit; @@ -145,7 +140,7 @@ filterx_set_subscript_new(FilterXExpr *object, FilterXExpr *key, FilterXExpr *ne FilterXSetSubscript *self = g_new0(FilterXSetSubscript, 1); filterx_expr_init_instance(&self->super); - self->super.eval = _eval; + self->super.eval = _set_subscript_eval; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; From 50235f0114582e216de0bd89eaaa3088dc99670f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:06:53 +0100 Subject: [PATCH 02/10] filterx: change evaluation order of set-subscript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a preparation step for introducing the =? assignment. We should evaluate operands consistently, and from now on, the evaluation order is from right to left. Signed-off-by: László Várady --- lib/filterx/expr-set-subscript.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/filterx/expr-set-subscript.c b/lib/filterx/expr-set-subscript.c index f29834999..bfe923b99 100644 --- a/lib/filterx/expr-set-subscript.c +++ b/lib/filterx/expr-set-subscript.c @@ -39,12 +39,16 @@ _set_subscript_eval(FilterXExpr *s) { FilterXSetSubscript *self = (FilterXSetSubscript *) s; FilterXObject *result = NULL; + FilterXObject *key = NULL; + + FilterXObject *new_value = filterx_expr_eval(self->new_value); + if (!new_value) + return NULL; FilterXObject *object = filterx_expr_eval_typed(self->object); if (!object) - return NULL; + goto exit; - FilterXObject *key = NULL; if (self->key) { key = filterx_expr_eval(self->key); @@ -58,10 +62,6 @@ _set_subscript_eval(FilterXExpr *s) goto exit; } - FilterXObject *new_value = filterx_expr_eval(self->new_value); - if (!new_value) - goto exit; - /* TODO: create ref unconditionally after implementing hierarchical CoW for JSON types * (or after creating our own dict/list repr) */ if (!new_value->weak_referenced) @@ -71,6 +71,7 @@ _set_subscript_eval(FilterXExpr *s) FilterXObject *cloned = filterx_object_clone(new_value); filterx_object_unref(new_value); + new_value = NULL; if (!filterx_object_set_subscript(object, key, &cloned)) { @@ -83,6 +84,7 @@ _set_subscript_eval(FilterXExpr *s) } exit: + filterx_object_unref(new_value); filterx_object_unref(key); filterx_object_unref(object); return result; From 6bc7d9664b82932131de78909781623234f6a8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:22:12 +0100 Subject: [PATCH 03/10] filterx: extract _set_subscript() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- lib/filterx/expr-set-subscript.c | 57 +++++++++++++++++--------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/lib/filterx/expr-set-subscript.c b/lib/filterx/expr-set-subscript.c index bfe923b99..7fa92e03e 100644 --- a/lib/filterx/expr-set-subscript.c +++ b/lib/filterx/expr-set-subscript.c @@ -34,6 +34,36 @@ typedef struct _FilterXSetSubscript FilterXExpr *new_value; } FilterXSetSubscript; +static inline FilterXObject * +_set_subscript(FilterXSetSubscript *self, FilterXObject *object, FilterXObject *key, FilterXObject **new_value) +{ + if (object->readonly) + { + filterx_eval_push_error("Object set-subscript failed, object is readonly", &self->super, key); + return NULL; + } + + /* TODO: create ref unconditionally after implementing hierarchical CoW for JSON types + * (or after creating our own dict/list repr) */ + if (!(*new_value)->weak_referenced) + { + *new_value = filterx_ref_new(*new_value); + } + + FilterXObject *cloned = filterx_object_clone(*new_value); + filterx_object_unref(*new_value); + *new_value = NULL; + + if (!filterx_object_set_subscript(object, key, &cloned)) + { + filterx_eval_push_error("Object set-subscript failed", &self->super, key); + filterx_object_unref(cloned); + return NULL; + } + + return cloned; +} + static FilterXObject * _set_subscript_eval(FilterXExpr *s) { @@ -56,32 +86,7 @@ _set_subscript_eval(FilterXExpr *s) goto exit; } - if (object->readonly) - { - filterx_eval_push_error("Object set-subscript failed, object is readonly", s, key); - goto exit; - } - - /* TODO: create ref unconditionally after implementing hierarchical CoW for JSON types - * (or after creating our own dict/list repr) */ - if (!new_value->weak_referenced) - { - new_value = filterx_ref_new(new_value); - } - - FilterXObject *cloned = filterx_object_clone(new_value); - filterx_object_unref(new_value); - new_value = NULL; - - if (!filterx_object_set_subscript(object, key, &cloned)) - { - filterx_eval_push_error("Object set-subscript failed", s, key); - filterx_object_unref(cloned); - } - else - { - result = cloned; - } + result = _set_subscript(self, object, key, &new_value); exit: filterx_object_unref(new_value); From ddb2345a8d7e6e7277c9cae241d87a20109a2726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:28:28 +0100 Subject: [PATCH 04/10] filterx: add filterx_nullv_set_subscript_new() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- lib/filterx/expr-set-subscript.c | 70 +++++++++++++++++++++++++++++++- lib/filterx/expr-set-subscript.h | 2 +- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/lib/filterx/expr-set-subscript.c b/lib/filterx/expr-set-subscript.c index 7fa92e03e..341c63c7c 100644 --- a/lib/filterx/expr-set-subscript.c +++ b/lib/filterx/expr-set-subscript.c @@ -24,6 +24,10 @@ #include "filterx/object-primitive.h" #include "filterx/filterx-eval.h" #include "filterx/filterx-ref.h" +#include "filterx/filterx-object-istype.h" +#include "filterx/filterx-eval.h" +#include "filterx/object-null.h" +#include "filterx/object-message-value.h" #include "scratch-buffers.h" typedef struct _FilterXSetSubscript @@ -37,7 +41,7 @@ typedef struct _FilterXSetSubscript static inline FilterXObject * _set_subscript(FilterXSetSubscript *self, FilterXObject *object, FilterXObject *key, FilterXObject **new_value) { - if (object->readonly) + if (object->readonly) { filterx_eval_push_error("Object set-subscript failed, object is readonly", &self->super, key); return NULL; @@ -64,6 +68,53 @@ _set_subscript(FilterXSetSubscript *self, FilterXObject *object, FilterXObject * return cloned; } +static inline FilterXObject * +_suppress_error(void) +{ + msg_debug("FILTERX null coalesce assignment supressing error", filterx_format_last_error()); + filterx_eval_clear_errors(); + + return filterx_null_new(); +} + +static FilterXObject * +_nullv_set_subscript_eval(FilterXExpr *s) +{ + FilterXSetSubscript *self = (FilterXSetSubscript *) s; + FilterXObject *result = NULL; + FilterXObject *key = NULL; + + FilterXObject *new_value = filterx_expr_eval(self->new_value); + if (!new_value || filterx_object_is_type(new_value, &FILTERX_TYPE_NAME(null)) + || (filterx_object_is_type(new_value, &FILTERX_TYPE_NAME(message_value)) + && filterx_message_value_get_type(new_value) == LM_VT_NULL)) + { + if (!new_value) + return _suppress_error(); + + return new_value; + } + + FilterXObject *object = filterx_expr_eval_typed(self->object); + if (!object) + goto exit; + + if (self->key) + { + key = filterx_expr_eval(self->key); + if (!key) + goto exit; + } + + result = _set_subscript(self, object, key, &new_value); + +exit: + filterx_object_unref(new_value); + filterx_object_unref(key); + filterx_object_unref(object); + return result; +} + static FilterXObject * _set_subscript_eval(FilterXExpr *s) { @@ -141,6 +192,23 @@ _free(FilterXExpr *s) filterx_expr_free_method(s); } +FilterXExpr * +filterx_nullv_set_subscript_new(FilterXExpr *object, FilterXExpr *key, FilterXExpr *new_value) +{ + FilterXSetSubscript *self = g_new0(FilterXSetSubscript, 1); + + filterx_expr_init_instance(&self->super); + self->super.eval = _nullv_set_subscript_eval; + self->super.init = _init; + self->super.deinit = _deinit; + self->super.free_fn = _free; + self->object = object; + self->key = key; + self->new_value = new_value; + self->super.ignore_falsy_result = TRUE; + return &self->super; +} + FilterXExpr * filterx_set_subscript_new(FilterXExpr *object, FilterXExpr *key, FilterXExpr *new_value) { diff --git a/lib/filterx/expr-set-subscript.h b/lib/filterx/expr-set-subscript.h index 8b2aed05b..d81b99625 100644 --- a/lib/filterx/expr-set-subscript.h +++ b/lib/filterx/expr-set-subscript.h @@ -26,6 +26,6 @@ #include "filterx/filterx-expr.h" FilterXExpr *filterx_set_subscript_new(FilterXExpr *object, FilterXExpr *key, FilterXExpr *new_value); - +FilterXExpr *filterx_nullv_set_subscript_new(FilterXExpr *object, FilterXExpr *key, FilterXExpr *new_value); #endif From 9246bbabc28ccfd8033101526ab31dc7c0b75055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:29:00 +0100 Subject: [PATCH 05/10] filterx: add filterx_nullv_assign_new() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- lib/filterx/expr-assign.c | 70 +++++++++++++++++++++++++++++++++------ lib/filterx/expr-assign.h | 2 +- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/lib/filterx/expr-assign.c b/lib/filterx/expr-assign.c index 04c20e4c4..e2a5d23bc 100644 --- a/lib/filterx/expr-assign.c +++ b/lib/filterx/expr-assign.c @@ -24,18 +24,15 @@ #include "filterx/object-primitive.h" #include "filterx/filterx-ref.h" #include "filterx/object-json.h" +#include "filterx/filterx-object-istype.h" +#include "filterx/filterx-eval.h" +#include "filterx/object-null.h" +#include "filterx/object-message-value.h" #include "scratch-buffers.h" -static FilterXObject * -_eval(FilterXExpr *s) +static inline FilterXObject * +_assign(FilterXBinaryOp *self, FilterXObject *value) { - FilterXBinaryOp *self = (FilterXBinaryOp *) s; - - FilterXObject *value = filterx_expr_eval(self->rhs); - - if (!value) - return NULL; - /* TODO: create ref unconditionally after implementing hierarchical CoW for JSON types * (or after creating our own dict/list repr) */ if (!value->weak_referenced) @@ -52,6 +49,59 @@ _eval(FilterXExpr *s) return value; } +static inline FilterXObject * +_suppress_error(void) +{ + msg_debug("FILTERX null coalesce assignment supressing error", filterx_format_last_error()); + filterx_eval_clear_errors(); + + return filterx_null_new(); +} + +static FilterXObject * +_nullv_assign_eval(FilterXExpr *s) +{ + FilterXBinaryOp *self = (FilterXBinaryOp *) s; + + FilterXObject *value = filterx_expr_eval(self->rhs); + + if (!value || filterx_object_is_type(value, &FILTERX_TYPE_NAME(null)) + || (filterx_object_is_type(value, &FILTERX_TYPE_NAME(message_value)) + && filterx_message_value_get_type(value) == LM_VT_NULL)) + { + if (!value) + return _suppress_error(); + + return value; + } + + return _assign(self, value); +} + +static FilterXObject * +_assign_eval(FilterXExpr *s) +{ + FilterXBinaryOp *self = (FilterXBinaryOp *) s; + + FilterXObject *value = filterx_expr_eval(self->rhs); + + if (!value) + return NULL; + + return _assign(self, value); +} + +FilterXExpr * +filterx_nullv_assign_new(FilterXExpr *lhs, FilterXExpr *rhs) +{ + FilterXBinaryOp *self = g_new0(FilterXBinaryOp, 1); + + filterx_binary_op_init_instance(self, lhs, rhs); + self->super.eval = _nullv_assign_eval; + self->super.ignore_falsy_result = TRUE; + return &self->super; +} + /* NOTE: takes the object reference */ FilterXExpr * filterx_assign_new(FilterXExpr *lhs, FilterXExpr *rhs) @@ -59,7 +109,7 @@ filterx_assign_new(FilterXExpr *lhs, FilterXExpr *rhs) FilterXBinaryOp *self = g_new0(FilterXBinaryOp, 1); filterx_binary_op_init_instance(self, lhs, rhs); - self->super.eval = _eval; + self->super.eval = _assign_eval; self->super.ignore_falsy_result = TRUE; return &self->super; } diff --git a/lib/filterx/expr-assign.h b/lib/filterx/expr-assign.h index 28d856a12..ba40faa50 100644 --- a/lib/filterx/expr-assign.h +++ b/lib/filterx/expr-assign.h @@ -26,6 +26,6 @@ #include "filterx/filterx-expr.h" FilterXExpr *filterx_assign_new(FilterXExpr *lhs, FilterXExpr *rhs); - +FilterXExpr *filterx_nullv_assign_new(FilterXExpr *lhs, FilterXExpr *rhs); #endif From c5c07770d49635f6fe2e2005f0d96ca40528ae9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:35:55 +0100 Subject: [PATCH 06/10] filterx: change evaluation order of setattr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a preparation step for introducing the =? assignment. We should evaluate operands consistently, and from now on, the evaluation order is from right to left. Signed-off-by: László Várady --- lib/filterx/expr-setattr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/filterx/expr-setattr.c b/lib/filterx/expr-setattr.c index 63ca21847..628a1e82d 100644 --- a/lib/filterx/expr-setattr.c +++ b/lib/filterx/expr-setattr.c @@ -41,9 +41,13 @@ _eval(FilterXExpr *s) FilterXSetAttr *self = (FilterXSetAttr *) s; FilterXObject *result = NULL; + FilterXObject *new_value = filterx_expr_eval(self->new_value); + if (!new_value) + return NULL; + FilterXObject *object = filterx_expr_eval_typed(self->object); if (!object) - return NULL; + goto exit; if (object->readonly) { @@ -51,10 +55,6 @@ _eval(FilterXExpr *s) goto exit; } - FilterXObject *new_value = filterx_expr_eval(self->new_value); - if (!new_value) - goto exit; - /* TODO: create ref unconditionally after implementing hierarchical CoW for JSON types * (or after creating our own dict/list repr) */ if (!new_value->weak_referenced) @@ -64,6 +64,7 @@ _eval(FilterXExpr *s) FilterXObject *cloned = filterx_object_clone(new_value); filterx_object_unref(new_value); + new_value = NULL; if (!filterx_object_setattr(object, self->attr, &cloned)) { @@ -76,6 +77,7 @@ _eval(FilterXExpr *s) } exit: + filterx_object_unref(new_value); filterx_object_unref(object); return result; } From 4b8799fe27300f5fc64f6fb41b7d2d4893c943d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:41:40 +0100 Subject: [PATCH 07/10] filterx: extract _setattr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- lib/filterx/expr-setattr.c | 57 +++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/lib/filterx/expr-setattr.c b/lib/filterx/expr-setattr.c index 628a1e82d..0fd228a39 100644 --- a/lib/filterx/expr-setattr.c +++ b/lib/filterx/expr-setattr.c @@ -35,46 +35,51 @@ typedef struct _FilterXSetAttr FilterXExpr *new_value; } FilterXSetAttr; -static FilterXObject * -_eval(FilterXExpr *s) +static inline FilterXObject * +_setattr(FilterXSetAttr *self, FilterXObject *object, FilterXObject **new_value) { - FilterXSetAttr *self = (FilterXSetAttr *) s; - FilterXObject *result = NULL; - - FilterXObject *new_value = filterx_expr_eval(self->new_value); - if (!new_value) - return NULL; - - FilterXObject *object = filterx_expr_eval_typed(self->object); - if (!object) - goto exit; - if (object->readonly) { - filterx_eval_push_error("Attribute set failed, object is readonly", s, self->attr); - goto exit; + filterx_eval_push_error("Attribute set failed, object is readonly", &self->super, self->attr); + return NULL; } /* TODO: create ref unconditionally after implementing hierarchical CoW for JSON types * (or after creating our own dict/list repr) */ - if (!new_value->weak_referenced) + if (!(*new_value)->weak_referenced) { - new_value = filterx_ref_new(new_value); + *new_value = filterx_ref_new(*new_value); } - FilterXObject *cloned = filterx_object_clone(new_value); - filterx_object_unref(new_value); - new_value = NULL; + FilterXObject *cloned = filterx_object_clone(*new_value); + filterx_object_unref(*new_value); + *new_value = NULL; if (!filterx_object_setattr(object, self->attr, &cloned)) { - filterx_eval_push_error("Attribute set failed", s, self->attr); + filterx_eval_push_error("Attribute set failed", &self->super, self->attr); filterx_object_unref(cloned); + return NULL; } - else - { - result = cloned; - } + + return cloned; +} + +static FilterXObject * +_setattr_eval(FilterXExpr *s) +{ + FilterXSetAttr *self = (FilterXSetAttr *) s; + FilterXObject *result = NULL; + + FilterXObject *new_value = filterx_expr_eval(self->new_value); + if (!new_value) + return NULL; + + FilterXObject *object = filterx_expr_eval_typed(self->object); + if (!object) + goto exit; + + result = _setattr(self, object, &new_value); exit: filterx_object_unref(new_value); @@ -127,7 +132,7 @@ filterx_setattr_new(FilterXExpr *object, FilterXString *attr_name, FilterXExpr * FilterXSetAttr *self = g_new0(FilterXSetAttr, 1); filterx_expr_init_instance(&self->super); - self->super.eval = _eval; + self->super.eval = _setattr_eval; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; From 195f667b8492aa411f147a2b18e53e346b2f00ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:44:07 +0100 Subject: [PATCH 08/10] filterx: add filterx_nullv_setattr_new() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- lib/filterx/expr-setattr.c | 61 ++++++++++++++++++++++++++++++++++++++ lib/filterx/expr-setattr.h | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/lib/filterx/expr-setattr.c b/lib/filterx/expr-setattr.c index 0fd228a39..274161941 100644 --- a/lib/filterx/expr-setattr.c +++ b/lib/filterx/expr-setattr.c @@ -25,6 +25,10 @@ #include "filterx/object-string.h" #include "filterx/filterx-eval.h" #include "filterx/filterx-ref.h" +#include "filterx/filterx-object-istype.h" +#include "filterx/filterx-eval.h" +#include "filterx/object-null.h" +#include "filterx/object-message-value.h" #include "scratch-buffers.h" typedef struct _FilterXSetAttr @@ -65,6 +69,44 @@ _setattr(FilterXSetAttr *self, FilterXObject *object, FilterXObject **new_value) return cloned; } +static inline FilterXObject * +_suppress_error(void) +{ + msg_debug("FILTERX null coalesce assignment supressing error", filterx_format_last_error()); + filterx_eval_clear_errors(); + + return filterx_null_new(); +} + +static FilterXObject * +_nullv_setattr_eval(FilterXExpr *s) +{ + FilterXSetAttr *self = (FilterXSetAttr *) s; + FilterXObject *result = NULL; + + FilterXObject *new_value = filterx_expr_eval(self->new_value); + if (!new_value || filterx_object_is_type(new_value, &FILTERX_TYPE_NAME(null)) + || (filterx_object_is_type(new_value, &FILTERX_TYPE_NAME(message_value)) + && filterx_message_value_get_type(new_value) == LM_VT_NULL)) + { + if (!new_value) + return _suppress_error(); + + return new_value; + } + + FilterXObject *object = filterx_expr_eval_typed(self->object); + if (!object) + goto exit; + + result = _setattr(self, object, &new_value); + +exit: + filterx_object_unref(new_value); + filterx_object_unref(object); + return result; +} + static FilterXObject * _setattr_eval(FilterXExpr *s) { @@ -125,6 +167,25 @@ _free(FilterXExpr *s) filterx_expr_free_method(s); } +FilterXExpr * +filterx_nullv_setattr_new(FilterXExpr *object, FilterXString *attr_name, FilterXExpr *new_value) +{ + FilterXSetAttr *self = g_new0(FilterXSetAttr, 1); + + filterx_expr_init_instance(&self->super); + self->super.eval = _nullv_setattr_eval; + self->super.init = _init; + self->super.deinit = _deinit; + self->super.free_fn = _free; + self->object = object; + + self->attr = (FilterXObject *) attr_name; + + self->new_value = new_value; + self->super.ignore_falsy_result = TRUE; + return &self->super; +} + /* Takes reference of object and new_value */ FilterXExpr * filterx_setattr_new(FilterXExpr *object, FilterXString *attr_name, FilterXExpr *new_value) diff --git a/lib/filterx/expr-setattr.h b/lib/filterx/expr-setattr.h index fac30396a..157fe479c 100644 --- a/lib/filterx/expr-setattr.h +++ b/lib/filterx/expr-setattr.h @@ -27,6 +27,6 @@ #include "filterx/object-string.h" FilterXExpr *filterx_setattr_new(FilterXExpr *object, FilterXString *attr_name, FilterXExpr *new_value); - +FilterXExpr *filterx_nullv_setattr_new(FilterXExpr *object, FilterXString *attr_name, FilterXExpr *new_value); #endif From 17a8a756e602e8716f30ad3226e23c6a8ffa1ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 27 Nov 2024 18:47:35 +0100 Subject: [PATCH 09/10] =?UTF-8?q?filterx:=20implement=20=3D=3F=3F=20assign?= =?UTF-8?q?ment=20operator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- lib/cfg-grammar.y | 2 +- lib/cfg-lex.l | 1 + lib/filterx/filterx-grammar.ym | 9 +++++++- .../functional_tests/filterx/test_filterx.py | 23 +++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/lib/cfg-grammar.y b/lib/cfg-grammar.y index 361aaf8d1..59decde07 100644 --- a/lib/cfg-grammar.y +++ b/lib/cfg-grammar.y @@ -206,7 +206,7 @@ main_location_print (FILE *yyo, YYLTYPE const * const yylocp) %left ';' /* operators in the filter language, the order of this determines precedence */ -%right KW_ASSIGN 9000, KW_PLUS_ASSIGN 9001 +%right KW_ASSIGN 9000, KW_PLUS_ASSIGN 9001, KW_NULLV_ASSIGN 9002 %right '?' ':' %right KW_NULL_COALESCING %left KW_OR 9010 diff --git a/lib/cfg-lex.l b/lib/cfg-lex.l index 14de8e338..e3d476f7a 100644 --- a/lib/cfg-lex.l +++ b/lib/cfg-lex.l @@ -321,6 +321,7 @@ filterx_word [^ \#'"/\(\)\{\}\[\]\\;\r\n\t,|\.@:] =~ { return KW_REGEXP_MATCH; } !~ { return KW_REGEXP_NOMATCH; } \?\? { return KW_NULL_COALESCING; } +=\?\? { return KW_NULLV_ASSIGN; } (-|\+)?{digit}+\.{digit}+ { yylval->fnum = strtod(yytext, NULL); return LL_FLOAT; } 0x{xdigit}+ { diff --git a/lib/filterx/filterx-grammar.ym b/lib/filterx/filterx-grammar.ym index ff581f50e..b39b5f9b8 100644 --- a/lib/filterx/filterx-grammar.ym +++ b/lib/filterx/filterx-grammar.ym @@ -116,6 +116,7 @@ construct_template_expr(LogTemplate *template) %type stmt_expr %type assignment %type plus_assignment +%type nullv_assignment %type generator_plus_assignment %type generator_assignment %type generator_casted_assignment @@ -216,9 +217,15 @@ assignment | expr '[' ']' KW_ASSIGN expr { $$ = filterx_set_subscript_new($1, NULL, $5); } | generator_assignment | plus_assignment + | nullv_assignment ; - +nullv_assignment + : variable KW_NULLV_ASSIGN expr { $$ = filterx_nullv_assign_new($1, $3); } + | expr '.' identifier KW_NULLV_ASSIGN expr { $$ = filterx_nullv_setattr_new($1, filterx_config_frozen_string(configuration, $3), $5); free($3); } + | expr '[' expr ']' KW_NULLV_ASSIGN expr { $$ = filterx_nullv_set_subscript_new($1, $3, $6); } + | expr '[' ']' KW_NULLV_ASSIGN expr { $$ = filterx_nullv_set_subscript_new($1, NULL, $5); } + ; generator_assignment /* TODO extract lvalues */ diff --git a/tests/light/functional_tests/filterx/test_filterx.py b/tests/light/functional_tests/filterx/test_filterx.py index 9908cd9fb..ddeface37 100644 --- a/tests/light/functional_tests/filterx/test_filterx.py +++ b/tests/light/functional_tests/filterx/test_filterx.py @@ -1709,6 +1709,29 @@ def test_null_coalesce_use_default_on_null(config, syslog_ng): assert file_true.read_log() == "bar\n" +def test_nullv_coalesce_assignment(config, syslog_ng): + (file_true, file_false) = create_config( + config, r""" + x = null; + y = "bar"; + obj = json(); + obj.a =?? x; + obj.b =?? y; + obj.b =?? nonexistent; + + $MSG =?? y; + $MSG =?? x; + $MSG =?? nonexistent; + $MSG += string(obj); + """, + ) + syslog_ng.start(config) + + assert file_true.get_stats()["processed"] == 1 + assert "processed" not in file_false.get_stats() + assert file_true.read_log() == 'bar{"b":"bar"}\n' + + def test_null_coalesce_use_default_on_error_and_supress_error(config, syslog_ng): (file_true, file_false) = create_config( config, r""" From 38477266da103f019b5dcdac9a4d54f9a9d6d482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Thu, 28 Nov 2024 15:19:05 +0100 Subject: [PATCH 10/10] news: add entry for #395 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- news/fx-feature-395.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 news/fx-feature-395.md diff --git a/news/fx-feature-395.md b/news/fx-feature-395.md new file mode 100644 index 000000000..b8f385fe8 --- /dev/null +++ b/news/fx-feature-395.md @@ -0,0 +1,16 @@ +`=??` assignment operator + +Syntactic sugar operator, which could slightly improve performance as well. + +It can be used to assign a non-null value to the left-hand side. +Evaluation errors from the right-hand side will be suppressed. + +For example, + +`resource.attributes['service.name'] =?? $PROGRAM;` can be used instead of: + +``` +if (isset($PROGRAM)) { + resource.attributes['service.name'] = $PROGRAM; +}; +```