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);
30 struct ec_node *child;
32 /* the configuration nodes */
33 struct ec_node *val_node;
34 struct ec_node **bin_ops;
35 unsigned int bin_ops_len;
36 struct ec_node **pre_ops;
37 unsigned int pre_ops_len;
38 struct ec_node **post_ops;
39 unsigned int post_ops_len;
40 struct ec_node **open_ops;
41 struct ec_node **close_ops;
42 unsigned int paren_len;
45 static int ec_node_expr_parse(const struct ec_node *node,
46 struct ec_pnode *state,
47 const struct ec_strvec *strvec)
49 struct ec_node_expr *priv = ec_node_priv(node);
51 if (priv->child == NULL) {
56 return ec_parse_child(priv->child, state, strvec);
60 ec_node_expr_complete(const struct ec_node *node,
62 const struct ec_strvec *strvec)
64 struct ec_node_expr *priv = ec_node_priv(node);
66 if (priv->child == NULL) {
71 return ec_complete_child(priv->child, comp, strvec);
74 static void ec_node_expr_free_priv(struct ec_node *node)
76 struct ec_node_expr *priv = ec_node_priv(node);
79 ec_node_free(priv->child);
80 ec_node_free(priv->val_node);
82 for (i = 0; i < priv->bin_ops_len; i++)
83 ec_node_free(priv->bin_ops[i]);
84 ec_free(priv->bin_ops);
85 for (i = 0; i < priv->pre_ops_len; i++)
86 ec_node_free(priv->pre_ops[i]);
87 ec_free(priv->pre_ops);
88 for (i = 0; i < priv->post_ops_len; i++)
89 ec_node_free(priv->post_ops[i]);
90 ec_free(priv->post_ops);
91 for (i = 0; i < priv->paren_len; i++) {
92 ec_node_free(priv->open_ops[i]);
93 ec_node_free(priv->close_ops[i]);
95 ec_free(priv->open_ops);
96 ec_free(priv->close_ops);
99 static int ec_node_expr_build(struct ec_node_expr *priv)
101 struct ec_node *term = NULL, *expr = NULL, *next = NULL,
102 *pre_op = NULL, *post_op = NULL, *ref = NULL,
106 ec_node_free(priv->child);
109 if (priv->val_node == NULL) {
114 if (priv->bin_ops_len == 0 && priv->pre_ops_len == 0 &&
115 priv->post_ops_len == 0) {
121 * Example of created grammar:
128 * term = post post_op*
129 * prod = term ( "*" term )*
130 * sum = prod ( "+" prod )*
134 /* we use this as a ref, will be set later */
135 ref = ec_node("seq", "ref");
139 /* prefix unary operators */
140 pre_op = ec_node("or", "pre-op");
143 for (i = 0; i < priv->pre_ops_len; i++) {
144 if (ec_node_or_add(pre_op, ec_node_clone(priv->pre_ops[i])) < 0)
148 /* suffix unary operators */
149 post_op = ec_node("or", "post-op");
152 for (i = 0; i < priv->post_ops_len; i++) {
153 if (ec_node_or_add(post_op, ec_node_clone(priv->post_ops[i])) < 0)
157 post = ec_node("or", "post");
160 if (ec_node_or_add(post, ec_node_clone(priv->val_node)) < 0)
162 if (ec_node_or_add(post,
163 EC_NODE_SEQ(EC_NO_ID,
164 ec_node_clone(pre_op),
165 ec_node_clone(ref))) < 0)
167 for (i = 0; i < priv->paren_len; i++) {
168 if (ec_node_or_add(post, EC_NODE_SEQ(EC_NO_ID,
169 ec_node_clone(priv->open_ops[i]),
171 ec_node_clone(priv->close_ops[i]))) < 0)
174 term = EC_NODE_SEQ("term",
176 ec_node_many(EC_NO_ID, ec_node_clone(post_op), 0, 0)
181 for (i = 0; i < priv->bin_ops_len; i++) {
182 next = EC_NODE_SEQ("next",
184 ec_node_many(EC_NO_ID,
185 EC_NODE_SEQ(EC_NO_ID,
186 ec_node_clone(priv->bin_ops[i]),
200 /* free the initial references */
201 ec_node_free(pre_op);
203 ec_node_free(post_op);
208 if (ec_node_seq_add(ref, ec_node_clone(expr)) < 0)
220 ec_node_free(pre_op);
221 ec_node_free(post_op);
229 ec_node_expr_get_children_count(const struct ec_node *node)
231 struct ec_node_expr *priv = ec_node_priv(node);
239 ec_node_expr_get_child(const struct ec_node *node, size_t i,
240 struct ec_node **child, unsigned int *refs)
242 struct ec_node_expr *priv = ec_node_priv(node);
247 *child = priv->child;
252 static struct ec_node_type ec_node_expr_type = {
254 .parse = ec_node_expr_parse,
255 .complete = ec_node_expr_complete,
256 .size = sizeof(struct ec_node_expr),
257 .free_priv = ec_node_expr_free_priv,
258 .get_children_count = ec_node_expr_get_children_count,
259 .get_child = ec_node_expr_get_child,
262 EC_NODE_TYPE_REGISTER(ec_node_expr_type);
264 int ec_node_expr_set_val_node(struct ec_node *node, struct ec_node *val_node)
266 struct ec_node_expr *priv = ec_node_priv(node);
268 if (ec_node_check_type(node, &ec_node_expr_type) < 0)
271 if (val_node == NULL) {
276 ec_node_free(priv->val_node);
277 priv->val_node = val_node;
278 ec_node_expr_build(priv);
283 ec_node_free(val_node);
287 /* add a binary operator */
288 int ec_node_expr_add_bin_op(struct ec_node *node, struct ec_node *op)
290 struct ec_node_expr *priv = ec_node_priv(node);
291 struct ec_node **bin_ops;
293 if (ec_node_check_type(node, &ec_node_expr_type) < 0)
296 if (node == NULL || op == NULL) {
301 bin_ops = ec_realloc(priv->bin_ops,
302 (priv->bin_ops_len + 1) * sizeof(*priv->bin_ops));
306 priv->bin_ops = bin_ops;
307 bin_ops[priv->bin_ops_len] = op;
309 ec_node_expr_build(priv);
318 /* add a unary pre-operator */
319 int ec_node_expr_add_pre_op(struct ec_node *node, struct ec_node *op)
321 struct ec_node_expr *priv = ec_node_priv(node);
322 struct ec_node **pre_ops;
324 if (ec_node_check_type(node, &ec_node_expr_type) < 0)
327 if (node == NULL || op == NULL) {
332 pre_ops = ec_realloc(priv->pre_ops,
333 (priv->pre_ops_len + 1) * sizeof(*priv->pre_ops));
337 priv->pre_ops = pre_ops;
338 pre_ops[priv->pre_ops_len] = op;
340 ec_node_expr_build(priv);
349 /* add a unary post-operator */
350 int ec_node_expr_add_post_op(struct ec_node *node, struct ec_node *op)
352 struct ec_node_expr *priv = ec_node_priv(node);
353 struct ec_node **post_ops;
355 if (ec_node_check_type(node, &ec_node_expr_type) < 0)
358 if (node == NULL || op == NULL) {
363 post_ops = ec_realloc(priv->post_ops,
364 (priv->post_ops_len + 1) * sizeof(*priv->post_ops));
365 if (post_ops == NULL)
368 priv->post_ops = post_ops;
369 post_ops[priv->post_ops_len] = op;
370 priv->post_ops_len++;
371 ec_node_expr_build(priv);
380 /* add parenthesis symbols */
381 int ec_node_expr_add_parenthesis(struct ec_node *node,
382 struct ec_node *open, struct ec_node *close)
384 struct ec_node_expr *priv = ec_node_priv(node);
385 struct ec_node **open_ops, **close_ops;
387 if (ec_node_check_type(node, &ec_node_expr_type) < 0)
390 if (node == NULL || open == NULL || close == NULL) {
395 open_ops = ec_realloc(priv->open_ops,
396 (priv->paren_len + 1) * sizeof(*priv->open_ops));
397 if (open_ops == NULL)
399 close_ops = ec_realloc(priv->close_ops,
400 (priv->paren_len + 1) * sizeof(*priv->close_ops));
401 if (close_ops == NULL)
404 priv->open_ops = open_ops;
405 priv->close_ops = close_ops;
406 open_ops[priv->paren_len] = open;
407 close_ops[priv->paren_len] = close;
409 ec_node_expr_build(priv);
419 enum expr_node_type {
429 static enum expr_node_type get_node_type(const struct ec_node *expr_node,
430 const struct ec_node *check)
432 struct ec_node_expr *expr_priv = ec_node_priv(expr_node);
435 if (check == expr_priv->val_node)
438 for (i = 0; i < expr_priv->bin_ops_len; i++) {
439 if (check == expr_priv->bin_ops[i])
442 for (i = 0; i < expr_priv->pre_ops_len; i++) {
443 if (check == expr_priv->pre_ops[i])
446 for (i = 0; i < expr_priv->post_ops_len; i++) {
447 if (check == expr_priv->post_ops[i])
451 for (i = 0; i < expr_priv->paren_len; i++) {
452 if (check == expr_priv->open_ops[i])
455 for (i = 0; i < expr_priv->paren_len; i++) {
456 if (check == expr_priv->close_ops[i])
466 const struct ec_pnode *op;
467 enum expr_node_type op_type;
470 /* merge x and y results in x */
471 static int merge_results(void *userctx,
472 const struct ec_node_expr_eval_ops *ops,
473 struct result *x, const struct result *y)
475 if (y->has_val == 0 && y->op == NULL)
477 if (x->has_val == 0 && x->op == NULL) {
482 if (x->has_val && y->has_val && y->op != NULL) {
483 if (y->op_type == BIN_OP) {
484 if (ops->eval_bin_op(&x->val, userctx, x->val,
492 if (x->has_val == 0 && x->op != NULL && y->has_val && y->op == NULL) {
493 if (x->op_type == PRE_OP) {
494 if (ops->eval_pre_op(&x->val, userctx, y->val,
501 } else if (x->op_type == BIN_OP) {
508 if (x->has_val && x->op == NULL && y->has_val == 0 && y->op != NULL) {
509 if (ops->eval_post_op(&x->val, userctx, x->val, y->op) < 0)
515 assert(false); /* we should not get here */
519 static int eval_expression(struct result *result,
521 const struct ec_node_expr_eval_ops *ops,
522 const struct ec_node *expr_node,
523 const struct ec_pnode *parse)
526 struct ec_pnode *open = NULL, *close = NULL;
527 struct result child_result;
528 struct ec_pnode *child;
529 enum expr_node_type type;
531 memset(result, 0, sizeof(*result));
532 memset(&child_result, 0, sizeof(child_result));
534 type = get_node_type(expr_node, ec_pnode_get_node(parse));
536 if (ops->eval_var(&result->val, userctx, parse) < 0)
539 } else if (type == PRE_OP || type == POST_OP || type == BIN_OP) {
541 result->op_type = type;
544 EC_PNODE_FOREACH_CHILD(child, parse) {
546 type = get_node_type(expr_node, ec_pnode_get_node(child));
547 if (type == PAREN_OPEN) {
550 } else if (type == PAREN_CLOSE) {
555 if (eval_expression(&child_result, userctx, ops,
556 expr_node, child) < 0)
559 if (merge_results(userctx, ops, result, &child_result) < 0)
562 memset(&child_result, 0, sizeof(child_result));
565 if (open != NULL && close != NULL) {
566 if (ops->eval_parenthesis(&result->val, userctx, open, close,
575 ops->eval_free(result->val, userctx);
576 if (child_result.has_val)
577 ops->eval_free(child_result.val, userctx);
578 memset(result, 0, sizeof(*result));
583 int ec_node_expr_eval(void **user_result, const struct ec_node *node,
584 struct ec_pnode *parse, const struct ec_node_expr_eval_ops *ops,
587 struct result result;
589 if (ops == NULL || ops->eval_var == NULL || ops->eval_pre_op == NULL ||
590 ops->eval_post_op == NULL || ops->eval_bin_op == NULL ||
591 ops->eval_parenthesis == NULL ||
592 ops->eval_free == NULL) {
597 if (ec_node_check_type(node, &ec_node_expr_type) < 0)
600 if (!ec_pnode_matches(parse)) {
605 if (eval_expression(&result, userctx, ops, node, parse) < 0)
608 assert(result.has_val);
609 assert(result.op == NULL);
610 *user_result = result.val;
615 /* the test case is in a separate file ecoli_node_expr_test.c */