master
c 342 lines 11.5 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../libnetdata.h"
4 #include "eval-internal.h"
5
6 // ----------------------------------------------------------------------------
7 // evaluation of expressions
8
9 ALWAYS_INLINE
10 static NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *v, int *error) {
11 NETDATA_DOUBLE n;
12
13 // Check if variable is NULL to avoid crashes
14 if (!v || !v->name) {
15 *error = EVAL_ERROR_UNKNOWN_VARIABLE;
16 buffer_strcat(exp->error_msg, "[ undefined variable ] ");
17 return NAN;
18 }
19
20 if(exp->variable_lookup_cb && exp->variable_lookup_cb(v->name, exp->variable_lookup_cb_data, &n)) {
21 buffer_sprintf(exp->error_msg, "[ ${%s} = ", string2str(v->name));
22 print_parsed_as_constant(exp->error_msg, n);
23 buffer_strcat(exp->error_msg, " ] ");
24 return n;
25 }
26
27 *error = EVAL_ERROR_UNKNOWN_VARIABLE;
28 buffer_sprintf(exp->error_msg, "[ undefined variable '%s' ] ", string2str(v->name));
29 return NAN;
30 }
31
32 ALWAYS_INLINE
33 static NETDATA_DOUBLE eval_value(EVAL_EXPRESSION *exp, EVAL_VALUE *v, int *error) {
34 NETDATA_DOUBLE n;
35
36 switch(v->type) {
37 case EVAL_VALUE_EXPRESSION:
38 n = eval_node(exp, v->expression, error);
39 break;
40
41 case EVAL_VALUE_NUMBER:
42 n = v->number;
43 break;
44
45 case EVAL_VALUE_VARIABLE:
46 n = eval_variable(exp, v->variable, error);
47 break;
48
49 default:
50 *error = EVAL_ERROR_INVALID_VALUE;
51 n = 0;
52 break;
53 }
54
55 return n;
56 }
57
58 ALWAYS_INLINE
59 static int is_true(NETDATA_DOUBLE n) {
60 // Handle special cases safely
61 if(isnan(n)) return 0; // NaN is considered false
62 if(isinf(n)) {
63 // Infinity is considered true (positive or negative)
64 return 1;
65 }
66 if(n == 0) return 0; // Zero is considered false
67 return 1; // Any other value is true
68 }
69
70 ALWAYS_INLINE
71 static NETDATA_DOUBLE eval_and(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
72 return is_true(eval_value(exp, &op->ops[0], error)) && is_true(eval_value(exp, &op->ops[1], error));
73 }
74
75 ALWAYS_INLINE
76 static NETDATA_DOUBLE eval_or(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
77 return is_true(eval_value(exp, &op->ops[0], error)) || is_true(eval_value(exp, &op->ops[1], error));
78 }
79
80 ALWAYS_INLINE
81 static NETDATA_DOUBLE eval_greater_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
82 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
83 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
84 return isgreaterequal(n1, n2);
85 }
86
87 ALWAYS_INLINE
88 static NETDATA_DOUBLE eval_less_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
89 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
90 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
91 return islessequal(n1, n2);
92 }
93
94 ALWAYS_INLINE
95 static NETDATA_DOUBLE eval_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
96 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
97 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
98 if(isnan(n1) && isnan(n2)) return 1;
99 if(isinf(n1) && isinf(n2)) return 1;
100 if(isnan(n1) || isnan(n2)) return 0;
101 if(isinf(n1) || isinf(n2)) return 0;
102 return considered_equal_ndd(n1, n2);
103 }
104
105 ALWAYS_INLINE
106 static NETDATA_DOUBLE eval_not_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
107 return !eval_equal(exp, op, error);
108 }
109
110 ALWAYS_INLINE
111 static NETDATA_DOUBLE eval_less(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
112 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
113 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
114 return isless(n1, n2);
115 }
116
117 ALWAYS_INLINE
118 static NETDATA_DOUBLE eval_greater(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
119 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
120 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
121 return isgreater(n1, n2);
122 }
123
124 ALWAYS_INLINE
125 static NETDATA_DOUBLE eval_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
126 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
127 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
128 if(isnan(n1) || isnan(n2)) return NAN;
129 if(isinf(n1) || isinf(n2)) return INFINITY;
130 return n1 + n2;
131 }
132
133 ALWAYS_INLINE
134 static NETDATA_DOUBLE eval_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
135 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
136 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
137 if(isnan(n1) || isnan(n2)) return NAN;
138 if(isinf(n1) || isinf(n2)) return INFINITY;
139 return n1 - n2;
140 }
141
142 ALWAYS_INLINE
143 static NETDATA_DOUBLE eval_multiply(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
144 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
145 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
146 if(isnan(n1) || isnan(n2)) return NAN;
147 if(isinf(n1) || isinf(n2)) return INFINITY;
148 return n1 * n2;
149 }
150
151 ALWAYS_INLINE
152 static NETDATA_DOUBLE eval_divide(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
153 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
154 if(*error != EVAL_ERROR_OK) return NAN; // Propagate previous errors
155
156 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
157 if(*error != EVAL_ERROR_OK) return NAN; // Propagate previous errors
158
159 if(isnan(n1) || isnan(n2)) {
160 *error = EVAL_ERROR_VALUE_IS_NAN;
161 return NAN;
162 }
163
164 if(isinf(n1) || isinf(n2)) {
165 *error = EVAL_ERROR_VALUE_IS_INFINITE;
166 return INFINITY;
167 }
168
169 if(n2 == 0) {
170 // In Netdata, we treat all division by zero as INFINITE error
171 // This ensures compatibility with existing code
172 *error = EVAL_ERROR_VALUE_IS_INFINITE;
173 return n1 >= 0 ? INFINITY : -INFINITY;
174 }
175
176 return n1 / n2;
177 }
178
179 ALWAYS_INLINE
180 static NETDATA_DOUBLE eval_modulo(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
181 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
182 if(*error != EVAL_ERROR_OK) return NAN;
183
184 NETDATA_DOUBLE n2 = eval_value(exp, &op->ops[1], error);
185 if(*error != EVAL_ERROR_OK) return NAN;
186
187 if(isnan(n1) || isnan(n2)) {
188 *error = EVAL_ERROR_VALUE_IS_NAN;
189 return NAN;
190 }
191
192 if(isinf(n1) || isinf(n2)) {
193 *error = EVAL_ERROR_VALUE_IS_INFINITE;
194 return INFINITY;
195 }
196
197 if(n2 == 0) {
198 *error = EVAL_ERROR_VALUE_IS_INFINITE;
199 return NAN; // Modulo by zero is undefined
200 }
201
202 return fmod(n1, n2);
203 }
204
205 ALWAYS_INLINE
206 static NETDATA_DOUBLE eval_nop(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
207 return eval_value(exp, &op->ops[0], error);
208 }
209
210 ALWAYS_INLINE
211 static NETDATA_DOUBLE eval_not(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
212 return !is_true(eval_value(exp, &op->ops[0], error));
213 }
214
215 ALWAYS_INLINE
216 static NETDATA_DOUBLE eval_sign_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
217 return eval_value(exp, &op->ops[0], error);
218 }
219
220 ALWAYS_INLINE
221 static NETDATA_DOUBLE eval_sign_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
222 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
223 if(isnan(n1)) return NAN;
224 if(isinf(n1)) return INFINITY;
225 return -n1;
226 }
227
228 ALWAYS_INLINE
229 static NETDATA_DOUBLE eval_abs(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
230 NETDATA_DOUBLE n1 = eval_value(exp, &op->ops[0], error);
231 if(isnan(n1)) return NAN;
232 if(isinf(n1)) return INFINITY;
233 return ABS(n1);
234 }
235
236 ALWAYS_INLINE
237 static NETDATA_DOUBLE eval_if_then_else(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
238 if(is_true(eval_value(exp, &op->ops[0], error)))
239 return eval_value(exp, &op->ops[1], error);
240 else
241 return eval_value(exp, &op->ops[2], error);
242 }
243
244 // Define operators table - use the struct definition from eval-internal.h
245 struct operator operators[256] = {
246 // this is a random access array
247 // we always access it with a known EVAL_OPERATOR_X
248
249 [EVAL_OPERATOR_AND] = { "&&", 2, 2, 0, eval_and },
250 [EVAL_OPERATOR_OR] = { "||", 2, 2, 0, eval_or },
251 [EVAL_OPERATOR_GREATER_THAN_OR_EQUAL] = { ">=", 3, 2, 0, eval_greater_than_or_equal },
252 [EVAL_OPERATOR_LESS_THAN_OR_EQUAL] = { "<=", 3, 2, 0, eval_less_than_or_equal },
253 [EVAL_OPERATOR_NOT_EQUAL] = { "!=", 3, 2, 0, eval_not_equal },
254 [EVAL_OPERATOR_EQUAL] = { "==", 3, 2, 0, eval_equal },
255 [EVAL_OPERATOR_LESS] = { "<", 3, 2, 0, eval_less },
256 [EVAL_OPERATOR_GREATER] = { ">", 3, 2, 0, eval_greater },
257 [EVAL_OPERATOR_PLUS] = { "+", 4, 2, 0, eval_plus },
258 [EVAL_OPERATOR_MINUS] = { "-", 4, 2, 0, eval_minus },
259 [EVAL_OPERATOR_MULTIPLY] = { "*", 5, 2, 0, eval_multiply },
260 [EVAL_OPERATOR_DIVIDE] = { "/", 5, 2, 0, eval_divide },
261 [EVAL_OPERATOR_MODULO] = { "%", 5, 2, 0, eval_modulo },
262 [EVAL_OPERATOR_NOT] = { "!", 6, 1, 0, eval_not },
263 [EVAL_OPERATOR_SIGN_PLUS] = { "+", 6, 1, 0, eval_sign_plus },
264 [EVAL_OPERATOR_SIGN_MINUS] = { "-", 6, 1, 0, eval_sign_minus },
265 [EVAL_OPERATOR_ABS] = { "abs(",6,1, 1, eval_abs },
266 [EVAL_OPERATOR_IF_THEN_ELSE] = { "?", 7, 3, 0, eval_if_then_else },
267 [EVAL_OPERATOR_NOP] = { NULL, 8, 1, 0, eval_nop },
268 [EVAL_OPERATOR_EXPRESSION_OPEN] = { NULL, 8, 1, 0, eval_nop },
269
270 // this should exist in our evaluation list
271 [EVAL_OPERATOR_EXPRESSION_CLOSE] = { NULL, 99, 1, 0, eval_nop }
272 };
273
274 // Helper function to get precedence
275 ALWAYS_INLINE
276 int eval_precedence(unsigned char operator) {
277 return operators[(unsigned char)(operator)].precedence;
278 }
279
280 ALWAYS_INLINE
281 NETDATA_DOUBLE eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
282 if(unlikely(!op)) {
283 *error = EVAL_ERROR_MISSING_OPERAND;
284 return 0;
285 }
286
287 if(unlikely(op->count != operators[op->operator].parameters)) {
288 *error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS;
289 return 0;
290 }
291
292 NETDATA_DOUBLE n = operators[op->operator].eval(exp, op, error);
293
294 return n;
295 }
296
297 // ----------------------------------------------------------------------------
298 // public API for evaluation
299
300 ALWAYS_INLINE
301 int expression_evaluate(EVAL_EXPRESSION *expression) {
302 expression->error = EVAL_ERROR_OK;
303
304 buffer_reset(expression->error_msg);
305 expression->result = eval_node(expression, expression->nodes, &expression->error);
306
307 if(unlikely(isnan(expression->result))) {
308 if(expression->error == EVAL_ERROR_OK)
309 expression->error = EVAL_ERROR_VALUE_IS_NAN;
310 }
311 else if(unlikely(isinf(expression->result))) {
312 if(expression->error == EVAL_ERROR_OK)
313 expression->error = EVAL_ERROR_VALUE_IS_INFINITE;
314 }
315 else if(unlikely(expression->error == EVAL_ERROR_UNKNOWN_VARIABLE)) {
316 // although there is an unknown variable
317 // the expression was evaluated successfully
318 expression->error = EVAL_ERROR_OK;
319 }
320
321 if(expression->error != EVAL_ERROR_OK) {
322 expression->result = NAN;
323
324 if(buffer_strlen(expression->error_msg))
325 buffer_strcat(expression->error_msg, "; ");
326
327 buffer_sprintf(expression->error_msg, "failed to evaluate expression with error %d (%s)", expression->error, expression_strerror(expression->error));
328 return 0;
329 }
330
331 return 1;
332 }
333
334 void expression_free(EVAL_EXPRESSION *expression) {
335 if(!expression) return;
336
337 if(expression->nodes) eval_node_free(expression->nodes);
338 string_freez((void *)expression->source);
339 string_freez((void *)expression->parsed_as);
340 buffer_free(expression->error_msg);
341 freez(expression);
342 }