diff --git a/lib/filterx/func-set-fields.c b/lib/filterx/func-set-fields.c index e3ef8f327..e7193eef8 100644 --- a/lib/filterx/func-set-fields.c +++ b/lib/filterx/func-set-fields.c @@ -24,6 +24,7 @@ #include "filterx/func-set-fields.h" #include "filterx/object-string.h" +#include "filterx/object-primitive.h" #include "filterx/object-dict-interface.h" #include "filterx/expr-literal.h" #include "filterx/expr-literal-generator.h" @@ -127,11 +128,83 @@ typedef struct FilterXFunctionSetFields_ GArray *fields; } FilterXFunctionSetFields; +static gboolean +_set_with_fallbacks(FilterXObject *dict_unwrapped, FilterXObject *key, GPtrArray *values) +{ + gboolean changed = FALSE; + + if (!values || values->len == 0) + return changed; + + for (guint i = 0; i < values->len; i++) + { + FilterXExpr *value = g_ptr_array_index(values, i); + FilterXObject *value_obj = filterx_expr_eval(value); + if (!value_obj) + { + filterx_eval_clear_errors(); + continue; + } + + FilterXObject *value_obj_cloned = filterx_object_clone(value_obj); + filterx_object_unref(value_obj); + + if (!filterx_object_set_subscript(dict_unwrapped, key, &value_obj_cloned)) + { + filterx_object_unref(value_obj_cloned); + continue; + } + + filterx_object_unref(value_obj_cloned); + changed = TRUE; + break; + } + + return changed; +} + +static void +_process_field(Field *field, FilterXObject *dict_unwrapped) +{ + gboolean changed = _set_with_fallbacks(dict_unwrapped, field->key, field->overrides); + if (changed) + return; + + if (filterx_object_is_key_set(dict_unwrapped, field->key)) + return; + + _set_with_fallbacks(dict_unwrapped, field->key, field->defaults); +} + static FilterXObject * _eval(FilterXExpr *s) { - // TODO: implement - return NULL; + FilterXFunctionSetFields *self = (FilterXFunctionSetFields *) s; + + gboolean success = FALSE; + + FilterXObject *dict = filterx_expr_eval(self->dict); + if (!dict) + goto exit; + + FilterXObject *dict_unwrapped = filterx_ref_unwrap_rw(dict); + if (!filterx_object_is_type(dict_unwrapped, &FILTERX_TYPE_NAME(dict))) + { + filterx_eval_push_error("First argument must be a dict. " FILTERX_FUNC_SET_FIELDS_USAGE, s, NULL); + goto exit; + } + + for (guint i = 0; i < self->fields->len; i++) + { + Field *field = &g_array_index(self->fields, Field, i); + _process_field(field, dict_unwrapped); + } + + success = TRUE; + +exit: + filterx_object_unref(dict); + return success ? filterx_boolean_new(TRUE) : NULL; } static gboolean