diff --git a/lib/filterx/expr-boolalg.c b/lib/filterx/expr-boolalg.c index b10dd5aad..d3f8eb855 100644 --- a/lib/filterx/expr-boolalg.c +++ b/lib/filterx/expr-boolalg.c @@ -36,6 +36,20 @@ _literal_expr_truthy(FilterXExpr *expr) return truthy; } +static FilterXExpr * +_optimize_not(FilterXExpr *s) +{ + FilterXUnaryOp *self = (FilterXUnaryOp *) s; + + if (filterx_unary_op_optimize_method(s)) + g_assert_not_reached(); + + if (!filterx_expr_is_literal(self->operand)) + return NULL; + + return filterx_literal_new(filterx_boolean_new(!_literal_expr_truthy(self->operand))); +} + static FilterXObject * _eval_not(FilterXExpr *s) { @@ -57,20 +71,41 @@ _eval_not(FilterXExpr *s) FilterXExpr * filterx_unary_not_new(FilterXExpr *operand) { - if (filterx_expr_is_literal(operand)) - { - FilterXExpr *optimized = filterx_literal_new(filterx_boolean_new(!_literal_expr_truthy(operand))); - filterx_expr_unref(operand); - return optimized; - } - FilterXUnaryOp *self = g_new0(FilterXUnaryOp, 1); filterx_unary_op_init_instance(self, "not", operand); + self->super.optimize = _optimize_not; self->super.eval = _eval_not; return &self->super; } +static FilterXExpr * +_optimize_and(FilterXExpr *s) +{ + FilterXBinaryOp *self = (FilterXBinaryOp *) s; + + if (filterx_binary_op_optimize_method(s)) + g_assert_not_reached(); + + if (!filterx_expr_is_literal(self->lhs)) + return NULL; + + if (!_literal_expr_truthy(self->lhs)) + return filterx_literal_new(filterx_boolean_new(FALSE)); + + if (!filterx_expr_is_literal(self->rhs)) + { + /* we can't optimize the AND away, but the LHS is a literal & truthy + * value. In this case we won't need to evaluate this every time in + * eval(), so unset it */ + filterx_expr_unref(self->lhs); + self->lhs = NULL; + return NULL; + } + + return filterx_literal_new(filterx_boolean_new(_literal_expr_truthy(self->rhs))); +} + static FilterXObject * _eval_and(FilterXExpr *s) { @@ -108,38 +143,42 @@ _eval_and(FilterXExpr *s) FilterXExpr * filterx_binary_and_new(FilterXExpr *lhs, FilterXExpr *rhs) { - FilterXExpr *optimized = NULL; - if (filterx_expr_is_literal(lhs)) - { - if (!_literal_expr_truthy(lhs)) - { - optimized = filterx_literal_new(filterx_boolean_new(FALSE)); - goto optimize; - } - - if (filterx_expr_is_literal(rhs)) - { - optimized = filterx_literal_new(filterx_boolean_new(_literal_expr_truthy(rhs))); - goto optimize; - } - } - FilterXBinaryOp *self = g_new0(FilterXBinaryOp, 1); filterx_binary_op_init_instance(self, "and", lhs, rhs); - if (filterx_expr_is_literal(lhs)) + + self->super.optimize = _optimize_and; + self->super.eval = _eval_and; + return &self->super; + +} + +static FilterXExpr * +_optimize_or(FilterXExpr *s) +{ + FilterXBinaryOp *self = (FilterXBinaryOp *) s; + + if (filterx_binary_op_optimize_method(s)) + g_assert_not_reached(); + + if (!filterx_expr_is_literal(self->lhs)) + return NULL; + + if (_literal_expr_truthy(self->lhs)) + return filterx_literal_new(filterx_boolean_new(TRUE)); + + if (!filterx_expr_is_literal(self->rhs)) { + /* we can't optimize the OR away (as rhs is not literal), but we do + * know that the lhs is literal and is a falsy value. In this case we + * won't need to evaluate this every time in eval(), so unset it */ + filterx_expr_unref(self->lhs); self->lhs = NULL; + return NULL; } - self->super.eval = _eval_and; - return &self->super; - -optimize: - filterx_expr_unref(lhs); - filterx_expr_unref(rhs); - return optimized; + return filterx_literal_new(filterx_boolean_new(_literal_expr_truthy(self->rhs))); } static FilterXObject * @@ -179,36 +218,11 @@ _eval_or(FilterXExpr *s) FilterXExpr * filterx_binary_or_new(FilterXExpr *lhs, FilterXExpr *rhs) { - FilterXExpr *optimized = NULL; - if (filterx_expr_is_literal(lhs)) - { - if (_literal_expr_truthy(lhs)) - { - optimized = filterx_literal_new(filterx_boolean_new(TRUE)); - goto optimize; - } - - if (filterx_expr_is_literal(rhs)) - { - optimized = filterx_literal_new(filterx_boolean_new(_literal_expr_truthy(rhs))); - goto optimize; - } - } - FilterXBinaryOp *self = g_new0(FilterXBinaryOp, 1); filterx_binary_op_init_instance(self, "or", lhs, rhs); - if (filterx_expr_is_literal(lhs)) - { - filterx_expr_unref(self->lhs); - self->lhs = NULL; - } + self->super.optimize = _optimize_or; self->super.eval = _eval_or; return &self->super; - -optimize: - filterx_expr_unref(lhs); - filterx_expr_unref(rhs); - return optimized; } diff --git a/lib/filterx/expr-comparison.c b/lib/filterx/expr-comparison.c index 8220b6770..e94c7d93c 100644 --- a/lib/filterx/expr-comparison.c +++ b/lib/filterx/expr-comparison.c @@ -237,6 +237,24 @@ _eval(FilterXExpr *s) return filterx_boolean_new(result); } +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXComparison *self = (FilterXComparison *) s; + + gint compare_mode = self->operator & FCMPX_MODE_MASK; + if (filterx_expr_is_literal(self->super.lhs)) + self->literal_lhs = _eval_based_on_compare_mode(self->super.lhs, compare_mode); + + if (filterx_expr_is_literal(self->super.rhs)) + self->literal_rhs = _eval_based_on_compare_mode(self->super.rhs, compare_mode); + + if (self->literal_lhs && self->literal_rhs) + return filterx_literal_new(_eval(&self->super.super)); + + return NULL; +} + static void _filterx_comparison_free(FilterXExpr *s) { @@ -254,23 +272,10 @@ filterx_comparison_new(FilterXExpr *lhs, FilterXExpr *rhs, gint operator) FilterXComparison *self = g_new0(FilterXComparison, 1); filterx_binary_op_init_instance(&self->super, "comparison", lhs, rhs); + self->super.super.optimize = _optimize; self->super.super.eval = _eval; self->super.super.free_fn = _filterx_comparison_free; self->operator = operator; - gint compare_mode = self->operator & FCMPX_MODE_MASK; - if (filterx_expr_is_literal(lhs)) - self->literal_lhs = _eval_based_on_compare_mode(lhs, compare_mode); - - if (filterx_expr_is_literal(rhs)) - self->literal_rhs = _eval_based_on_compare_mode(rhs, compare_mode); - - if (filterx_expr_is_literal(lhs) && filterx_expr_is_literal(rhs)) - { - FilterXExpr *optimized = filterx_literal_new(_eval(&self->super.super)); - filterx_expr_unref(&self->super.super); - return optimized; - } - return &self->super.super; } diff --git a/lib/filterx/expr-compound.c b/lib/filterx/expr-compound.c index 041a7b242..edf922e91 100644 --- a/lib/filterx/expr-compound.c +++ b/lib/filterx/expr-compound.c @@ -136,6 +136,19 @@ _eval(FilterXExpr *s) return result; } +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXCompoundExpr *self = (FilterXCompoundExpr *) s; + + for (gint i = 0; i < self->exprs->len; i++) + { + FilterXExpr **expr = (FilterXExpr **) &g_ptr_array_index(self->exprs, i); + *expr = filterx_expr_optimize(*expr); + } + return NULL; +} + static gboolean _init(FilterXExpr *s, GlobalConfig *cfg) { @@ -220,6 +233,7 @@ filterx_compound_expr_new(gboolean return_value_of_last_expr) filterx_expr_init_instance(&self->super); self->super.eval = _eval; + self->super.optimize = _optimize; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; diff --git a/lib/filterx/expr-condition.c b/lib/filterx/expr-condition.c index 95494fe34..ee49c2b59 100644 --- a/lib/filterx/expr-condition.c +++ b/lib/filterx/expr-condition.c @@ -38,6 +38,7 @@ struct _FilterXConditional FilterXExpr *false_branch; }; + static gboolean _init(FilterXExpr *s, GlobalConfig *cfg) { @@ -68,7 +69,6 @@ _init(FilterXExpr *s, GlobalConfig *cfg) return filterx_expr_init_method(s, cfg); } - static void _deinit(FilterXExpr *s, GlobalConfig *cfg) { @@ -146,6 +146,50 @@ _eval(FilterXExpr *s) return result; } +static void +_optimize_branches(FilterXExpr *s) +{ + FilterXConditional *self = (FilterXConditional *) s; + + self->condition = filterx_expr_optimize(self->condition); + self->true_branch = filterx_expr_optimize(self->true_branch); + self->false_branch = filterx_expr_optimize(self->false_branch); +} + +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXConditional *self = (FilterXConditional *) s; + + _optimize_branches(s); + + if (!filterx_expr_is_literal(self->condition)) + return FALSE; + + FilterXObject *condition_value = filterx_expr_eval(self->condition); + + g_assert(condition_value); + gboolean condition_truthy = filterx_object_truthy(condition_value); + filterx_object_unref(condition_value); + + if (condition_truthy) + { + if (self->true_branch) + return filterx_expr_ref(self->true_branch); + else + return filterx_expr_ref(self->condition); + } + else + { + if (self->false_branch) + return filterx_expr_ref(self->false_branch); + else + return filterx_literal_new(filterx_boolean_new(TRUE)); + } + + return NULL; +} + void filterx_conditional_set_true_branch(FilterXExpr *s, FilterXExpr *true_branch) { @@ -170,6 +214,7 @@ filterx_conditional_new(FilterXExpr *condition) FilterXConditional *self = g_new0(FilterXConditional, 1); filterx_expr_init_instance(&self->super); self->super.eval = _eval; + self->super.optimize = _optimize; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; @@ -197,37 +242,3 @@ filterx_conditional_find_tail(FilterXExpr *s) } return s; } - -FilterXExpr * -filterx_literal_conditional(FilterXExpr *condition, FilterXExpr *true_branch, FilterXExpr *false_branch) -{ - g_assert(filterx_expr_is_literal(condition)); - - FilterXObject *condition_value = filterx_expr_eval(condition); - g_assert(condition_value); - - FilterXExpr *optimized = NULL; - - if (filterx_object_truthy(condition_value)) - { - if (true_branch) - optimized = true_branch; - else - optimized = filterx_expr_ref(condition); - - filterx_expr_unref(false_branch); - } - else - { - if (false_branch) - optimized = false_branch; - else - optimized = filterx_literal_new(filterx_boolean_new(TRUE)); - - filterx_expr_unref(true_branch); - } - - filterx_object_unref(condition_value); - filterx_expr_unref(condition); - return optimized; -} diff --git a/lib/filterx/expr-condition.h b/lib/filterx/expr-condition.h index 8b602de07..cd463f8ea 100644 --- a/lib/filterx/expr-condition.h +++ b/lib/filterx/expr-condition.h @@ -31,6 +31,4 @@ void filterx_conditional_set_false_branch(FilterXExpr *s, FilterXExpr *false_bra FilterXExpr *filterx_conditional_find_tail(FilterXExpr *s); FilterXExpr *filterx_conditional_new(FilterXExpr *condition); -FilterXExpr *filterx_literal_conditional(FilterXExpr *condition, FilterXExpr *true_branch, FilterXExpr *false_branch); - #endif diff --git a/lib/filterx/expr-function.c b/lib/filterx/expr-function.c index 013bcf7e0..bedc06399 100644 --- a/lib/filterx/expr-function.c +++ b/lib/filterx/expr-function.c @@ -134,6 +134,19 @@ _simple_eval(FilterXExpr *s) return res; } +static FilterXExpr * +_simple_optimize(FilterXExpr *s) +{ + FilterXSimpleFunction *self = (FilterXSimpleFunction *) s; + + for (guint64 i = 0; i < self->args->len; i++) + { + FilterXExpr **arg = (FilterXExpr **) &g_ptr_array_index(self->args, i); + *arg = filterx_expr_optimize(*arg); + } + return filterx_function_optimize_method(&self->super); +} + static gboolean _simple_init(FilterXExpr *s, GlobalConfig *cfg) { @@ -206,6 +219,7 @@ filterx_simple_function_new(const gchar *function_name, FilterXFunctionArgs *arg filterx_function_init_instance(&self->super, function_name); self->super.super.eval = _simple_eval; + self->super.super.optimize = _simple_optimize; self->super.super.init = _simple_init; self->super.super.deinit = _simple_deinit; self->super.super.free_fn = _simple_free; @@ -225,6 +239,12 @@ filterx_simple_function_new(const gchar *function_name, FilterXFunctionArgs *arg return NULL; } +FilterXExpr * +filterx_function_optimize_method(FilterXFunction *s) +{ + return NULL; +} + gboolean filterx_function_init_method(FilterXFunction *s, GlobalConfig *cfg) { diff --git a/lib/filterx/expr-function.h b/lib/filterx/expr-function.h index 0c1085f2a..f657c0333 100644 --- a/lib/filterx/expr-function.h +++ b/lib/filterx/expr-function.h @@ -70,6 +70,7 @@ enum FilterXFunctionError }; void filterx_function_init_instance(FilterXFunction *s, const gchar *function_name); +FilterXExpr *filterx_function_optimize_method(FilterXFunction *s); gboolean filterx_function_init_method(FilterXFunction *s, GlobalConfig *cfg); void filterx_function_deinit_method(FilterXFunction *s, GlobalConfig *cfg); void filterx_function_free_method(FilterXFunction *s); diff --git a/lib/filterx/expr-generator.c b/lib/filterx/expr-generator.c index 378c989a5..246400f34 100644 --- a/lib/filterx/expr-generator.c +++ b/lib/filterx/expr-generator.c @@ -55,10 +55,20 @@ filterx_expr_is_generator(FilterXExpr *s) return s && s->eval == _eval; } +FilterXExpr * +filterx_generator_optimize_method(FilterXExpr *s) +{ + FilterXExprGenerator *self = (FilterXExprGenerator *) s; + + self->fillable = filterx_expr_optimize(self->fillable); + return NULL; +} + void filterx_generator_init_instance(FilterXExpr *s) { filterx_expr_init_instance(s); + s->optimize = filterx_generator_optimize_method; s->init = filterx_generator_init_method; s->deinit = filterx_generator_deinit_method; s->eval = _eval; @@ -109,6 +119,15 @@ _create_container_eval(FilterXExpr *s) return self->generator->create_container(self->generator, self->fillable_parent); } +static FilterXExpr * +_create_container_optimize(FilterXExpr *s) +{ + FilterXExprGeneratorCreateContainer *self = (FilterXExprGeneratorCreateContainer *) s; + + self->fillable_parent = filterx_expr_optimize(self->fillable_parent); + return NULL; +} + static gboolean _create_container_init(FilterXExpr *s, GlobalConfig *cfg) { @@ -172,6 +191,7 @@ filterx_generator_create_container_new(FilterXExpr *g, FilterXExpr *fillable_par filterx_expr_init_instance(&self->super); self->generator = (FilterXExprGenerator *) g; self->fillable_parent = fillable_parent; + self->super.optimize = _create_container_optimize; self->super.init = _create_container_init; self->super.deinit = _create_container_deinit; self->super.eval = _create_container_eval; diff --git a/lib/filterx/expr-generator.h b/lib/filterx/expr-generator.h index f3026c448..6308d73f9 100644 --- a/lib/filterx/expr-generator.h +++ b/lib/filterx/expr-generator.h @@ -37,6 +37,7 @@ struct FilterXExprGenerator_ void filterx_generator_set_fillable(FilterXExpr *s, FilterXExpr *fillable); void filterx_generator_init_instance(FilterXExpr *s); +FilterXExpr *filterx_generator_optimize_method(FilterXExpr *s); gboolean filterx_generator_init_method(FilterXExpr *s, GlobalConfig *cfg); void filterx_generator_deinit_method(FilterXExpr *s, GlobalConfig *cfg); void filterx_generator_free_method(FilterXExpr *s); diff --git a/lib/filterx/expr-get-subscript.c b/lib/filterx/expr-get-subscript.c index 32a1d51ce..13bfe4dd2 100644 --- a/lib/filterx/expr-get-subscript.c +++ b/lib/filterx/expr-get-subscript.c @@ -105,6 +105,16 @@ _unset(FilterXExpr *s) return result; } +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXGetSubscript *self = (FilterXGetSubscript *) s; + + self->operand = filterx_expr_optimize(self->operand); + self->key = filterx_expr_optimize(self->key); + return NULL; +} + static gboolean _init(FilterXExpr *s, GlobalConfig *cfg) { @@ -163,6 +173,7 @@ filterx_get_subscript_new(FilterXExpr *operand, FilterXExpr *key) self->super.eval = _eval; self->super.is_set = _isset; self->super.unset = _unset; + self->super.optimize = _optimize; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; diff --git a/lib/filterx/expr-getattr.c b/lib/filterx/expr-getattr.c index f85bf1585..825029472 100644 --- a/lib/filterx/expr-getattr.c +++ b/lib/filterx/expr-getattr.c @@ -92,6 +92,15 @@ _isset(FilterXExpr *s) return result; } +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXGetAttr *self = (FilterXGetAttr *) s; + + self->operand = filterx_expr_optimize(self->operand); + return NULL; +} + static gboolean _init(FilterXExpr *s, GlobalConfig *cfg) { @@ -143,6 +152,7 @@ filterx_getattr_new(FilterXExpr *operand, FilterXString *attr_name) self->super.eval = _eval; self->super.unset = _unset; self->super.is_set = _isset; + self->super.optimize = _optimize; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; diff --git a/lib/filterx/expr-literal-generator.c b/lib/filterx/expr-literal-generator.c index 465496bec..5776b6760 100644 --- a/lib/filterx/expr-literal-generator.c +++ b/lib/filterx/expr-literal-generator.c @@ -59,6 +59,13 @@ _literal_generator_elem_init(FilterXLiteralGeneratorElem *self, GlobalConfig *cf return TRUE; } +static void +_literal_generator_elem_optimize(FilterXLiteralGeneratorElem *self) +{ + self->key = filterx_expr_optimize(self->key); + self->value = filterx_expr_optimize(self->value); +} + static void _literal_generator_elem_deinit(FilterXLiteralGeneratorElem *self, GlobalConfig *cfg) { @@ -140,6 +147,21 @@ _literal_generator_generate(FilterXExprGenerator *s, FilterXObject *fillable) return _eval_elements(fillable, self->elements); } +static FilterXExpr * +_literal_generator_optimize(FilterXExpr *s) +{ + FilterXExprLiteralGenerator *self = (FilterXExprLiteralGenerator *) s; + + for (GList *link = self->elements; link; link = link->next) + { + FilterXLiteralGeneratorElem *elem = (FilterXLiteralGeneratorElem *) link->data; + + _literal_generator_elem_optimize(elem); + } + + return filterx_generator_optimize_method(s); +} + static gboolean _literal_generator_init(FilterXExpr *s, GlobalConfig *cfg) { @@ -191,6 +213,7 @@ _literal_generator_init_instance(FilterXExprLiteralGenerator *self) { filterx_generator_init_instance(&self->super.super); self->super.generate = _literal_generator_generate; + self->super.super.optimize = _literal_generator_optimize; self->super.super.init = _literal_generator_init; self->super.super.deinit = _literal_generator_deinit; self->super.super.free_fn = _literal_generator_free; diff --git a/lib/filterx/expr-plus-generator.c b/lib/filterx/expr-plus-generator.c index a0677ab65..662a6ae48 100644 --- a/lib/filterx/expr-plus-generator.c +++ b/lib/filterx/expr-plus-generator.c @@ -100,6 +100,16 @@ _expr_plus_generator_create_container(FilterXExprGenerator *s, FilterXExpr *fill return generator->create_container(generator, fillable_parent); } +static FilterXExpr * +_expr_plus_generator_optimize(FilterXExpr *s) +{ + FilterXOperatorPlusGenerator *self = (FilterXOperatorPlusGenerator *) s; + + self->lhs = filterx_expr_optimize(self->lhs); + self->rhs = filterx_expr_optimize(self->rhs); + return filterx_generator_optimize_method(s); +} + static gboolean _expr_plus_generator_init(FilterXExpr *s, GlobalConfig *cfg) { @@ -142,6 +152,7 @@ filterx_operator_plus_generator_new(FilterXExpr *lhs, FilterXExpr *rhs) self->lhs = lhs; self->rhs = rhs; self->super.generate = _expr_plus_generator_generate; + self->super.super.optimize = _expr_plus_generator_optimize; self->super.super.init = _expr_plus_generator_init; self->super.super.deinit = _expr_plus_generator_deinit; self->super.super.free_fn = _expr_plus_generator_free; diff --git a/lib/filterx/expr-plus.c b/lib/filterx/expr-plus.c index f5e562f4a..f31d7f181 100644 --- a/lib/filterx/expr-plus.c +++ b/lib/filterx/expr-plus.c @@ -57,6 +57,25 @@ _eval(FilterXExpr *s) return res; } +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXOperatorPlus *self = (FilterXOperatorPlus *) s; + + if (filterx_binary_op_optimize_method(s)) + g_assert_not_reached(); + + if (filterx_expr_is_literal(self->super.lhs)) + self->literal_lhs = filterx_expr_eval_typed(self->super.lhs); + + if (filterx_expr_is_literal(self->super.rhs)) + self->literal_rhs = filterx_expr_eval(self->super.rhs); + + if (self->literal_lhs && self->literal_rhs) + return filterx_literal_new(_eval(&self->super.super)); + return NULL; +} + static void _filterx_operator_plus_free(FilterXExpr *s) { @@ -72,21 +91,9 @@ filterx_operator_plus_new(FilterXExpr *lhs, FilterXExpr *rhs) { FilterXOperatorPlus *self = g_new0(FilterXOperatorPlus, 1); filterx_binary_op_init_instance(&self->super, "plus", lhs, rhs); + self->super.super.optimize = _optimize; self->super.super.eval = _eval; self->super.super.free_fn = _filterx_operator_plus_free; - if (filterx_expr_is_literal(lhs)) - self->literal_lhs = filterx_expr_eval_typed(lhs); - - if (filterx_expr_is_literal(rhs)) - self->literal_rhs = filterx_expr_eval(rhs); - - if (filterx_expr_is_literal(lhs) && filterx_expr_is_literal(rhs)) - { - FilterXExpr *optimized = filterx_literal_new(_eval(&self->super.super)); - filterx_expr_unref(&self->super.super); - return optimized; - } - return &self->super.super; } diff --git a/lib/filterx/expr-regexp-search.c b/lib/filterx/expr-regexp-search.c index 2efd9cf69..4769def16 100644 --- a/lib/filterx/expr-regexp-search.c +++ b/lib/filterx/expr-regexp-search.c @@ -214,6 +214,15 @@ _regexp_search_generator_create_container(FilterXExprGenerator *s, FilterXExpr * return filterx_generator_create_dict_container(s, fillable_parent); } +static FilterXExpr * +_regexp_search_generator_optimize(FilterXExpr *s) +{ + FilterXExprRegexpSearchGenerator *self = (FilterXExprRegexpSearchGenerator *) s; + + self->lhs = filterx_expr_optimize(self->lhs); + return filterx_generator_optimize_method(s); +} + static gboolean _regexp_search_generator_init(FilterXExpr *s, GlobalConfig *cfg) { @@ -293,6 +302,7 @@ filterx_generator_function_regexp_search_new(FilterXFunctionArgs *args, GError * filterx_generator_function_init_instance(&self->super, "regexp_search"); self->super.super.generate = _regexp_search_generator_generate; + self->super.super.super.optimize = _regexp_search_generator_optimize; self->super.super.super.init = _regexp_search_generator_init; self->super.super.super.deinit = _regexp_search_generator_deinit; self->super.super.super.free_fn = _regexp_search_generator_free; diff --git a/lib/filterx/expr-regexp-subst.c b/lib/filterx/expr-regexp-subst.c index ba6d2bb95..ed0c6264d 100644 --- a/lib/filterx/expr-regexp-subst.c +++ b/lib/filterx/expr-regexp-subst.c @@ -333,6 +333,15 @@ _extract_subst_args(FilterXFuncRegexpSubst *self, FilterXFunctionArgs *args, GEr return TRUE; } +static FilterXExpr * +_subst_optimize(FilterXExpr *s) +{ + FilterXFuncRegexpSubst *self = (FilterXFuncRegexpSubst *) s; + + self->string_expr = filterx_expr_optimize(self->string_expr); + return filterx_function_optimize_method(&self->super); +} + static gboolean _subst_init(FilterXExpr *s, GlobalConfig *cfg) { @@ -369,6 +378,7 @@ filterx_function_regexp_subst_new(FilterXFunctionArgs *args, GError **error) FilterXFuncRegexpSubst *self = g_new0(FilterXFuncRegexpSubst, 1); filterx_function_init_instance(&self->super, "regexp_subst"); self->super.super.eval = _subst_eval; + self->super.super.optimize = _subst_optimize; self->super.super.init = _subst_init; self->super.super.deinit = _subst_deinit; self->super.super.free_fn = _subst_free; diff --git a/lib/filterx/expr-regexp.c b/lib/filterx/expr-regexp.c index cc02da193..f6ed993d6 100644 --- a/lib/filterx/expr-regexp.c +++ b/lib/filterx/expr-regexp.c @@ -65,6 +65,15 @@ _regexp_match_eval(FilterXExpr *s) return result; } +static FilterXExpr * +_regexp_match_optimize(FilterXExpr *s) +{ + FilterXExprRegexpMatch *self = (FilterXExprRegexpMatch *) s; + + self->lhs = filterx_expr_optimize(self->lhs); + return NULL; +} + static gboolean _regexp_match_init(FilterXExpr *s, GlobalConfig *cfg) { @@ -104,6 +113,7 @@ filterx_expr_regexp_match_new(FilterXExpr *lhs, const gchar *pattern) filterx_expr_init_instance(&self->super); self->super.eval = _regexp_match_eval; + self->super.optimize = _regexp_match_optimize; self->super.init = _regexp_match_init; self->super.deinit = _regexp_match_deinit; self->super.free_fn = _regexp_match_free; diff --git a/lib/filterx/expr-set-subscript.c b/lib/filterx/expr-set-subscript.c index cfb5c100a..040c0650c 100644 --- a/lib/filterx/expr-set-subscript.c +++ b/lib/filterx/expr-set-subscript.c @@ -148,6 +148,17 @@ _set_subscript_eval(FilterXExpr *s) return result; } +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXSetSubscript *self = (FilterXSetSubscript *) s; + + self->object = filterx_expr_optimize(self->object); + self->new_value = filterx_expr_optimize(self->new_value); + self->key = filterx_expr_optimize(self->key); + return NULL; +} + static gboolean _init(FilterXExpr *s, GlobalConfig *cfg) { @@ -213,6 +224,7 @@ filterx_nullv_set_subscript_new(FilterXExpr *object, FilterXExpr *key, FilterXEx filterx_expr_init_instance(&self->super); self->super.eval = _nullv_set_subscript_eval; + self->super.optimize = _optimize; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; @@ -230,6 +242,7 @@ filterx_set_subscript_new(FilterXExpr *object, FilterXExpr *key, FilterXExpr *ne filterx_expr_init_instance(&self->super); self->super.eval = _set_subscript_eval; + self->super.optimize = _optimize; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; diff --git a/lib/filterx/expr-setattr.c b/lib/filterx/expr-setattr.c index 3151a7ed4..c15a2dd5a 100644 --- a/lib/filterx/expr-setattr.c +++ b/lib/filterx/expr-setattr.c @@ -131,6 +131,16 @@ _setattr_eval(FilterXExpr *s) return result; } +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXSetAttr *self = (FilterXSetAttr *) s; + + self->object = filterx_expr_optimize(self->object); + self->new_value = filterx_expr_optimize(self->new_value); + return NULL; +} + static gboolean _init(FilterXExpr *s, GlobalConfig *cfg) { @@ -188,6 +198,7 @@ filterx_nullv_setattr_new(FilterXExpr *object, FilterXString *attr_name, FilterX filterx_expr_init_instance(&self->super); self->super.eval = _nullv_setattr_eval; + self->super.optimize = _optimize; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; @@ -208,6 +219,7 @@ filterx_setattr_new(FilterXExpr *object, FilterXString *attr_name, FilterXExpr * filterx_expr_init_instance(&self->super); self->super.eval = _setattr_eval; + self->super.optimize = _optimize; self->super.init = _init; self->super.deinit = _deinit; self->super.free_fn = _free; diff --git a/lib/filterx/expr-unset.c b/lib/filterx/expr-unset.c index b3dfa97a5..b536fcb02 100644 --- a/lib/filterx/expr-unset.c +++ b/lib/filterx/expr-unset.c @@ -46,6 +46,19 @@ _eval(FilterXExpr *s) return filterx_boolean_new(TRUE); } +static FilterXExpr * +_optimize(FilterXExpr *s) +{ + FilterXExprUnset *self = (FilterXExprUnset *) s; + + for (guint i = 0; i < self->exprs->len; i++) + { + FilterXExpr **expr = (FilterXExpr **) &g_ptr_array_index(self->exprs, i); + *expr = filterx_expr_optimize(*expr); + } + return NULL; +} + static gboolean _init(FilterXExpr *s, GlobalConfig *cfg) { @@ -98,6 +111,7 @@ filterx_function_unset_new(FilterXFunctionArgs *args, GError **error) filterx_function_init_instance(&self->super, "unset"); self->super.super.eval = _eval; + self->super.super.optimize = _optimize; self->super.super.init = _init; self->super.super.deinit = _deinit; self->super.super.free_fn = _free; diff --git a/lib/filterx/filterx-expr.c b/lib/filterx/filterx-expr.c index 88e181a7d..ab21621d0 100644 --- a/lib/filterx/filterx-expr.c +++ b/lib/filterx/filterx-expr.c @@ -30,13 +30,13 @@ #include "stats/stats-cluster-single.h" void -filterx_expr_set_location_with_text(FilterXExpr *self, CfgLexer *lexer, CFG_LTYPE *lloc, const gchar *text) +filterx_expr_set_location_with_text(FilterXExpr *self, CFG_LTYPE *lloc, const gchar *text) { if (!self->lloc) self->lloc = g_new0(CFG_LTYPE, 1); *self->lloc = *lloc; - if (debug_flag) + if (debug_flag && text) self->expr_text = g_strdup(text); } @@ -65,6 +65,40 @@ filterx_expr_format_location_tag(FilterXExpr *self) return evt_tag_str("expr", "n/a"); } +FilterXExpr * +filterx_expr_optimize(FilterXExpr *self) +{ + if (!self) + return NULL; + + if (self->optimized) + return self; + + self->optimized = TRUE; + g_assert(!self->inited); + + if (!self->optimize) + return self; + + FilterXExpr *optimized = self->optimize(self); + if (!optimized) + return self; + + /* the new expression may be also be optimized */ + optimized = filterx_expr_optimize(optimized); + + msg_trace("FilterX: expression optimized", + filterx_expr_format_location_tag(self)); + if (self->lloc) + { + /* copy location information to the optimized representation */ + filterx_expr_set_location_with_text(optimized, self->lloc, self->expr_text); + } + /* consume original expression */ + filterx_expr_unref(self); + return optimized; +} + gboolean filterx_expr_init_method(FilterXExpr *self, GlobalConfig *cfg) { @@ -127,6 +161,15 @@ filterx_expr_unref(FilterXExpr *self) } } +FilterXExpr * +filterx_unary_op_optimize_method(FilterXExpr *s) +{ + FilterXUnaryOp *self = (FilterXUnaryOp *) s; + + self->operand = filterx_expr_optimize(self->operand); + return NULL; +} + gboolean filterx_unary_op_init_method(FilterXExpr *s, GlobalConfig *cfg) { @@ -174,6 +217,7 @@ void filterx_unary_op_init_instance(FilterXUnaryOp *self, const gchar *name, FilterXExpr *operand) { filterx_expr_init_instance(&self->super); + self->super.optimize = filterx_unary_op_optimize_method; self->super.init = filterx_unary_op_init_method; self->super.deinit = filterx_unary_op_deinit_method; self->super.free_fn = filterx_unary_op_free_method; @@ -192,6 +236,16 @@ filterx_binary_op_free_method(FilterXExpr *s) filterx_expr_free_method(s); } +FilterXExpr * +filterx_binary_op_optimize_method(FilterXExpr *s) +{ + FilterXBinaryOp *self = (FilterXBinaryOp *) s; + + self->lhs = filterx_expr_optimize(self->lhs); + self->rhs = filterx_expr_optimize(self->rhs); + return NULL; +} + gboolean filterx_binary_op_init_method(FilterXExpr *s, GlobalConfig *cfg) { @@ -234,6 +288,7 @@ void filterx_binary_op_init_instance(FilterXBinaryOp *self, const gchar *name, FilterXExpr *lhs, FilterXExpr *rhs) { filterx_expr_init_instance(&self->super); + self->super.optimize = filterx_binary_op_optimize_method; self->super.init = filterx_binary_op_init_method; self->super.deinit = filterx_binary_op_deinit_method; self->super.free_fn = filterx_binary_op_free_method; diff --git a/lib/filterx/filterx-expr.h b/lib/filterx/filterx-expr.h index 1864c4b37..0a5388ccf 100644 --- a/lib/filterx/filterx-expr.h +++ b/lib/filterx/filterx-expr.h @@ -37,7 +37,7 @@ struct _FilterXExpr /* not thread-safe */ guint32 ref_cnt; - guint32 ignore_falsy_result:1, suppress_from_trace:1, inited:1; + guint32 ignore_falsy_result:1, suppress_from_trace:1, inited:1, optimized:1; /* not to be used except for FilterXMessageRef, replace any cached values * with the unmarshaled version */ @@ -53,6 +53,7 @@ struct _FilterXExpr gboolean (*init)(FilterXExpr *self, GlobalConfig *cfg); void (*deinit)(FilterXExpr *self, GlobalConfig *cfg); + FilterXExpr *(*optimize)(FilterXExpr *self); void (*free_fn)(FilterXExpr *self); const gchar *type; @@ -147,8 +148,9 @@ filterx_expr_unset_available(FilterXExpr *self) } void filterx_expr_set_location(FilterXExpr *self, CfgLexer *lexer, CFG_LTYPE *lloc); -void filterx_expr_set_location_with_text(FilterXExpr *self, CfgLexer *lexer, CFG_LTYPE *lloc, const gchar *text); +void filterx_expr_set_location_with_text(FilterXExpr *self, CFG_LTYPE *lloc, const gchar *text); EVTTAG *filterx_expr_format_location_tag(FilterXExpr *self); +FilterXExpr *filterx_expr_optimize(FilterXExpr *self); void filterx_expr_init_instance(FilterXExpr *self); FilterXExpr *filterx_expr_new(void); FilterXExpr *filterx_expr_ref(FilterXExpr *self); @@ -191,6 +193,7 @@ typedef struct _FilterXUnaryOp const gchar *name; } FilterXUnaryOp; +FilterXExpr *filterx_unary_op_optimize_method(FilterXExpr *s); gboolean filterx_unary_op_init_method(FilterXExpr *s, GlobalConfig *cfg); void filterx_unary_op_deinit_method(FilterXExpr *s, GlobalConfig *cfg); void filterx_unary_op_free_method(FilterXExpr *s); @@ -203,6 +206,7 @@ typedef struct _FilterXBinaryOp const gchar *name; } FilterXBinaryOp; +FilterXExpr *filterx_binary_op_optimize_method(FilterXExpr *s); gboolean filterx_binary_op_init_method(FilterXExpr *s, GlobalConfig *cfg); void filterx_binary_op_deinit_method(FilterXExpr *s, GlobalConfig *cfg); void filterx_binary_op_free_method(FilterXExpr *s); diff --git a/lib/filterx/filterx-grammar.ym b/lib/filterx/filterx-grammar.ym index b39b5f9b8..e0cc8090f 100644 --- a/lib/filterx/filterx-grammar.ym +++ b/lib/filterx/filterx-grammar.ym @@ -171,7 +171,7 @@ block : '{' stmts '}' { FilterXExpr *block = filterx_compound_expr_new(FALSE); filterx_compound_expr_add_list(block, $2); - filterx_expr_set_location_with_text(block, lexer, &@$, "{ ... }"); + filterx_expr_set_location_with_text(block, &@$, "{ ... }"); $$ = block; } ; @@ -641,29 +641,15 @@ ternary : expr '?' expr ':' expr { filterx_expr_set_location($1, lexer, &@1); - if (filterx_expr_is_literal($1)) - { - $$ = filterx_literal_conditional($1, $3, $5); - } - else - { - $$ = filterx_conditional_new($1); - filterx_conditional_set_true_branch($$, $3); - filterx_conditional_set_false_branch($$, $5); - } + $$ = filterx_conditional_new($1); + filterx_conditional_set_true_branch($$, $3); + filterx_conditional_set_false_branch($$, $5); } | expr '?' ':' expr { filterx_expr_set_location($1, lexer, &@1); - if (filterx_expr_is_literal($1)) - { - $$ = filterx_literal_conditional($1, NULL, $4); - } - else - { - $$ = filterx_conditional_new($1); - filterx_conditional_set_false_branch($$, $4); - } + $$ = filterx_conditional_new($1); + filterx_conditional_set_false_branch($$, $4); } ; diff --git a/lib/filterx/filterx-pipe.c b/lib/filterx/filterx-pipe.c index 1f2142edb..20c7dad90 100644 --- a/lib/filterx/filterx-pipe.c +++ b/lib/filterx/filterx-pipe.c @@ -41,6 +41,8 @@ log_filterx_pipe_init(LogPipe *s) if (!self->name) self->name = cfg_tree_get_rule_name(&cfg->tree, ENC_FILTER, s->expr_node); + self->block = filterx_expr_optimize(self->block); + if (!filterx_expr_init(self->block, cfg)) return FALSE;