libamxp  1.4.0
Patterns C Implementation
amxp_expression_node.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #ifndef _GNU_SOURCE
56 #define _GNU_SOURCE
57 #endif
58 
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <amxc/amxc.h>
62 
63 #include "amxp_expr_priv.h"
64 
65 static void amxp_expr_node_clean_args(amxc_llist_it_t* it) {
66  amxp_expr_node_t* node = amxc_container_of(it, amxp_expr_node_t, it);
67  amxp_expr_node_delete(&node);
68 }
69 
70 static void amxp_expr_node_build_args(amxp_expr_t* expr, amxc_var_t* value, amxc_llist_t* args) {
71  amxc_var_set_type(value, AMXC_VAR_ID_LIST);
72  amxc_llist_for_each(it, args) {
73  amxp_expr_node_t* value_node = amxc_container_of(it, amxp_expr_node_t, it);
74  amxc_var_t* v = amxp_expr_node_get_value(expr, value_node);
75  amxc_var_set_index(value, -1, v, AMXC_VAR_FLAG_DEFAULT);
77  }
78 }
79 
80 static const char* amxp_expr_compop2string(amxp_expr_comp_t op) {
81  const char* string[] = {
82  "==",
83  "!=",
84  "\\<",
85  "\\>",
86  "\\<=",
87  "\\>=",
88  "matches",
89  "starts with",
90  "in",
91  "~=",
92  "^=",
93  "ends with"
94  };
95 
96  return string[op];
97 }
98 
100  *node = (amxp_expr_node_t*) calloc(1, sizeof(amxp_expr_node_t));
101  (*node)->type = type;
102 }
103 
105  when_null(node, exit);
106  when_null(*node, exit);
107 
108  amxc_llist_it_take(&(*node)->it);
109  switch((*node)->type) {
111  case amxp_expr_and:
112  case amxp_expr_or:
113  amxp_expr_node_delete(&(*node)->left.node);
114  amxp_expr_node_delete(&(*node)->right.node);
115  break;
116  case amxp_expr_not:
117  amxp_expr_node_delete(&(*node)->left.node);
118  break;
119  case amxp_expr_value:
120  if((amxc_var_type_of((*node)->left.value) == AMXC_VAR_ID_LIST) ||
121  ((*node)->left.value == NULL)) {
122  amxc_llist_clean(&(*node)->right.args, amxp_expr_node_clean_args);
123  }
124  amxc_var_delete(&(*node)->left.value);
125  break;
127  case amxp_expr_bool_func:
128  free((*node)->left.func_name);
129  (*node)->left.func_name = NULL;
130  amxc_var_delete(&(*node)->value);
131  amxc_llist_clean(&(*node)->right.args, amxp_expr_node_clean_args);
132  break;
133  case amxp_expr_field:
134  free((*node)->left.field);
135  amxc_var_delete(&(*node)->value);
136  break;
137  }
138  free(*node);
139  *node = NULL;
140 exit:
141  return;
142 }
143 
144 void amxp_expr_node_push(amxc_lstack_t* stack, amxp_expr_node_t* node) {
145  amxc_lstack_push(stack, &node->it);
146 }
147 
148 amxp_expr_node_t* amxp_expr_node_pop(amxc_lstack_t* stack) {
149  amxp_expr_node_t* node = NULL;
150  amxc_lstack_it_t* it = amxc_lstack_pop(stack);
151 
152  when_null(it, exit);
153  node = amxc_container_of(it, amxp_expr_node_t, it);
154 
155 exit:
156  return node;
157 }
158 
160  node->left.node = left;
161  amxc_llist_it_take(&left->it);
162 }
163 
165  node->right.node = right;
166  amxc_llist_it_take(&right->it);
167 }
168 
169 void amxp_expr_node_set_value(amxp_expr_node_t* node, amxc_var_t* value) {
170  node->left.value = value;
171 }
172 
173 void amxp_expr_node_set_function(amxp_expr_node_t* node, char* func_name) {
174  node->left.func_name = func_name;
175 }
176 
177 void amxp_expr_node_set_field(amxp_expr_node_t* node, char* field) {
178  node->left.field = field;
179 }
180 
182  node->compare = comop;
183 }
184 
186  amxc_llist_append(&node->right.args, &value->it);
187 }
188 
190  amxp_expr_node_t* node = NULL;
191  amxc_llist_it_t* it = amxc_llist_get_first(&expr->nodes);
192  when_null(it, exit);
193 
194  node = amxc_container_of(it, amxp_expr_node_t, it);
195 
196 exit:
197  return node;
198 }
199 
201  amxc_var_t* value = NULL;
202  switch(node->type) {
203  case amxp_expr_value:
204  if((node->left.value == NULL) ||
205  (amxc_var_type_of(node->left.value) == AMXC_VAR_ID_LIST)) {
206  if(node->left.value == NULL) {
207  amxc_var_new(&node->left.value);
208  }
209  value = node->left.value;
210  amxc_llist_clean(&value->data.vl, NULL);
211  amxp_expr_node_build_args(expr, value, &node->right.args);
212  } else {
213  value = node->left.value;
214  }
215  break;
216  case amxp_expr_field:
217  if(node->value == NULL) {
218  amxc_var_new(&node->value);
219  }
220  amxp_expr_get_field(expr, node->value, node->left.field);
221  if(expr->status == amxp_expr_status_ok) {
222  value = node->value;
223  } else {
224  amxc_var_set_type(node->value, AMXC_VAR_ID_NULL);
225  value = node->value;
226  }
227  break;
228  case amxp_expr_value_func: {
229  amxc_var_t args;
230  amxc_var_init(&args);
231  amxp_expr_node_build_args(expr, &args, &node->right.args);
232  if(node->value == NULL) {
233  amxc_var_new(&node->value);
234  }
235  amxp_expr_call_value_func(expr, node->left.func_name, &args, node->value);
236  amxc_llist_clean(&args.data.vl, NULL);
237  value = node->value;
238  }
239  break;
240  default:
241  break;
242  }
243 
244  return value;
245 }
246 
248  bool result = true;
249  when_null(node, exit);
250 
251  switch(node->type) {
252  case amxp_expr_and: {
253  bool right = false;
254  bool left = amxp_expr_node_eval(expr, node->left.node);
255  if(!left) {
256  result = left;
257  } else {
258  right = amxp_expr_node_eval(expr, node->right.node);
259  result = (left && right);
260  }
261  }
262  break;
263  case amxp_expr_or: {
264  bool right = false;
265  bool left = amxp_expr_node_eval(expr, node->left.node);
266  if(left) {
267  result = left;
268  } else {
269  right = amxp_expr_node_eval(expr, node->right.node);
270  result = (left || right);
271  }
272  }
273  break;
274  case amxp_expr_not:
275  result = !amxp_expr_node_eval(expr, node->left.node);
276  break;
277  case amxp_expr_compare_oper: {
278  amxc_var_t* left_value = amxp_expr_node_get_value(expr, node->left.node);
279  amxc_var_t* right_value = amxp_expr_node_get_value(expr, node->right.node);
280  if(!amxc_var_is_null(left_value) && !amxc_var_is_null(right_value)) {
281  result = amxp_expr_compare(expr, left_value, right_value, node->compare);
282  } else {
283  result = false;
284  }
285  }
286  break;
287  case amxp_expr_value:
288  if(amxc_var_type_of(node->left.value) != AMXC_VAR_ID_BOOL) {
290  result = false;
291  } else {
292  result = amxc_var_constcast(bool, node->left.value);
293  }
294  break;
295  case amxp_expr_field:
296  if(node->value == NULL) {
297  amxc_var_new(&node->value);
298  }
299  amxp_expr_get_field(expr, node->value, node->left.field);
300  if(expr->status != amxp_expr_status_ok) {
301  result = false;
302  } else {
303  result = amxc_var_constcast(bool, node->value);
304  }
305  break;
306  case amxp_expr_bool_func: {
307  amxc_var_t args;
308  amxc_var_init(&args);
309  amxp_expr_node_build_args(expr, &args, &node->right.args);
310  result = amxp_expr_call_bool_func(expr, node->left.func_name, &args);
311  amxc_llist_clean(&args.data.vl, NULL);
312  }
313  break;
314  default:
315  break;
316  }
317 
318 exit:
319  return result;
320 }
321 
322 void amxp_expr_node_dump(amxp_expr_t* expr, amxp_expr_node_t* node, uint32_t level, uint32_t parent_id) {
323  static uint32_t id = 0;
324  uint32_t current_id = 0;
325 
326  when_null(node, exit);
327 
328  if(level == 0) {
329  amxc_string_t expr_txt;
330  amxc_string_init(&expr_txt, 0);
331  amxc_string_setf(&expr_txt, "%s", expr->expression);
332  amxc_string_replace(&expr_txt, "\"", "\\\"", UINT32_MAX);
333  printf("digraph D {\n");
334  printf("graph [ordering=\"out\"];\n");
335  printf("label = \"%s\";\n", amxc_string_get(&expr_txt, 0));
336  printf("labelloc = \"t\";\n");
337  id = 1;
338  parent_id = 0;
339  amxc_string_clean(&expr_txt);
340  } else {
341  id++;
342  }
343 
344  current_id = id;
345 
346  printf("node_%d", current_id);
347  switch(node->type) {
349  printf("[shape=\"record\" label=\"{COMPARE|%s}\"];\n", amxp_expr_compop2string(node->compare));
350  amxp_expr_node_dump(expr, node->left.node, level + 1, current_id);
351  amxp_expr_node_dump(expr, node->right.node, level + 1, current_id);
352  break;
353  case amxp_expr_and:
354  printf("[shape=\"box\" label=\"AND\"];\n");
355  amxp_expr_node_dump(expr, node->left.node, level + 1, current_id);
356  amxp_expr_node_dump(expr, node->right.node, level + 1, current_id);
357  break;
358  case amxp_expr_or:
359  printf("[shape=\"box\" label=\"OR\"];\n");
360  amxp_expr_node_dump(expr, node->left.node, level + 1, current_id);
361  amxp_expr_node_dump(expr, node->right.node, level + 1, current_id);
362  break;
363  case amxp_expr_not:
364  printf("[shape=\"box\" label=\"NOT\"];\n");
365  amxp_expr_node_dump(expr, node->left.node, level + 1, current_id);
366  break;
367  case amxp_expr_value: {
368  char* value = amxc_var_dyncast(cstring_t, node->left.value);
369  printf("[shape=\"record\" label=\"{VALUE|%s}\"];\n", value);
370  free(value);
371  }
372  break;
374  printf("[shape=\"record\" label=\"{VALUE FUNCTION|%s}\"];\n", node->left.func_name);
375  break;
376  case amxp_expr_bool_func:
377  printf("[shape=\"record\" label=\"{BOOL FUNCTION|%s}\"];\n", node->left.func_name);
378  break;
379  case amxp_expr_field:
380  printf("[shape=\"record\" label=\"{FIELD|%s}\"];\n", node->left.field);
381  break;
382  }
383 
384  if(parent_id != 0) {
385  printf("node_%d -> node_%d;\n", parent_id, current_id);
386  }
387 
388  if(level == 0) {
389  printf("}\n");
390  }
391 
392 exit:
393  return;
394 }
enum _amxp_expr_node_type amxp_expr_node_type_t
PRIVATE void PRIVATE int PRIVATE bool amxp_expr_compare(amxp_expr_t *expr, amxc_var_t *lvalue, amxc_var_t *rvalue, amxp_expr_comp_t comperator)
enum _amxp_expr_comp amxp_expr_comp_t
PRIVATE amxp_expr_status_t amxp_expr_call_value_func(amxp_expr_t *expr, const char *func, amxc_var_t *args, amxc_var_t *ret)
@ amxp_expr_value
@ amxp_expr_bool_func
@ amxp_expr_or
@ amxp_expr_not
@ amxp_expr_compare_oper
@ amxp_expr_value_func
@ amxp_expr_field
@ amxp_expr_and
PRIVATE amxp_expr_status_t amxp_expr_get_field(amxp_expr_t *expr, amxc_var_t *var, const char *path)
PRIVATE bool amxp_expr_call_bool_func(amxp_expr_t *expr, const char *func, amxc_var_t *args)
amxp_expr_node_t * amxp_expr_get_node(amxp_expr_t *expr)
bool amxp_expr_node_eval(amxp_expr_t *expr, amxp_expr_node_t *node)
void amxp_expr_node_set_compop(amxp_expr_node_t *node, amxp_expr_comp_t comop)
void amxp_expr_node_add_value(amxp_expr_node_t *node, amxp_expr_node_t *value)
static const char * amxp_expr_compop2string(amxp_expr_comp_t op)
amxp_expr_node_t * amxp_expr_node_pop(amxc_lstack_t *stack)
static void amxp_expr_node_clean_args(amxc_llist_it_t *it)
void amxp_expr_node_push(amxc_lstack_t *stack, amxp_expr_node_t *node)
void amxp_expr_node_set_left(amxp_expr_node_t *node, amxp_expr_node_t *left)
static void amxp_expr_node_build_args(amxp_expr_t *expr, amxc_var_t *value, amxc_llist_t *args)
void amxp_expr_node_new(amxp_expr_node_t **node, amxp_expr_node_type_t type)
void amxp_expr_node_set_value(amxp_expr_node_t *node, amxc_var_t *value)
void amxp_expr_node_set_right(amxp_expr_node_t *node, amxp_expr_node_t *right)
void amxp_expr_node_delete(amxp_expr_node_t **node)
void amxp_expr_node_set_function(amxp_expr_node_t *node, char *func_name)
void amxp_expr_node_dump(amxp_expr_t *expr, amxp_expr_node_t *node, uint32_t level, uint32_t parent_id)
amxc_var_t * amxp_expr_node_get_value(amxp_expr_t *expr, amxp_expr_node_t *node)
void amxp_expr_node_set_field(amxp_expr_node_t *node, char *field)
@ amxp_expr_status_invalid_value
@ amxp_expr_status_ok
union _amxp_expr_node::@0 left
amxp_expr_node_t * node
amxc_llist_t args
amxc_llist_it_t it
union _amxp_expr_node::@1 right
amxp_expr_comp_t compare
amxp_expr_node_type_t type
amxc_var_t * value
char * expression
amxc_lstack_t nodes
amxp_expr_status_t status