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