@cryptotaxi247 / netdata-1 / commits / 54e87bf0c

added inline conditional evaluation, C and javascript like: (condition)?(true expression):(false expression) - made check of nan values work

Costa Tsaousis committed Aug 25, 2016 at 01:38 UTC 54e87bf0c757e855bfe931c09fcd5318db679596
2 files changed +154 -27
src/eval.c
+150 -27
@@ -44,6 +44,7 @@ typedef struct eval_node {
44 #define EVAL_OPERATOR_SIGN_PLUS 'P'
45 #define EVAL_OPERATOR_SIGN_MINUS 'M'
46 #define EVAL_OPERATOR_ABS 'A'
47 +#define EVAL_OPERATOR_IF_THEN_ELSE '?'
48
49 // ----------------------------------------------------------------------------
50 // forward function definitions
@@ -73,29 +74,48 @@ static inline calculated_number eval_check_number(calculated_number n, int *erro
74 }
75
76 static inline calculated_number eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *v, int *error) {
76 - static uint32_t this_hash = 0, now_hash = 0;
77 + static uint32_t this_hash = 0, now_hash = 0, after_hash = 0, before_hash = 0;
78 + calculated_number n;
79
80 if(unlikely(this_hash == 0)) {
81 this_hash = simple_hash("this");
82 now_hash = simple_hash("now");
83 + after_hash = simple_hash("after");
84 + before_hash = simple_hash("before");
85 }
86
83 - if(exp->this && v->hash == this_hash && !strcmp(v->name, "this")) {
87 + if(v->hash == this_hash && !strcmp(v->name, "this")) {
88 + n = (exp->this)?*exp->this:NAN;
89 buffer_strcat(exp->error_msg, "[ $this = ");
85 - print_parsed_as_constant(exp->error_msg, *exp->this);
90 + print_parsed_as_constant(exp->error_msg, n);
91 + buffer_strcat(exp->error_msg, " ] ");
92 + return n;
93 + }
94 +
95 + if(v->hash == after_hash && !strcmp(v->name, "after")) {
96 + n = (exp->after && *exp->after)?*exp->after:NAN;
97 + buffer_strcat(exp->error_msg, "[ $after = ");
98 + print_parsed_as_constant(exp->error_msg, n);
99 buffer_strcat(exp->error_msg, " ] ");
87 - return *exp->this;
100 + return n;
101 + }
102 +
103 + if(v->hash == before_hash && !strcmp(v->name, "before")) {
104 + n = (exp->before && *exp->before)?*exp->before:NAN;
105 + buffer_strcat(exp->error_msg, "[ $before = ");
106 + print_parsed_as_constant(exp->error_msg, n);
107 + buffer_strcat(exp->error_msg, " ] ");
108 + return n;
109 }
110
111 if(v->hash == now_hash && !strcmp(v->name, "now")) {
91 - calculated_number n = time(NULL);
112 + n = time(NULL);
113 buffer_strcat(exp->error_msg, "[ $now = ");
114 print_parsed_as_constant(exp->error_msg, n);
115 buffer_strcat(exp->error_msg, " ] ");
116 return n;
117 }
118
98 - calculated_number n;
119 if(exp->rrdcalc && health_variable_lookup(v->name, v->hash, exp->rrdcalc, &n)) {
120 buffer_sprintf(exp->error_msg, "[ $%s = ", v->name);
121 print_parsed_as_constant(exp->error_msg, n);
@@ -134,57 +154,105 @@ static inline calculated_number eval_value(EVAL_EXPRESSION *exp, EVAL_VALUE *v,
154 return n;
155 }
156
157 +static inline int is_true(calculated_number n) {
158 + if(isnan(n)) return 0;
159 + if(isinf(n)) return 1;
160 + if(n == 0) return 0;
161 + return 1;
162 +}
163 +
164 calculated_number eval_and(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
138 - return eval_value(exp, &op->ops[0], error) && eval_value(exp, &op->ops[1], error);
165 + return is_true(eval_value(exp, &op->ops[0], error)) && is_true(eval_value(exp, &op->ops[1], error));
166 }
167 calculated_number eval_or(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
141 - return eval_value(exp, &op->ops[0], error) || eval_value(exp, &op->ops[1], error);
168 + return is_true(eval_value(exp, &op->ops[0], error)) || is_true(eval_value(exp, &op->ops[1], error));
169 }
170 calculated_number eval_greater_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
144 - return eval_value(exp, &op->ops[0], error) >= eval_value(exp, &op->ops[1], error);
171 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
172 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
173 + return isgreaterequal(n1, n2);
174 }
175 calculated_number eval_less_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
147 - return eval_value(exp, &op->ops[0], error) <= eval_value(exp, &op->ops[1], error);
148 -}
149 -calculated_number eval_not_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
150 - return eval_value(exp, &op->ops[0], error) != eval_value(exp, &op->ops[1], error);
176 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
177 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
178 + return islessequal(n1, n2);
179 }
180 calculated_number eval_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
153 - return eval_value(exp, &op->ops[0], error) == eval_value(exp, &op->ops[1], error);
181 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
182 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
183 + if(isnan(n1) && isnan(n2)) return 1;
184 + if(isinf(n1) && isinf(n2)) return 1;
185 + if(isnan(n1) || isnan(n2)) return 0;
186 + if(isinf(n1) || isinf(n2)) return 0;
187 + return n1 == n2;
188 +}
189 +calculated_number eval_not_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
190 + return !eval_equal(exp, op, error);
191 }
192 calculated_number eval_less(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
156 - return eval_value(exp, &op->ops[0], error) < eval_value(exp, &op->ops[1], error);
193 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
194 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
195 + return isless(n1, n2);
196 }
197 calculated_number eval_greater(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
159 - return eval_value(exp, &op->ops[0], error) > eval_value(exp, &op->ops[1], error);
198 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
199 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
200 + return isgreater(n1, n2);
201 }
202 calculated_number eval_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
162 - return eval_value(exp, &op->ops[0], error) + eval_value(exp, &op->ops[1], error);
203 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
204 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
205 + if(isnan(n1) || isnan(n2)) return NAN;
206 + if(isinf(n1) || isinf(n2)) return INFINITY;
207 + return n1 + n2;
208 }
209 calculated_number eval_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
165 - return eval_value(exp, &op->ops[0], error) - eval_value(exp, &op->ops[1], error);
210 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
211 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
212 + if(isnan(n1) || isnan(n2)) return NAN;
213 + if(isinf(n1) || isinf(n2)) return INFINITY;
214 + return n1 - n2;
215 }
216 calculated_number eval_multiply(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
168 - return eval_value(exp, &op->ops[0], error) * eval_value(exp, &op->ops[1], error);
217 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
218 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
219 + if(isnan(n1) || isnan(n2)) return NAN;
220 + if(isinf(n1) || isinf(n2)) return INFINITY;
221 + return n1 * n2;
222 }
223 calculated_number eval_divide(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
171 - return eval_value(exp, &op->ops[0], error) / eval_value(exp, &op->ops[1], error);
224 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
225 + calculated_number n2 = eval_value(exp, &op->ops[1], error);
226 + if(isnan(n1) || isnan(n2)) return NAN;
227 + if(isinf(n1) || isinf(n2)) return INFINITY;
228 + return n1 / n2;
229 }
230 calculated_number eval_nop(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
231 return eval_value(exp, &op->ops[0], error);
232 }
233 calculated_number eval_not(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
177 - return !eval_value(exp, &op->ops[0], error);
234 + return !is_true(eval_value(exp, &op->ops[0], error));
235 }
236 calculated_number eval_sign_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
237 return eval_value(exp, &op->ops[0], error);
238 }
239 calculated_number eval_sign_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
183 - return -eval_value(exp, &op->ops[0], error);
240 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
241 + if(isnan(n1)) return NAN;
242 + if(isinf(n1)) return INFINITY;
243 + return -n1;
244 }
245 calculated_number eval_abs(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
186 - calculated_number n = eval_value(exp, &op->ops[0], error);
187 - return abs(n);
246 + calculated_number n1 = eval_value(exp, &op->ops[0], error);
247 + if(isnan(n1)) return NAN;
248 + if(isinf(n1)) return INFINITY;
249 + return abs(n1);
250 +}
251 +calculated_number eval_if_then_else(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
252 + if(is_true(eval_value(exp, &op->ops[0], error)))
253 + return eval_value(exp, &op->ops[1], error);
254 + else
255 + return eval_value(exp, &op->ops[2], error);
256 }
257
258 static struct operator {
@@ -197,6 +265,7 @@ static struct operator {
265 // this is a random access array
266 // we always access it with a known EVAL_OPERATOR_X
267
268 + [EVAL_OPERATOR_IF_THEN_ELSE] = { "?", 1, 3, 0, eval_if_then_else },
269 [EVAL_OPERATOR_AND] = { "&&", 2, 2, 0, eval_and },
270 [EVAL_OPERATOR_OR] = { "||", 2, 2, 0, eval_or },
271 [EVAL_OPERATOR_GREATER_THAN_OR_EQUAL] = { ">=", 3, 2, 0, eval_greater_than_or_equal },
@@ -217,7 +286,7 @@ static struct operator {
286 [EVAL_OPERATOR_EXPRESSION_OPEN] = { NULL, 7, 1, 0, eval_nop },
287
288 // this should exist in our evaluation list
220 - [EVAL_OPERATOR_EXPRESSION_CLOSE] = { NULL, 7, 1, 0, eval_nop }
289 + [EVAL_OPERATOR_EXPRESSION_CLOSE] = { NULL, 99, 1, 0, eval_nop }
290 };
291
292 #define eval_precedence(operator) (operators[(unsigned char)(operator)].precedence)
@@ -318,6 +387,18 @@ static inline void print_parsed_as_node(BUFFER *out, EVAL_NODE *op, int *error)
387 print_parsed_as_value(out, &op->ops[1], error);
388 buffer_strcat(out, ")");
389 }
390 + else if(op->operator == EVAL_OPERATOR_IF_THEN_ELSE && operators[op->operator].parameters == 3) {
391 + buffer_strcat(out, "(");
392 + print_parsed_as_value(out, &op->ops[0], error);
393 +
394 + if(operators[op->operator].print_as)
395 + buffer_sprintf(out, " %s ", operators[op->operator].print_as);
396 +
397 + print_parsed_as_value(out, &op->ops[1], error);
398 + buffer_strcat(out, " : ");
399 + print_parsed_as_value(out, &op->ops[2], error);
400 + buffer_strcat(out, ")");
401 + }
402
403 if(operators[op->operator].isfunction)
404 buffer_strcat(out, ")");
@@ -617,6 +698,18 @@ static inline int parse_abs(const char **string) {
698 return 0;
699 }
700
701 +static inline int parse_if_then_else(const char **string) {
702 + const char *s = *string;
703 +
704 + // ?
705 + if(s[0] == '?') {
706 + *string = &s[1];
707 + return 1;
708 + }
709 +
710 + return 0;
711 +}
712 +
713 static struct operator_parser {
714 unsigned char id;
715 int (*parse)(const char **);
@@ -638,6 +731,7 @@ static struct operator_parser {
731 { EVAL_OPERATOR_MINUS, parse_minus },
732 { EVAL_OPERATOR_MULTIPLY, parse_multiply },
733 { EVAL_OPERATOR_DIVIDE, parse_divide },
734 + { EVAL_OPERATOR_IF_THEN_ELSE, parse_if_then_else },
735
736 /* we should not put in this list the following:
737 *
@@ -830,10 +924,36 @@ static inline EVAL_NODE *parse_rest_of_expression(const char **string, int *erro
924 return NULL;
925 }
926
833 - EVAL_NODE *op = eval_node_alloc(2);
927 + EVAL_NODE *op = eval_node_alloc(operators[operator].parameters);
928 op->operator = operator;
929 op->precedence = precedence;
930
931 + if(operator == EVAL_OPERATOR_IF_THEN_ELSE && op->count == 3) {
932 + skip_spaces(string);
933 +
934 + if(**string != ':') {
935 + eval_node_free(op);
936 + eval_node_free(op1);
937 + eval_node_free(op2);
938 + *error = EVAL_ERROR_IF_THEN_ELSE_MISSING_ELSE;
939 + return NULL;
940 + }
941 + (*string)++;
942 +
943 + skip_spaces(string);
944 +
945 + EVAL_NODE *op3 = parse_one_full_operand(string, error);
946 + if(!op3) {
947 + eval_node_free(op);
948 + eval_node_free(op1);
949 + eval_node_free(op2);
950 + // error is already reported
951 + return NULL;
952 + }
953 +
954 + eval_node_set_value_to_node(op, 2, op3);
955 + }
956 +
957 eval_node_set_value_to_node(op, 1, op2);
958
959 // precedence processing
@@ -854,7 +974,7 @@ static inline EVAL_NODE *parse_rest_of_expression(const char **string, int *erro
974 ;
975 }
976 else if(**string) {
857 - if(op1) eval_node_free(op1);
977 + eval_node_free(op1);
978 op1 = NULL;
979 *error = EVAL_ERROR_MISSING_OPERATOR;
980 }
@@ -990,6 +1110,9 @@ const char *expression_strerror(int error) {
1110 case EVAL_ERROR_UNKNOWN_VARIABLE:
1111 return "undefined variable";
1112
1113 + case EVAL_ERROR_IF_THEN_ELSE_MISSING_ELSE:
1114 + return "missing second sub-expression of inline conditional";
1115 +
1116 default:
1117 return "unknown error";
1118 }
src/eval.h
+4
@@ -15,6 +15,9 @@ typedef struct eval_expression {
15 const char *parsed_as;
16
17 calculated_number *this;
18 + time_t *after;
19 + time_t *before;
20 +
21 calculated_number result;
22
23 int error;
@@ -41,6 +44,7 @@ typedef struct eval_expression {
44 #define EVAL_ERROR_MISSING_OPERAND 3
45 #define EVAL_ERROR_MISSING_OPERATOR 4
46 #define EVAL_ERROR_REMAINING_GARBAGE 5
47 +#define EVAL_ERROR_IF_THEN_ELSE_MISSING_ELSE 6
48
49 // evaluation errors
50 #define EVAL_ERROR_INVALID_VALUE 101