1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
14 #include <ecoli_malloc.h>
15 #include <ecoli_log.h>
16 #include <ecoli_test.h>
17 #include <ecoli_strvec.h>
18 #include <ecoli_node.h>
19 #include <ecoli_parse.h>
20 #include <ecoli_complete.h>
21 #include <ecoli_node_seq.h>
22 #include <ecoli_node_many.h>
23 #include <ecoli_node_or.h>
24 #include <ecoli_node_expr.h>
26 EC_LOG_TYPE_REGISTER(node_expr);
32 struct ec_node *child;
34 /* the configuration nodes */
35 struct ec_node *val_node;
36 struct ec_node **bin_ops;
37 unsigned int bin_ops_len;
38 struct ec_node **pre_ops;
39 unsigned int pre_ops_len;
40 struct ec_node **post_ops;
41 unsigned int post_ops_len;
42 struct ec_node **open_ops;
43 struct ec_node **close_ops;
44 unsigned int paren_len;
47 static int ec_node_expr_parse(const struct ec_node *gen_node,
48 struct ec_parse *state,
49 const struct ec_strvec *strvec)
51 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
53 if (node->child == NULL) {
58 return ec_node_parse_child(node->child, state, strvec);
62 ec_node_expr_complete(const struct ec_node *gen_node,
64 const struct ec_strvec *strvec)
66 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
68 if (node->child == NULL) {
73 return ec_node_complete_child(node->child, comp, strvec);
76 static void ec_node_expr_free_priv(struct ec_node *gen_node)
78 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
81 ec_node_free(node->child);
82 ec_node_free(node->val_node);
84 for (i = 0; i < node->bin_ops_len; i++)
85 ec_node_free(node->bin_ops[i]);
86 ec_free(node->bin_ops);
87 for (i = 0; i < node->pre_ops_len; i++)
88 ec_node_free(node->pre_ops[i]);
89 ec_free(node->pre_ops);
90 for (i = 0; i < node->post_ops_len; i++)
91 ec_node_free(node->post_ops[i]);
92 ec_free(node->post_ops);
93 for (i = 0; i < node->paren_len; i++) {
94 ec_node_free(node->open_ops[i]);
95 ec_node_free(node->close_ops[i]);
97 ec_free(node->open_ops);
98 ec_free(node->close_ops);
101 static int ec_node_expr_build(struct ec_node_expr *node)
103 struct ec_node *term = NULL, *expr = NULL, *next = NULL,
104 *pre_op = NULL, *post_op = NULL, *ref = NULL,
108 ec_node_free(node->child);
111 if (node->val_node == NULL) {
116 if (node->bin_ops_len == 0 && node->pre_ops_len == 0 &&
117 node->post_ops_len == 0) {
123 * Example of created grammar:
130 * term = post post_op*
131 * prod = term ( "*" term )*
132 * sum = prod ( "+" prod )*
136 /* we use this as a ref, will be set later */
137 ref = ec_node("seq", "ref");
141 /* prefix unary operators */
142 pre_op = ec_node("or", "pre-op");
145 for (i = 0; i < node->pre_ops_len; i++) {
146 if (ec_node_or_add(pre_op, ec_node_clone(node->pre_ops[i])) < 0)
150 /* suffix unary operators */
151 post_op = ec_node("or", "post-op");
154 for (i = 0; i < node->post_ops_len; i++) {
155 if (ec_node_or_add(post_op, ec_node_clone(node->post_ops[i])) < 0)
159 post = ec_node("or", "post");
162 if (ec_node_or_add(post, ec_node_clone(node->val_node)) < 0)
164 if (ec_node_or_add(post,
165 EC_NODE_SEQ(EC_NO_ID,
166 ec_node_clone(pre_op),
167 ec_node_clone(ref))) < 0)
169 for (i = 0; i < node->paren_len; i++) {
170 if (ec_node_or_add(post, EC_NODE_SEQ(EC_NO_ID,
171 ec_node_clone(node->open_ops[i]),
173 ec_node_clone(node->close_ops[i]))) < 0)
176 term = EC_NODE_SEQ("term",
178 ec_node_many(EC_NO_ID, ec_node_clone(post_op), 0, 0)
183 for (i = 0; i < node->bin_ops_len; i++) {
184 next = EC_NODE_SEQ("next",
186 ec_node_many(EC_NO_ID,
187 EC_NODE_SEQ(EC_NO_ID,
188 ec_node_clone(node->bin_ops[i]),
202 /* free the initial references */
203 ec_node_free(pre_op);
205 ec_node_free(post_op);
210 if (ec_node_seq_add(ref, ec_node_clone(expr)) < 0)
222 ec_node_free(pre_op);
223 ec_node_free(post_op);
231 ec_node_expr_get_children_count(const struct ec_node *gen_node)
233 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
240 static struct ec_node *
241 ec_node_expr_get_child(const struct ec_node *gen_node, size_t i)
243 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
251 static struct ec_node_type ec_node_expr_type = {
253 .parse = ec_node_expr_parse,
254 .complete = ec_node_expr_complete,
255 .size = sizeof(struct ec_node_expr),
256 .free_priv = ec_node_expr_free_priv,
257 .get_children_count = ec_node_expr_get_children_count,
258 .get_child = ec_node_expr_get_child,
261 EC_NODE_TYPE_REGISTER(ec_node_expr_type);
263 int ec_node_expr_set_val_node(struct ec_node *gen_node, struct ec_node *val_node)
265 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
267 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
270 if (val_node == NULL) {
275 ec_node_free(node->val_node);
276 node->val_node = val_node;
277 ec_node_expr_build(node);
282 ec_node_free(val_node);
286 /* add a binary operator */
287 int ec_node_expr_add_bin_op(struct ec_node *gen_node, struct ec_node *op)
289 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
290 struct ec_node **bin_ops;
292 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
295 if (node == NULL || op == NULL) {
300 bin_ops = ec_realloc(node->bin_ops,
301 (node->bin_ops_len + 1) * sizeof(*node->bin_ops));
305 node->bin_ops = bin_ops;
306 bin_ops[node->bin_ops_len] = op;
308 ec_node_expr_build(node);
317 /* add a unary pre-operator */
318 int ec_node_expr_add_pre_op(struct ec_node *gen_node, struct ec_node *op)
320 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
321 struct ec_node **pre_ops;
323 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
326 if (node == NULL || op == NULL) {
331 pre_ops = ec_realloc(node->pre_ops,
332 (node->pre_ops_len + 1) * sizeof(*node->pre_ops));
336 node->pre_ops = pre_ops;
337 pre_ops[node->pre_ops_len] = op;
339 ec_node_expr_build(node);
348 /* add a unary post-operator */
349 int ec_node_expr_add_post_op(struct ec_node *gen_node, struct ec_node *op)
351 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
352 struct ec_node **post_ops;
354 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
357 if (node == NULL || op == NULL) {
362 post_ops = ec_realloc(node->post_ops,
363 (node->post_ops_len + 1) * sizeof(*node->post_ops));
364 if (post_ops == NULL)
367 node->post_ops = post_ops;
368 post_ops[node->post_ops_len] = op;
369 node->post_ops_len++;
370 ec_node_expr_build(node);
379 /* add parenthesis symbols */
380 int ec_node_expr_add_parenthesis(struct ec_node *gen_node,
381 struct ec_node *open, struct ec_node *close)
383 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
384 struct ec_node **open_ops, **close_ops;
386 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
389 if (node == NULL || open == NULL || close == NULL) {
394 open_ops = ec_realloc(node->open_ops,
395 (node->paren_len + 1) * sizeof(*node->open_ops));
396 if (open_ops == NULL)
398 close_ops = ec_realloc(node->close_ops,
399 (node->paren_len + 1) * sizeof(*node->close_ops));
400 if (close_ops == NULL)
403 node->open_ops = open_ops;
404 node->close_ops = close_ops;
405 open_ops[node->paren_len] = open;
406 close_ops[node->paren_len] = close;
408 ec_node_expr_build(node);
418 enum expr_node_type {
428 static enum expr_node_type get_node_type(const struct ec_node *expr_gen_node,
429 const struct ec_node *check)
431 struct ec_node_expr *expr_node = (struct ec_node_expr *)expr_gen_node;
434 if (check == expr_node->val_node)
437 for (i = 0; i < expr_node->bin_ops_len; i++) {
438 if (check == expr_node->bin_ops[i])
441 for (i = 0; i < expr_node->pre_ops_len; i++) {
442 if (check == expr_node->pre_ops[i])
445 for (i = 0; i < expr_node->post_ops_len; i++) {
446 if (check == expr_node->post_ops[i])
450 for (i = 0; i < expr_node->paren_len; i++) {
451 if (check == expr_node->open_ops[i])
454 for (i = 0; i < expr_node->paren_len; i++) {
455 if (check == expr_node->close_ops[i])
465 const struct ec_parse *op;
466 enum expr_node_type op_type;
469 /* merge x and y results in x */
470 static int merge_results(void *userctx,
471 const struct ec_node_expr_eval_ops *ops,
472 struct result *x, const struct result *y)
474 if (y->has_val == 0 && y->op == NULL)
476 if (x->has_val == 0 && x->op == NULL) {
481 if (x->has_val && y->has_val && y->op != NULL) {
482 if (y->op_type == BIN_OP) {
483 if (ops->eval_bin_op(&x->val, userctx, x->val,
491 if (x->has_val == 0 && x->op != NULL && y->has_val && y->op == NULL) {
492 if (x->op_type == PRE_OP) {
493 if (ops->eval_pre_op(&x->val, userctx, y->val,
500 } else if (x->op_type == BIN_OP) {
507 if (x->has_val && x->op == NULL && y->has_val == 0 && y->op != NULL) {
508 if (ops->eval_post_op(&x->val, userctx, x->val, y->op) < 0)
514 assert(false); /* we should not get here */
518 static int eval_expression(struct result *result,
520 const struct ec_node_expr_eval_ops *ops,
521 const struct ec_node *expr_gen_node,
522 const struct ec_parse *parse)
525 struct ec_parse *open = NULL, *close = NULL;
526 struct result child_result;
527 struct ec_parse *child;
528 enum expr_node_type type;
530 memset(result, 0, sizeof(*result));
531 memset(&child_result, 0, sizeof(child_result));
533 type = get_node_type(expr_gen_node, ec_parse_get_node(parse));
535 if (ops->eval_var(&result->val, userctx, parse) < 0)
538 } else if (type == PRE_OP || type == POST_OP || type == BIN_OP) {
540 result->op_type = type;
543 EC_PARSE_FOREACH_CHILD(child, parse) {
545 type = get_node_type(expr_gen_node, ec_parse_get_node(child));
546 if (type == PAREN_OPEN) {
549 } else if (type == PAREN_CLOSE) {
554 if (eval_expression(&child_result, userctx, ops,
555 expr_gen_node, child) < 0)
558 if (merge_results(userctx, ops, result, &child_result) < 0)
561 memset(&child_result, 0, sizeof(child_result));
564 if (open != NULL && close != NULL) {
565 if (ops->eval_parenthesis(&result->val, userctx, open, close,
574 ops->eval_free(result->val, userctx);
575 if (child_result.has_val)
576 ops->eval_free(child_result.val, userctx);
577 memset(result, 0, sizeof(*result));
582 int ec_node_expr_eval(void **user_result, const struct ec_node *node,
583 struct ec_parse *parse, const struct ec_node_expr_eval_ops *ops,
586 struct result result;
588 if (ops == NULL || ops->eval_var == NULL || ops->eval_pre_op == NULL ||
589 ops->eval_post_op == NULL || ops->eval_bin_op == NULL ||
590 ops->eval_parenthesis == NULL ||
591 ops->eval_free == NULL) {
596 if (ec_node_check_type(node, &ec_node_expr_type) < 0)
599 if (!ec_parse_matches(parse)) {
604 if (eval_expression(&result, userctx, ops, node, parse) < 0)
607 assert(result.has_val);
608 assert(result.op == NULL);
609 *user_result = result.val;
614 /* the test case is in a separate file ecoli_node_expr_test.c */