diff --git a/lib/filterx/CMakeLists.txt b/lib/filterx/CMakeLists.txt index 60314764d97..a0c8fc42c52 100644 --- a/lib/filterx/CMakeLists.txt +++ b/lib/filterx/CMakeLists.txt @@ -5,8 +5,6 @@ set(FILTERX_HEADERS filterx/expr-function.h filterx/expr-getattr.h filterx/expr-get-subscript.h - filterx/expr-dict.h - filterx/expr-list.h filterx/expr-literal.h filterx/expr-message-ref.h filterx/expr-setattr.h @@ -33,6 +31,9 @@ set(FILTERX_HEADERS filterx/expr-condition.h filterx/expr-isset.h filterx/expr-unset.h + filterx/expr-shorthand.h + filterx/expr-generator.h + filterx/expr-literal-generator.h filterx/filterx-private.h PARENT_SCOPE ) @@ -44,8 +45,6 @@ set(FILTERX_SOURCES filterx/expr-function.c filterx/expr-getattr.c filterx/expr-get-subscript.c - filterx/expr-dict.c - filterx/expr-list.c filterx/expr-literal.c filterx/expr-message-ref.c filterx/expr-setattr.c @@ -73,6 +72,9 @@ set(FILTERX_SOURCES filterx/expr-condition.c filterx/expr-isset.c filterx/expr-unset.c + filterx/expr-shorthand.c + filterx/expr-generator.c + filterx/expr-literal-generator.c filterx/filterx-private.c PARENT_SCOPE ) diff --git a/lib/filterx/Makefile.am b/lib/filterx/Makefile.am index 41c65a725c3..e66cfa0cfcd 100644 --- a/lib/filterx/Makefile.am +++ b/lib/filterx/Makefile.am @@ -12,8 +12,6 @@ filterxinclude_HEADERS = \ lib/filterx/expr-setattr.h \ lib/filterx/expr-get-subscript.h \ lib/filterx/expr-set-subscript.h \ - lib/filterx/expr-dict.h \ - lib/filterx/expr-list.h \ lib/filterx/expr-message-ref.h \ lib/filterx/expr-comparison.h \ lib/filterx/filterx-object.h \ @@ -35,6 +33,9 @@ filterxinclude_HEADERS = \ lib/filterx/expr-condition.h \ lib/filterx/expr-isset.h \ lib/filterx/expr-unset.h \ + lib/filterx/expr-shorthand.h \ + lib/filterx/expr-generator.h \ + lib/filterx/expr-literal-generator.h \ lib/filterx/filterx-private.h @@ -50,8 +51,6 @@ filterx_sources = \ lib/filterx/expr-setattr.c \ lib/filterx/expr-get-subscript.c \ lib/filterx/expr-set-subscript.c \ - lib/filterx/expr-dict.c \ - lib/filterx/expr-list.c \ lib/filterx/expr-message-ref.c \ lib/filterx/expr-comparison.c \ lib/filterx/filterx-object.c \ @@ -74,6 +73,9 @@ filterx_sources = \ lib/filterx/expr-condition.c \ lib/filterx/expr-isset.c \ lib/filterx/expr-unset.c \ + lib/filterx/expr-shorthand.c \ + lib/filterx/expr-generator.c \ + lib/filterx/expr-literal-generator.c \ lib/filterx/filterx-private.c \ lib/filterx/filterx-grammar.y diff --git a/lib/filterx/expr-dict.c b/lib/filterx/expr-dict.c deleted file mode 100644 index 07957b35d77..00000000000 --- a/lib/filterx/expr-dict.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2023 Balazs Scheidler - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * As an additional exemption you are allowed to compile & link against the - * OpenSSL libraries as published by the OpenSSL project. See the file - * COPYING for details. - * - */ -#include "expr-dict.h" -#include "object-dict-interface.h" -#include "scratch-buffers.h" -#include "compat/json.h" - -struct _FilterXKeyValue -{ - gchar *key; - FilterXExpr *value_expr; -}; - -FilterXKeyValue * -filterx_kv_new(const gchar *key, FilterXExpr *value_expr) -{ - FilterXKeyValue *self = g_new0(FilterXKeyValue, 1); - self->key = g_strdup(key); - self->value_expr = value_expr; - return self; -} - -void -filterx_kv_free(FilterXKeyValue *self) -{ - g_free(self->key); - filterx_expr_unref(self->value_expr); - g_free(self); -} - -typedef struct _FilterXDictExpr -{ - FilterXExpr super; - FilterXExpr *fillable; - GList *key_values; -} FilterXDictExpr; - -static gboolean -_eval_key_value(FilterXDictExpr *self, FilterXObject *fillable, FilterXKeyValue *kv) -{ - FilterXObject *value = filterx_expr_eval_typed(kv->value_expr); - if (!value) - return FALSE; - - FilterXObject *cloned_value = filterx_object_clone(value); - filterx_object_unref(value); - - gboolean result = filterx_object_setattr(fillable, kv->key, cloned_value); - filterx_object_unref(cloned_value); - return result; -} - -static FilterXObject * -_eval(FilterXExpr *s) -{ - FilterXDictExpr *self = (FilterXDictExpr *) s; - - FilterXObject *fillable = filterx_expr_eval_typed(self->fillable); - if (!fillable) - return NULL; - - if (!filterx_object_is_type(fillable, &FILTERX_TYPE_NAME(dict))) - goto fail; - - for (GList *l = self->key_values; l; l = l->next) - { - if (!_eval_key_value(self, fillable, l->data)) - goto fail; - } - return fillable; - -fail: - filterx_object_unref(fillable); - return NULL; -} - -static void -_free(FilterXExpr *s) -{ - FilterXDictExpr *self = (FilterXDictExpr *) s; - - g_list_free_full(self->key_values, (GDestroyNotify) filterx_kv_free); - filterx_expr_unref(self->fillable); - filterx_expr_free_method(s); -} - -FilterXExpr * -filterx_dict_expr_new(FilterXExpr *fillable, GList *key_values) -{ - FilterXDictExpr *self = g_new0(FilterXDictExpr, 1); - - filterx_expr_init_instance(&self->super); - self->super.eval = _eval; - self->super.free_fn = _free; - self->key_values = key_values; - self->fillable = filterx_expr_ref(fillable); - return &self->super; -} - -static FilterXObject * -_inner_eval(FilterXExpr *s) -{ - FilterXDictExpr *self = (FilterXDictExpr *) s; - - FilterXObject *root_fillable = filterx_expr_eval_typed(self->fillable); - if (!root_fillable) - return NULL; - - FilterXObject *fillable = filterx_object_create_dict(root_fillable); - filterx_object_unref(root_fillable); - if (!fillable) - return NULL; - - if (!filterx_object_is_type(fillable, &FILTERX_TYPE_NAME(dict))) - goto fail; - - for (GList *l = self->key_values; l; l = l->next) - { - if (!_eval_key_value(self, fillable, l->data)) - goto fail; - } - return fillable; - -fail: - filterx_object_unref(fillable); - return NULL; -} - -FilterXExpr * -filterx_dict_expr_inner_new(FilterXExpr *fillable, GList *key_values) -{ - FilterXDictExpr *self = g_new0(FilterXDictExpr, 1); - - filterx_expr_init_instance(&self->super); - self->super.eval = _inner_eval; - self->super.free_fn = _free; - self->key_values = key_values; - self->fillable = filterx_expr_ref(fillable); - return &self->super; -} diff --git a/lib/filterx/expr-generator.c b/lib/filterx/expr-generator.c new file mode 100644 index 00000000000..827705397d4 --- /dev/null +++ b/lib/filterx/expr-generator.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 Attila Szakacs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "filterx/expr-generator.h" + +/* Takes reference of fillable */ +void +filterx_generator_set_fillable(FilterXExpr *s, FilterXExpr *fillable) +{ + FilterXExprGenerator *self = (FilterXExprGenerator *) s; + + self->fillable = fillable; +} + +void +filterx_generator_init_instance(FilterXExpr *s) +{ + filterx_expr_init_instance(s); +} + +void +filterx_generator_free_method(FilterXExpr *s) +{ + FilterXExprGenerator *self = (FilterXExprGenerator *) s; + + filterx_expr_unref(self->fillable); + filterx_expr_free_method(s); +} + +typedef struct FilterXExprGeneratorCreateContainer_ +{ + FilterXExpr super; + FilterXExprGenerator *generator; + FilterXExpr *fillable_parent; +} FilterXExprGeneratorCreateContainer; + +static FilterXObject * +_create_container_eval(FilterXExpr *s) +{ + FilterXExprGeneratorCreateContainer *self = (FilterXExprGeneratorCreateContainer *) s; + + return self->generator->create_container(self->generator, self->fillable_parent); +} + +static void +_create_container_free(FilterXExpr *s) +{ + FilterXExprGeneratorCreateContainer *self = (FilterXExprGeneratorCreateContainer *) s; + + filterx_expr_unref(&self->generator->super); + filterx_expr_unref(self->fillable_parent); + filterx_expr_free_method(s); +} + +FilterXExpr * +filterx_generator_create_container_new(FilterXExpr *g, FilterXExpr *fillable_parent) +{ + FilterXExprGeneratorCreateContainer *self = g_new0(FilterXExprGeneratorCreateContainer, 1); + + filterx_expr_init_instance(&self->super); + self->generator = (FilterXExprGenerator *) filterx_expr_ref(g); + self->fillable_parent = filterx_expr_ref(fillable_parent); + self->super.eval = _create_container_eval; + self->super.free_fn = _create_container_free; + + return &self->super; +} diff --git a/lib/filterx/expr-dict.h b/lib/filterx/expr-generator.h similarity index 60% rename from lib/filterx/expr-dict.h rename to lib/filterx/expr-generator.h index 3fb5639c995..0630afeb595 100644 --- a/lib/filterx/expr-dict.h +++ b/lib/filterx/expr-generator.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Balazs Scheidler + * Copyright (c) 2024 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,18 +20,24 @@ * COPYING for details. * */ -#ifndef FILTERX_EXPR_JSON_H_INCLUDED -#define FILTERX_EXPR_JSON_H_INCLUDED -#include "filterx/filterx-expr.h" +#ifndef FILTERX_EXPR_GENERATOR_H_INCLUDED +#define FILTERX_EXPR_GENERATOR_H_INCLUDED -typedef struct _FilterXKeyValue FilterXKeyValue; +#include "filterx/filterx-expr.h" -FilterXKeyValue *filterx_kv_new(const gchar *key, FilterXExpr *value_expr); -void filterx_kv_free(FilterXKeyValue *self); +typedef struct FilterXExprGenerator_ FilterXExprGenerator; +struct FilterXExprGenerator_ +{ + FilterXExpr super; + FilterXExpr *fillable; + FilterXObject *(*create_container)(FilterXExprGenerator *self, FilterXExpr *fillable_parent); +}; -FilterXExpr *filterx_dict_expr_new(FilterXExpr *fillable, GList *key_values); -FilterXExpr *filterx_dict_expr_inner_new(FilterXExpr *fillable, GList *key_values); +void filterx_generator_set_fillable(FilterXExpr *s, FilterXExpr *fillable); +void filterx_generator_init_instance(FilterXExpr *s); +void filterx_generator_free_method(FilterXExpr *s); +FilterXExpr *filterx_generator_create_container_new(FilterXExpr *g, FilterXExpr *fillable_parent); #endif diff --git a/lib/filterx/expr-list.c b/lib/filterx/expr-list.c deleted file mode 100644 index df217c2bccf..00000000000 --- a/lib/filterx/expr-list.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2023 Balazs Scheidler - * Copyright (c) 2024 Attila Szakacs - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * As an additional exemption you are allowed to compile & link against the - * OpenSSL libraries as published by the OpenSSL project. See the file - * COPYING for details. - * - */ -#include "expr-list.h" -#include "object-list-interface.h" -#include "object-primitive.h" -#include "scratch-buffers.h" - -typedef struct _FilterXListExpr -{ - FilterXExpr super; - FilterXExpr *fillable; - GList *values; -} FilterXListExpr; - -static gboolean -_eval_value(FilterXListExpr *self, FilterXObject *fillable, FilterXExpr *expr) -{ - FilterXObject *value = filterx_expr_eval_typed(expr); - if (!value) - return FALSE; - - FilterXObject *cloned_value = filterx_object_clone(value); - filterx_object_unref(value); - - gboolean success = filterx_list_append(fillable, cloned_value); - filterx_object_unref(cloned_value); - return success; -} - -static FilterXObject * -_eval(FilterXExpr *s) -{ - FilterXListExpr *self = (FilterXListExpr *) s; - - FilterXObject *fillable = filterx_expr_eval_typed(self->fillable); - if (!fillable) - return NULL; - - if (!filterx_object_is_type(fillable, &FILTERX_TYPE_NAME(list))) - goto fail; - - for (GList *l = self->values; l; l = l->next) - { - if (!_eval_value(self, fillable, l->data)) - goto fail; - } - - return fillable; - -fail: - filterx_object_unref(fillable); - return NULL; -} - -static void -_free(FilterXExpr *s) -{ - FilterXListExpr *self = (FilterXListExpr *) s; - - g_list_free_full(self->values, (GDestroyNotify) filterx_expr_unref); - filterx_expr_unref(self->fillable); - filterx_expr_free_method(s); -} - -FilterXExpr * -filterx_list_expr_new(FilterXExpr *fillable, GList *values) -{ - FilterXListExpr *self = g_new0(FilterXListExpr, 1); - - filterx_expr_init_instance(&self->super); - self->super.eval = _eval; - self->super.free_fn = _free; - self->fillable = filterx_expr_ref(fillable); - self->values = values; - return &self->super; -} - -static FilterXObject * -_inner_eval(FilterXExpr *s) -{ - FilterXListExpr *self = (FilterXListExpr *) s; - - FilterXObject *root_fillable = filterx_expr_eval_typed(self->fillable); - if (!root_fillable) - return NULL; - - FilterXObject *fillable = filterx_object_create_list(root_fillable); - filterx_object_unref(root_fillable); - if (!fillable) - return NULL; - - if (!filterx_object_is_type(fillable, &FILTERX_TYPE_NAME(list))) - goto fail; - - for (GList *l = self->values; l; l = l->next) - { - if (!_eval_value(self, fillable, l->data)) - goto fail; - } - - return fillable; - -fail: - filterx_object_unref(fillable); - return NULL; -} - -FilterXExpr * -filterx_list_expr_inner_new(FilterXExpr *fillable, GList *values) -{ - FilterXListExpr *self = g_new0(FilterXListExpr, 1); - - filterx_expr_init_instance(&self->super); - self->super.eval = _inner_eval; - self->super.free_fn = _free; - self->fillable = filterx_expr_ref(fillable); - self->values = values; - return &self->super; -} diff --git a/lib/filterx/expr-literal-generator.c b/lib/filterx/expr-literal-generator.c new file mode 100644 index 00000000000..5384040649d --- /dev/null +++ b/lib/filterx/expr-literal-generator.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2024 Attila Szakacs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "filterx/expr-literal-generator.h" +#include "filterx/object-primitive.h" + +struct FilterXLiteralGeneratorElem_ +{ + FilterXExpr *key; + FilterXExpr *value; + gboolean cloneable; +}; + +FilterXLiteralGeneratorElem * +filterx_literal_generator_elem_new(FilterXExpr *key, FilterXExpr *value, gboolean cloneable) +{ + FilterXLiteralGeneratorElem *self = g_new0(FilterXLiteralGeneratorElem, 1); + + self->key = key; + self->value = value; + self->cloneable = cloneable; + + return self; +} + +static void +_literal_generator_elem_free(FilterXLiteralGeneratorElem *self) +{ + filterx_expr_unref(self->key); + filterx_expr_unref(self->value); + g_free(self); +} + + +struct FilterXExprLiteralGenerator_ +{ + FilterXExprGenerator super; + GList *elements; +}; + +/* Takes reference of elements */ +void +filterx_literal_generator_set_elements(FilterXExpr *s, GList *elements) +{ + FilterXExprLiteralGenerator *self = (FilterXExprLiteralGenerator *) s; + + g_assert(!self->elements); + self->elements = elements; +} + +static gboolean +_eval_elements(FilterXObject *fillable, GList *elements) +{ + for (GList *link = elements; link; link = link->next) + { + FilterXLiteralGeneratorElem *elem = (FilterXLiteralGeneratorElem *) link->data; + + FilterXObject *key = NULL; + if (elem->key) + { + key = filterx_expr_eval_typed(elem->key); + if (!key) + return FALSE; + } + + FilterXObject *value = filterx_expr_eval_typed(elem->value); + if (!value) + { + filterx_object_unref(key); + return FALSE; + } + + if (elem->cloneable) + { + FilterXObject *cloned_value = filterx_object_clone(value); + filterx_object_unref(value); + value = cloned_value; + } + + gboolean success = filterx_object_set_subscript(fillable, key, value); + + filterx_object_unref(key); + filterx_object_unref(value); + + if (!success) + return FALSE; + } + + return TRUE; +} + +static FilterXObject * +_dict_generator_create_container(FilterXExprGenerator *s, FilterXExpr *fillable_parent) +{ + FilterXObject *fillable_parent_obj = filterx_expr_eval_typed(fillable_parent); + if (!fillable_parent_obj) + return NULL; + + FilterXObject *result = filterx_object_create_dict(fillable_parent_obj); + filterx_object_unref(fillable_parent_obj); + return result; +} + +static FilterXObject * +_list_generator_create_container(FilterXExprGenerator *s, FilterXExpr *fillable_parent) +{ + FilterXObject *fillable_parent_obj = filterx_expr_eval_typed(fillable_parent); + if (!fillable_parent_obj) + return NULL; + + FilterXObject *result = filterx_object_create_list(fillable_parent_obj); + filterx_object_unref(fillable_parent_obj); + return result; +} + +static FilterXObject * +_literal_generator_eval(FilterXExpr *s) +{ + FilterXExprLiteralGenerator *self = (FilterXExprLiteralGenerator *) s; + + FilterXObject *fillable = filterx_expr_eval_typed(self->super.fillable); + if (!fillable) + return NULL; + + FilterXObject *result = _eval_elements(fillable, self->elements) ? filterx_boolean_new(TRUE) : NULL; + filterx_object_unref(fillable); + return result; +} + +void +_literal_generator_free(FilterXExpr *s) +{ + FilterXExprLiteralGenerator *self = (FilterXExprLiteralGenerator *) s; + + g_list_free_full(self->elements, (GDestroyNotify) _literal_generator_elem_free); + filterx_generator_free_method(s); +} + +static void +_literal_generator_init_instance(FilterXExprLiteralGenerator *self) +{ + filterx_generator_init_instance(&self->super.super); + self->super.super.eval = _literal_generator_eval; + self->super.super.free_fn = _literal_generator_free; +} + +FilterXExpr * +filterx_literal_dict_generator_new(void) +{ + FilterXExprLiteralGenerator *self = g_new0(FilterXExprLiteralGenerator, 1); + + _literal_generator_init_instance(self); + self->super.create_container = _dict_generator_create_container; + + return &self->super.super; +} + +FilterXExpr * +filterx_literal_list_generator_new(void) +{ + FilterXExprLiteralGenerator *self = g_new0(FilterXExprLiteralGenerator, 1); + + _literal_generator_init_instance(self); + self->super.create_container = _list_generator_create_container; + + return &self->super.super; +} + + +typedef struct FilterXLiteralInnerGenerator_ +{ + FilterXExpr super; + FilterXExprLiteralGenerator *root_literal_generator; + GList *elements; +} FilterXLiteralInnerGenerator; + +void +_literal_inner_generator_free(FilterXExpr *s) +{ + FilterXLiteralInnerGenerator *self = (FilterXLiteralInnerGenerator *) s; + + g_list_free_full(self->elements, (GDestroyNotify) _literal_generator_elem_free); + filterx_expr_free_method(s); +} + +static void +_literal_inner_generator_init_instance(FilterXLiteralInnerGenerator *self, FilterXExpr *root_literal_generator, + GList *elements) +{ + filterx_expr_init_instance(&self->super); + self->super.free_fn = _literal_inner_generator_free; + + /* + * We do not ref or unref the root_literal_generator, as we are always accessed through that, so it is expected + * to be alive while we are alive. + */ + self->root_literal_generator = (FilterXExprLiteralGenerator *) root_literal_generator; + self->elements = elements; +} + +static FilterXObject * +_inner_dict_generator_eval(FilterXExpr *s) +{ + FilterXLiteralInnerGenerator *self = (FilterXLiteralInnerGenerator *) s; + + FilterXObject *root_fillable = filterx_expr_eval_typed(self->root_literal_generator->super.fillable); + if (!root_fillable) + return NULL; + + FilterXObject *fillable = filterx_object_create_dict(root_fillable); + filterx_object_unref(root_fillable); + if (!fillable) + return NULL; + + if (_eval_elements(fillable, self->elements)) + return fillable; + + filterx_object_unref(fillable); + return NULL; +} + +static FilterXObject * +_inner_list_generator_eval(FilterXExpr *s) +{ + FilterXLiteralInnerGenerator *self = (FilterXLiteralInnerGenerator *) s; + + FilterXObject *root_fillable = filterx_expr_eval_typed(self->root_literal_generator->super.fillable); + if (!root_fillable) + return NULL; + + FilterXObject *fillable = filterx_object_create_list(root_fillable); + filterx_object_unref(root_fillable); + if (!fillable) + return NULL; + + if (_eval_elements(fillable, self->elements)) + return fillable; + + filterx_object_unref(fillable); + return NULL; +} + +/* Takes reference of elements */ +FilterXExpr * +filterx_literal_inner_dict_generator_new(FilterXExpr *root_literal_generator, GList *elements) +{ + FilterXLiteralInnerGenerator *self = g_new0(FilterXLiteralInnerGenerator, 1); + + _literal_inner_generator_init_instance(self, root_literal_generator, elements); + self->super.eval = _inner_dict_generator_eval; + + return &self->super; +} + +/* Takes reference of elements */ +FilterXExpr * +filterx_literal_inner_list_generator_new(FilterXExpr *root_literal_generator, GList *elements) +{ + FilterXLiteralInnerGenerator *self = g_new0(FilterXLiteralInnerGenerator, 1); + + _literal_inner_generator_init_instance(self, root_literal_generator, elements); + self->super.eval = _inner_list_generator_eval; + + return &self->super; +} diff --git a/lib/filterx/expr-literal-generator.h b/lib/filterx/expr-literal-generator.h new file mode 100644 index 00000000000..c14eaf1d5bd --- /dev/null +++ b/lib/filterx/expr-literal-generator.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 Attila Szakacs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef FILTERX_EXPR_LITERAL_GENERATOR_H_INCLUDED +#define FILTERX_EXPR_LITERAL_GENERATOR_H_INCLUDED + +#include "filterx/expr-generator.h" + +typedef struct FilterXLiteralGeneratorElem_ FilterXLiteralGeneratorElem; +typedef struct FilterXExprLiteralGenerator_ FilterXExprLiteralGenerator; + +FilterXLiteralGeneratorElem *filterx_literal_generator_elem_new(FilterXExpr *key, FilterXExpr *value, + gboolean cloneable); + +FilterXExpr *filterx_literal_dict_generator_new(void); +FilterXExpr *filterx_literal_list_generator_new(void); +void filterx_literal_generator_set_elements(FilterXExpr *s, GList *elements); + +FilterXExpr *filterx_literal_inner_dict_generator_new(FilterXExpr *root_literal_generator, GList *elements); +FilterXExpr *filterx_literal_inner_list_generator_new(FilterXExpr *root_literal_generator, GList *elements); + +#endif diff --git a/lib/filterx/expr-shorthand.c b/lib/filterx/expr-shorthand.c new file mode 100644 index 00000000000..23259a9f360 --- /dev/null +++ b/lib/filterx/expr-shorthand.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 Attila Szakacs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "filterx/expr-shorthand.h" + +typedef struct _FilterXShorthand +{ + FilterXExpr super; + GList *exprs; +} FilterXShorthand; + +static FilterXObject * +_eval(FilterXExpr *s) +{ + FilterXShorthand *self = (FilterXShorthand *) s; + + FilterXObject *result = NULL; + for (GList *elem = self->exprs; elem; elem = elem->next) + { + filterx_object_unref(result); + + FilterXExpr *expr = elem->data; + result = filterx_expr_eval(expr); + + if (!result || filterx_object_falsy(result)) + break; + } + + return result; +} + +static void +_free(FilterXExpr *s) +{ + FilterXShorthand *self = (FilterXShorthand *) s; + + g_list_free_full(self->exprs, (GDestroyNotify) filterx_expr_unref); + filterx_expr_free_method(s); +} + +/* Takes reference of expr */ +void +filterx_shorthand_add(FilterXExpr *s, FilterXExpr *expr) +{ + FilterXShorthand *self = (FilterXShorthand *) s; + + self->exprs = g_list_append(self->exprs, expr); +} + +FilterXExpr * +filterx_shorthand_new(void) +{ + FilterXShorthand *self = g_new0(FilterXShorthand, 1); + + filterx_expr_init_instance(&self->super); + self->super.eval = _eval; + self->super.free_fn = _free; + + return &self->super; +} + diff --git a/lib/filterx/expr-list.h b/lib/filterx/expr-shorthand.h similarity index 76% rename from lib/filterx/expr-list.h rename to lib/filterx/expr-shorthand.h index 7a360bcda0d..8c146fa7486 100644 --- a/lib/filterx/expr-list.h +++ b/lib/filterx/expr-shorthand.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Balazs Scheidler + * Copyright (c) 2024 Attila Szakacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,13 +20,12 @@ * COPYING for details. * */ -#ifndef FILTERX_EXPR_LIST_H_INCLUDED -#define FILTERX_EXPR_LIST_H_INCLUDED +#ifndef FILTERX_SHORTHAND_H_INCLUDED +#define FILTERX_SHORTHAND_H_INCLUDED #include "filterx/filterx-expr.h" - -FilterXExpr *filterx_list_expr_new(FilterXExpr *fillable, GList *values); -FilterXExpr *filterx_list_expr_inner_new(FilterXExpr *fillable, GList *values); +FilterXExpr *filterx_shorthand_new(void); +void filterx_shorthand_add(FilterXExpr *s, FilterXExpr *expr); #endif diff --git a/lib/filterx/filterx-grammar.ym b/lib/filterx/filterx-grammar.ym index 06c07e62c88..1438840d4ba 100644 --- a/lib/filterx/filterx-grammar.ym +++ b/lib/filterx/filterx-grammar.ym @@ -39,8 +39,6 @@ #include "filterx/expr-setattr.h" #include "filterx/expr-get-subscript.h" #include "filterx/expr-set-subscript.h" -#include "filterx/expr-dict.h" -#include "filterx/expr-list.h" #include "filterx/expr-comparison.h" #include "filterx/object-primitive.h" #include "filterx/object-json.h" @@ -51,10 +49,12 @@ #include "filterx/expr-condition.h" #include "filterx/expr-isset.h" #include "filterx/expr-unset.h" +#include "filterx/expr-literal-generator.h" +#include "filterx/expr-shorthand.h" #include "template/templates.h" -FilterXExpr *last_fillable; +FilterXExpr *last_literal_generator; FilterXExpr * construct_template_expr(LogTemplate *template) @@ -92,6 +92,7 @@ construct_template_expr(LogTemplate *template) %type stmts %type stmt %type assignment +%type generator_assignment %type expr %type expr_value %type expr_generator @@ -102,14 +103,14 @@ construct_template_expr(LogTemplate *template) %type literal_object %type lvalue %type template -%type dict_expr -%type dict_expr_inner -%type dict_key_values -%type dict_key_value -%type list_expr -%type list_expr_inner -%type list_values -%type list_value +%type dict_generator +%type inner_dict_generator +%type dict_element +%type dict_elements +%type list_generator +%type inner_list_generator +%type list_element +%type list_elements %type boolean %type conditional %type if @@ -138,6 +139,45 @@ assignment | expr '.' LL_IDENTIFIER KW_ASSIGN expr { $$ = filterx_setattr_new($1, $3, $5); free($3); } | expr '[' expr ']' KW_ASSIGN expr { $$ = filterx_set_subscript_new($1, $3, $6); } | expr '[' ']' KW_ASSIGN expr { $$ = filterx_set_subscript_new($1, NULL, $5); } + | generator_assignment + ; + +generator_assignment + : expr '.' LL_IDENTIFIER KW_ASSIGN expr_generator + { + FilterXExpr *setattr = filterx_setattr_new($1, $3, filterx_generator_create_container_new($5, $1)); + filterx_generator_set_fillable($5, filterx_getattr_new(filterx_expr_ref($1), $3)); + + FilterXExpr *shorthand = filterx_shorthand_new(); + filterx_shorthand_add(shorthand, setattr); + filterx_shorthand_add(shorthand, $5); + + $$ = shorthand; + } + | expr '[' expr ']' KW_ASSIGN expr_generator + { + FilterXExpr *set_subscript = filterx_set_subscript_new($1, $3, filterx_generator_create_container_new($6, $1)); + filterx_generator_set_fillable($6, filterx_get_subscript_new(filterx_expr_ref($1), filterx_expr_ref($3))); + + FilterXExpr *shorthand = filterx_shorthand_new(); + filterx_shorthand_add(shorthand, set_subscript); + filterx_shorthand_add(shorthand, $6); + + $$ = shorthand; + } + | expr '[' ']' KW_ASSIGN expr_generator + { + FilterXExpr *minus_one = filterx_literal_new(filterx_config_freeze_object(configuration, filterx_integer_new(-1))); + FilterXExpr *set_subscript = filterx_set_subscript_new($1, NULL, filterx_generator_create_container_new($5, $1)); + filterx_generator_set_fillable($5, filterx_get_subscript_new(filterx_expr_ref($1), minus_one)); + + FilterXExpr *shorthand = filterx_shorthand_new(); + filterx_shorthand_add(shorthand, set_subscript); + filterx_shorthand_add(shorthand, $5); + + $$ = shorthand; + } + | expr KW_PLUS_ASSIGN expr_generator { $$ = $3; filterx_generator_set_fillable($3, $1); } ; expr @@ -148,7 +188,6 @@ expr | expr KW_AND expr { $$ = filterx_binary_and_new($1, $3); } | expr '.' LL_IDENTIFIER { $$ = filterx_getattr_new($1, $3); free($3); } | expr '[' expr ']' { $$ = filterx_get_subscript_new($1, $3); } - | expr KW_PLUS_ASSIGN { last_fillable = $1; } expr_generator { $$ = $4; } | expr KW_TA_LT expr { $$ = filterx_comparison_new($1, $3, FCMPX_TYPE_AWARE | FCMPX_LT); } | expr KW_TA_LE expr { $$ = filterx_comparison_new($1, $3, FCMPX_TYPE_AWARE | FCMPX_LT | FCMPX_EQ); } | expr KW_TA_EQ expr { $$ = filterx_comparison_new($1, $3, FCMPX_TYPE_AWARE | FCMPX_EQ); } @@ -176,8 +215,8 @@ expr_value ; expr_generator - : dict_expr - | list_expr + : dict_generator + | list_generator ; function_call @@ -238,44 +277,46 @@ template } ; -dict_expr - : '{' dict_key_values '}' { $$ = filterx_dict_expr_new(last_fillable, $2); } +dict_generator + : '{' { last_literal_generator = filterx_literal_dict_generator_new(); } dict_elements '}' + { filterx_literal_generator_set_elements(last_literal_generator, $3); $$ = last_literal_generator; } ; -dict_expr_inner - : '{' dict_key_values '}' { $$ = filterx_dict_expr_inner_new(last_fillable, $2); } +inner_dict_generator + : '{' dict_elements '}' { $$ = filterx_literal_inner_dict_generator_new(last_literal_generator, $2); } ; -dict_key_values - : dict_key_value ',' dict_key_values { $$ = g_list_prepend($3, $1); } - | dict_key_value { $$ = g_list_append(NULL, $1); } - | { $$ = NULL; } +dict_elements + : dict_element ',' dict_elements { $$ = g_list_prepend($3, $1); } + | dict_element { $$ = g_list_append(NULL, $1); } + | { $$ = NULL; } ; -dict_key_value - : LL_STRING ':' expr { $$ = filterx_kv_new($1, $3); free($1); } - | LL_STRING ':' dict_expr_inner { $$ = filterx_kv_new($1, $3); free($1); } - | LL_STRING ':' list_expr_inner { $$ = filterx_kv_new($1, $3); free($1); } +dict_element + : expr ':' expr { $$ = filterx_literal_generator_elem_new($1, $3, TRUE); } + | expr ':' inner_dict_generator { $$ = filterx_literal_generator_elem_new($1, $3, FALSE); } + | expr ':' inner_list_generator { $$ = filterx_literal_generator_elem_new($1, $3, FALSE); } ; -list_expr - : '[' list_values ']' { $$ = filterx_list_expr_new(last_fillable, $2); } +list_generator + : '[' { last_literal_generator = filterx_literal_list_generator_new(); } list_elements ']' + { filterx_literal_generator_set_elements(last_literal_generator, $3); $$ = last_literal_generator; } ; -list_expr_inner - : '[' list_values ']' { $$ = filterx_list_expr_inner_new(last_fillable, $2); } +inner_list_generator + : '[' list_elements ']' { $$ = filterx_literal_inner_list_generator_new(last_literal_generator, $2); } ; -list_values - : list_value ',' list_values { $$ = g_list_prepend($3, $1); } - | list_value { $$ = g_list_append(NULL, $1); } - | { $$ = NULL; } +list_elements + : list_element ',' list_elements { $$ = g_list_prepend($3, $1); } + | list_element { $$ = g_list_append(NULL, $1); } + | { $$ = NULL; } ; -list_value - : expr { $$ = $1; } - | dict_expr_inner { $$ = $1; } - | list_expr_inner { $$ = $1; } +list_element + : expr { $$ = filterx_literal_generator_elem_new(NULL, $1, TRUE); } + | inner_dict_generator { $$ = filterx_literal_generator_elem_new(NULL, $1, FALSE); } + | inner_list_generator { $$ = filterx_literal_generator_elem_new(NULL, $1, FALSE); } ; conditional diff --git a/lib/filterx/tests/test_filterx_expr.c b/lib/filterx/tests/test_filterx_expr.c index abca178f79f..925adba3ec4 100644 --- a/lib/filterx/tests/test_filterx_expr.c +++ b/lib/filterx/tests/test_filterx_expr.c @@ -26,8 +26,7 @@ #include "filterx/expr-literal.h" #include "filterx/expr-template.h" -#include "filterx/expr-list.h" -#include "filterx/expr-dict.h" +#include "filterx/expr-literal-generator.h" #include "filterx/object-primitive.h" #include "filterx/object-string.h" #include "filterx/object-json.h" @@ -120,43 +119,59 @@ Test(filterx_expr, test_filterx_list_merge) FilterXExpr *fillable = filterx_literal_new(json_array); FilterXExpr *list_expr = NULL; FilterXObject *result = NULL; + gboolean success = FALSE; GList *values = NULL, *inner_values = NULL; // [42]; - values = g_list_append(NULL, filterx_literal_new(filterx_integer_new(42))); - list_expr = filterx_list_expr_new(fillable, values); - - // $fillable << [42]; + values = g_list_append(NULL, filterx_literal_generator_elem_new(NULL, + filterx_literal_new(filterx_integer_new(42)), + TRUE)); + list_expr = filterx_literal_list_generator_new(); + filterx_generator_set_fillable(list_expr, filterx_expr_ref(fillable)); + filterx_literal_generator_set_elements(list_expr, values); + + // $fillable += [42]; result = filterx_expr_eval(list_expr); - cr_assert_eq(result, json_array); - cr_assert(filterx_object_is_type(result, &FILTERX_TYPE_NAME(list))); - cr_assert_eq(filterx_list_len(result), 1); - _assert_int_value_and_unref(filterx_list_get_subscript(result, 0), 42); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_list_len(json_array), 1); + _assert_int_value_and_unref(filterx_list_get_subscript(json_array, 0), 42); filterx_object_unref(result); - // $fillable << [42]; + // $fillable += [42]; result = filterx_expr_eval(list_expr); - cr_assert_eq(result, json_array); - cr_assert_eq(filterx_list_len(result), 2); - _assert_int_value_and_unref(filterx_list_get_subscript(result, 0), 42); - _assert_int_value_and_unref(filterx_list_get_subscript(result, 1), 42); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_list_len(json_array), 2); + _assert_int_value_and_unref(filterx_list_get_subscript(json_array, 0), 42); + _assert_int_value_and_unref(filterx_list_get_subscript(json_array, 1), 42); filterx_object_unref(result); filterx_expr_unref(list_expr); // [[1337]]; - inner_values = g_list_append(NULL, filterx_literal_new(filterx_integer_new(1337))); - values = g_list_append(NULL, filterx_list_expr_inner_new(fillable, inner_values)); - list_expr = filterx_list_expr_new(fillable, values); - - // $fillable << [[1337]]; + list_expr = filterx_literal_list_generator_new(); + filterx_generator_set_fillable(list_expr, filterx_expr_ref(fillable)); + inner_values = g_list_append(NULL, filterx_literal_generator_elem_new(NULL, + filterx_literal_new(filterx_integer_new(1337)), + TRUE)); + values = g_list_append(NULL, filterx_literal_generator_elem_new(NULL, + filterx_literal_inner_list_generator_new(list_expr, inner_values), + FALSE)); + filterx_literal_generator_set_elements(list_expr, values); + + // $fillable += [[1337]]; result = filterx_expr_eval(list_expr); - cr_assert_eq(result, json_array); - cr_assert_eq(filterx_list_len(result), 3); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_list_len(json_array), 3); - FilterXObject *stored_inner_list = filterx_list_get_subscript(result, 2); + FilterXObject *stored_inner_list = filterx_list_get_subscript(json_array, 2); cr_assert(stored_inner_list); cr_assert(filterx_object_is_type(stored_inner_list, &FILTERX_TYPE_NAME(list))); cr_assert_eq(filterx_list_len(stored_inner_list), 1); @@ -192,6 +207,7 @@ Test(filterx_expr, test_filterx_dict_merge) FilterXExpr *fillable = filterx_literal_new(json); FilterXExpr *dict_expr = NULL; FilterXObject *result = NULL; + gboolean success = FALSE; GList *values = NULL, *inner_values = NULL; FilterXObject *foo = filterx_string_new("foo", -1); @@ -200,70 +216,94 @@ Test(filterx_expr, test_filterx_dict_merge) // {"foo": 42}; - values = g_list_append(NULL, filterx_kv_new("foo", filterx_literal_new(filterx_integer_new(42)))); - dict_expr = filterx_dict_expr_new(fillable, values); - - // $fillable << {"foo": 42}; + values = g_list_append(NULL, filterx_literal_generator_elem_new(filterx_literal_new(filterx_object_ref(foo)), + filterx_literal_new(filterx_integer_new(42)), + TRUE)); + dict_expr = filterx_literal_dict_generator_new(); + filterx_generator_set_fillable(dict_expr, filterx_expr_ref(fillable)); + filterx_literal_generator_set_elements(dict_expr, values); + + // $fillable += {"foo": 42}; result = filterx_expr_eval(dict_expr); - cr_assert_eq(result, json); - cr_assert(filterx_object_is_type(result, &FILTERX_TYPE_NAME(dict))); - cr_assert_eq(filterx_dict_len(result), 1); - _assert_int_value_and_unref(filterx_object_get_subscript(result, foo), 42); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_dict_len(json), 1); + _assert_int_value_and_unref(filterx_object_get_subscript(json, foo), 42); filterx_object_unref(result); - // $fillable << {"foo": 42}; + // $fillable += {"foo": 42}; result = filterx_expr_eval(dict_expr); - cr_assert_eq(result, json); - cr_assert_eq(filterx_dict_len(result), 1); - _assert_int_value_and_unref(filterx_object_get_subscript(result, foo), 42); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_dict_len(json), 1); + _assert_int_value_and_unref(filterx_object_get_subscript(json, foo), 42); filterx_object_unref(result); filterx_expr_unref(dict_expr); // {"foo": 420}; - values = g_list_append(NULL, filterx_kv_new("foo", filterx_literal_new(filterx_integer_new(420)))); - dict_expr = filterx_dict_expr_new(fillable, values); - - // $fillable << {"foo": 420}; + values = g_list_append(NULL, filterx_literal_generator_elem_new(filterx_literal_new(filterx_object_ref(foo)), + filterx_literal_new(filterx_integer_new(420)), + TRUE)); + dict_expr = filterx_literal_dict_generator_new(); + filterx_generator_set_fillable(dict_expr, filterx_expr_ref(fillable)); + filterx_literal_generator_set_elements(dict_expr, values); + + // $fillable += {"foo": 420}; result = filterx_expr_eval(dict_expr); - cr_assert_eq(result, json); - cr_assert(filterx_object_is_type(result, &FILTERX_TYPE_NAME(dict))); - cr_assert_eq(filterx_dict_len(result), 1); - _assert_int_value_and_unref(filterx_object_get_subscript(result, foo), 420); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_dict_len(json), 1); + _assert_int_value_and_unref(filterx_object_get_subscript(json, foo), 420); filterx_object_unref(result); filterx_expr_unref(dict_expr); // {"bar": 1337}; - values = g_list_append(NULL, filterx_kv_new("bar", filterx_literal_new(filterx_integer_new(1337)))); - dict_expr = filterx_dict_expr_new(fillable, values); - - // $fillable << {"bar": 1337}; + values = g_list_append(NULL, filterx_literal_generator_elem_new(filterx_literal_new(filterx_object_ref(bar)), + filterx_literal_new(filterx_integer_new(1337)), + TRUE)); + dict_expr = filterx_literal_dict_generator_new(); + filterx_generator_set_fillable(dict_expr, filterx_expr_ref(fillable)); + filterx_literal_generator_set_elements(dict_expr, values); + + // $fillable += {"bar": 1337}; result = filterx_expr_eval(dict_expr); - cr_assert_eq(result, json); - cr_assert(filterx_object_is_type(result, &FILTERX_TYPE_NAME(dict))); - cr_assert_eq(filterx_dict_len(result), 2); - _assert_int_value_and_unref(filterx_object_get_subscript(result, foo), 420); - _assert_int_value_and_unref(filterx_object_get_subscript(result, bar), 1337); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_dict_len(json), 2); + _assert_int_value_and_unref(filterx_object_get_subscript(json, foo), 420); + _assert_int_value_and_unref(filterx_object_get_subscript(json, bar), 1337); filterx_object_unref(result); filterx_expr_unref(dict_expr); // {"baz": {"foo": 1}}; - inner_values = g_list_append(NULL, filterx_kv_new("foo", filterx_literal_new(filterx_integer_new(1)))); - values = g_list_append(NULL, filterx_kv_new("baz", filterx_dict_expr_inner_new(fillable, inner_values))); - dict_expr = filterx_dict_expr_new(fillable, values); - - // $fillable << {"baz": {"foo": 1}}; + dict_expr = filterx_literal_dict_generator_new(); + filterx_generator_set_fillable(dict_expr, filterx_expr_ref(fillable)); + inner_values = g_list_append(NULL, filterx_literal_generator_elem_new(filterx_literal_new(filterx_object_ref(foo)), + filterx_literal_new(filterx_integer_new(1)), + TRUE)); + values = g_list_append(NULL, filterx_literal_generator_elem_new(filterx_literal_new(filterx_object_ref(baz)), + filterx_literal_inner_dict_generator_new(dict_expr, inner_values), + FALSE)); + filterx_literal_generator_set_elements(dict_expr, values); + + // $fillable += {"baz": {"foo": 1}}; result = filterx_expr_eval(dict_expr); - cr_assert_eq(result, json); - cr_assert(filterx_object_is_type(result, &FILTERX_TYPE_NAME(dict))); - cr_assert_eq(filterx_dict_len(result), 3); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_dict_len(json), 3); - FilterXObject *stored_inner_dict = filterx_object_get_subscript(result, baz); + FilterXObject *stored_inner_dict = filterx_object_get_subscript(json, baz); cr_assert(stored_inner_dict); cr_assert(filterx_object_is_type(stored_inner_dict, &FILTERX_TYPE_NAME(dict))); cr_assert_eq(filterx_dict_len(stored_inner_dict), 1); @@ -272,14 +312,15 @@ Test(filterx_expr, test_filterx_dict_merge) filterx_object_unref(result); - // $fillable << {"foo": 1}}; + // $fillable += {"foo": 1}}; // Shallow merge. result = filterx_expr_eval(dict_expr); - cr_assert_eq(result, json); - cr_assert(filterx_object_is_type(result, &FILTERX_TYPE_NAME(dict))); - cr_assert_eq(filterx_dict_len(result), 3); + cr_assert(result); + cr_assert(filterx_boolean_unwrap(result, &success)); + cr_assert(success); + cr_assert_eq(filterx_dict_len(json), 3); - stored_inner_dict = filterx_object_get_subscript(result, baz); + stored_inner_dict = filterx_object_get_subscript(json, baz); cr_assert(stored_inner_dict); cr_assert(filterx_object_is_type(stored_inner_dict, &FILTERX_TYPE_NAME(dict))); cr_assert_eq(filterx_dict_len(stored_inner_dict), 1); diff --git a/modules/json/filterx-format-json.c b/modules/json/filterx-format-json.c index d4b8af66fbc..ae3656d173c 100644 --- a/modules/json/filterx-format-json.c +++ b/modules/json/filterx-format-json.c @@ -289,6 +289,8 @@ _format_and_append_value(FilterXObject *value, GString *result) if (filterx_object_is_type(value, &FILTERX_TYPE_NAME(list))) return _format_and_append_list(value, result); + /* FIXME: handle datetime based on object-datetime.c:_convert_unix_time_to_string() */ + return _repr_append(value, result); } diff --git a/tests/light/functional_tests/filterx/test_filterx.py b/tests/light/functional_tests/filterx/test_filterx.py index 837419a1e5b..1b8d89ebdba 100644 --- a/tests/light/functional_tests/filterx/test_filterx.py +++ b/tests/light/functional_tests/filterx/test_filterx.py @@ -518,6 +518,24 @@ def test_list_subscript_without_index_appends_an_element(config, syslog_ng): assert file_true.read_log() == """foo,bar,baz\n""" +def test_literal_generator_assignment(config, syslog_ng): + (file_true, file_false) = create_config( + config, """ +$MSG = json(); +$MSG.foo = {"answer": 42, "leet": 1337}; +$MSG["bar"] = {"answer+1": 43, "leet+1": 1338}; +$MSG.list = ["will be replaced"]; +$MSG.list[0] = [1, 2, 3]; +$MSG.list[] = [4, 5, 6]; +""", + ) + syslog_ng.start(config) + + assert file_true.get_stats()["processed"] == 1 + assert "processed" not in file_false.get_stats() + assert file_true.read_log() == """{"foo":{"answer":42,"leet":1337},"bar":{"answer+1":43,"leet+1":1338},"list":[[1,2,3],[4,5,6]]}\n""" + + def test_function_call(config, syslog_ng): (file_true, file_false) = create_config( config, """