2 * Copyright (c) 2016-2017, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <ecoli_malloc.h>
38 #include <ecoli_log.h>
39 #include <ecoli_test.h>
40 #include <ecoli_strvec.h>
42 #include <ecoli_tk_seq.h>
43 #include <ecoli_tk_many.h>
44 #include <ecoli_tk_or.h>
45 #include <ecoli_tk_weakref.h>
46 #include <ecoli_tk_expr.h>
54 /* the configuration nodes */
56 struct ec_tk **bin_ops;
57 unsigned int bin_ops_len;
58 struct ec_tk **pre_ops;
59 unsigned int pre_ops_len;
60 struct ec_tk **post_ops;
61 unsigned int post_ops_len;
62 struct ec_tk **open_ops;
63 struct ec_tk **close_ops;
64 unsigned int paren_len;
67 static struct ec_parsed_tk *ec_tk_expr_parse(const struct ec_tk *gen_tk,
68 const struct ec_strvec *strvec)
70 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
72 return ec_tk_parse_tokens(tk->child, strvec);
75 static struct ec_completed_tk *ec_tk_expr_complete(const struct ec_tk *gen_tk,
76 const struct ec_strvec *strvec)
78 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
80 return ec_tk_complete_tokens(tk->child, strvec);
83 static void ec_tk_expr_free_priv(struct ec_tk *gen_tk)
85 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
88 ec_log(EC_LOG_DEBUG, "free %p %p %p\n", tk, tk->child, tk->val_tk);
89 ec_tk_free(tk->val_tk);
91 for (i = 0; i < tk->bin_ops_len; i++)
92 ec_tk_free(tk->bin_ops[i]);
94 for (i = 0; i < tk->pre_ops_len; i++)
95 ec_tk_free(tk->pre_ops[i]);
97 for (i = 0; i < tk->post_ops_len; i++)
98 ec_tk_free(tk->post_ops[i]);
99 ec_free(tk->post_ops);
100 for (i = 0; i < tk->paren_len; i++) {
101 ec_tk_free(tk->open_ops[i]);
102 ec_tk_free(tk->close_ops[i]);
104 ec_free(tk->open_ops);
105 ec_free(tk->close_ops);
107 ec_tk_free(tk->child);
110 static int ec_tk_expr_build(struct ec_tk *gen_tk)
112 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
113 struct ec_tk *term = NULL, *expr = NULL, *next = NULL,
114 *pre_op = NULL, *post_op = NULL,
115 *post = NULL, *weak = NULL;
119 if (tk->val_tk == NULL)
121 if (tk->bin_ops_len == 0 && tk->pre_ops_len == 0 &&
122 tk->post_ops_len == 0)
125 /* create the object, we will initialize it later: this is
126 * needed because we have a circular dependency */
128 weak = ec_tk_weakref_empty("weak");
132 /* prefix unary operators */
133 pre_op = ec_tk_or("pre-op");
136 for (i = 0; i < tk->pre_ops_len; i++) {
137 if (ec_tk_or_add(pre_op, ec_tk_clone(tk->pre_ops[i])) < 0)
141 /* suffix unary operators */
142 post_op = ec_tk_or("post-op");
145 for (i = 0; i < tk->post_ops_len; i++) {
146 if (ec_tk_or_add(post_op, ec_tk_clone(tk->post_ops[i])) < 0)
150 post = ec_tk_or("post");
153 if (ec_tk_or_add(post, ec_tk_clone(tk->val_tk)) < 0)
155 if (ec_tk_or_add(post,
158 ec_tk_clone(weak))) < 0)
160 for (i = 0; i < tk->paren_len; i++) {
161 if (ec_tk_or_add(post, EC_TK_SEQ(NULL,
162 ec_tk_clone(tk->open_ops[i]),
164 ec_tk_clone(tk->close_ops[i]))) < 0)
167 term = EC_TK_SEQ("term",
169 ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0)
174 for (i = 0; i < tk->bin_ops_len; i++) {
175 next = EC_TK_SEQ("next",
179 ec_tk_clone(tk->bin_ops[i]),
193 /* free the initial references */
201 /* no need to clone here, the node is not consumed */
202 if (ec_tk_weakref_set(weak, expr) < 0)
222 static struct ec_tk_type ec_tk_expr_type = {
224 .build = ec_tk_expr_build,
225 .parse = ec_tk_expr_parse,
226 .complete = ec_tk_expr_complete,
227 .free_priv = ec_tk_expr_free_priv,
230 EC_TK_TYPE_REGISTER(ec_tk_expr_type);
232 struct ec_tk *ec_tk_expr(const char *id)
234 struct ec_tk_expr *tk = NULL;
235 struct ec_tk *gen_tk = NULL;
237 gen_tk = ec_tk_new(id, &ec_tk_expr_type, sizeof(*tk));
240 tk = (struct ec_tk_expr *)gen_tk;
245 int ec_tk_expr_set_val_tk(struct ec_tk *gen_tk, struct ec_tk *val_tk)
247 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
254 if (gen_tk->flags & EC_TK_F_BUILT)
257 if (tk->val_tk != NULL)
261 gen_tk->flags &= ~EC_TK_F_BUILT;
270 /* add a binary operator */
271 int ec_tk_expr_add_bin_op(struct ec_tk *gen_tk, struct ec_tk *op)
273 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
274 struct ec_tk **bin_ops;
280 if (tk == NULL || op == NULL)
283 if (gen_tk->flags & EC_TK_F_BUILT)
287 bin_ops = ec_realloc(tk->bin_ops,
288 (tk->bin_ops_len + 1) * sizeof(*tk->bin_ops));
292 tk->bin_ops = bin_ops;
293 bin_ops[tk->bin_ops_len] = op;
295 gen_tk->flags &= ~EC_TK_F_BUILT;
304 /* add a unary pre-operator */
305 int ec_tk_expr_add_pre_op(struct ec_tk *gen_tk, struct ec_tk *op)
307 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
308 struct ec_tk **pre_ops;
314 if (tk == NULL || op == NULL)
317 if (gen_tk->flags & EC_TK_F_BUILT)
321 pre_ops = ec_realloc(tk->pre_ops,
322 (tk->pre_ops_len + 1) * sizeof(*tk->pre_ops));
326 tk->pre_ops = pre_ops;
327 pre_ops[tk->pre_ops_len] = op;
329 gen_tk->flags &= ~EC_TK_F_BUILT;
338 /* add a unary post-operator */
339 int ec_tk_expr_add_post_op(struct ec_tk *gen_tk, struct ec_tk *op)
341 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
342 struct ec_tk **post_ops;
348 if (tk == NULL || op == NULL)
351 if (gen_tk->flags & EC_TK_F_BUILT)
355 post_ops = ec_realloc(tk->post_ops,
356 (tk->post_ops_len + 1) * sizeof(*tk->post_ops));
357 if (post_ops == NULL)
360 tk->post_ops = post_ops;
361 post_ops[tk->post_ops_len] = op;
363 gen_tk->flags &= ~EC_TK_F_BUILT;
372 /* add parenthesis symbols */
373 int ec_tk_expr_add_parenthesis(struct ec_tk *gen_tk,
374 struct ec_tk *open, struct ec_tk *close)
376 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
377 struct ec_tk **open_ops, **close_ops;
383 if (tk == NULL || open == NULL || close == NULL)
386 if (gen_tk->flags & EC_TK_F_BUILT)
390 open_ops = ec_realloc(tk->open_ops,
391 (tk->paren_len + 1) * sizeof(*tk->open_ops));
392 if (open_ops == NULL)
394 close_ops = ec_realloc(tk->close_ops,
395 (tk->paren_len + 1) * sizeof(*tk->close_ops));
396 if (close_ops == NULL)
399 tk->open_ops = open_ops;
400 tk->close_ops = close_ops;
401 open_ops[tk->paren_len] = open;
402 close_ops[tk->paren_len] = close;
404 gen_tk->flags &= ~EC_TK_F_BUILT;
423 static enum expr_tk_type get_tk_type(const struct ec_tk *expr_gen_tk,
424 const struct ec_tk *check_tk)
426 struct ec_tk_expr *expr_tk = (struct ec_tk_expr *)expr_gen_tk;
429 if (check_tk == expr_tk->val_tk)
432 for (i = 0; i < expr_tk->bin_ops_len; i++) {
433 if (check_tk == expr_tk->bin_ops[i])
436 for (i = 0; i < expr_tk->pre_ops_len; i++) {
437 if (check_tk == expr_tk->pre_ops[i])
440 for (i = 0; i < expr_tk->post_ops_len; i++) {
441 if (check_tk == expr_tk->post_ops[i])
445 for (i = 0; i < expr_tk->paren_len; i++) {
446 if (check_tk == expr_tk->open_ops[i])
449 for (i = 0; i < expr_tk->paren_len; i++) {
450 if (check_tk == expr_tk->close_ops[i])
460 const struct ec_parsed_tk *op;
461 enum expr_tk_type op_type;
464 /* merge x and y results in x */
465 static int merge_results(void *userctx,
466 const struct ec_tk_expr_eval_ops *ops,
467 struct result *x, const struct result *y)
471 if (y->has_val == 0 && y->op == NULL)
473 if (x->has_val == 0 && x->op == NULL) {
478 if (x->has_val && x->op == NULL && y->has_val && y->op != NULL) {
479 ret = ops->eval_bin_op(&x->val, userctx, x->val, y->op, y->val);
486 if (x->has_val == 0 && x->op != NULL && y->has_val && y->op == NULL) {
487 if (x->op_type == PRE_OP) {
488 ret = ops->eval_pre_op(&x->val, userctx, y->val, x->op);
495 } else if (x->op_type == BIN_OP) {
502 if (x->has_val && x->op == NULL && y->has_val == 0 && y->op != NULL) {
503 ret = ops->eval_post_op(&x->val, userctx, x->val, y->op);
510 assert(true); /* we should not get here */
514 static int eval_expression(struct result *result,
516 const struct ec_tk_expr_eval_ops *ops,
517 const struct ec_tk *expr_gen_tk,
518 const struct ec_parsed_tk *parsed_tk)
521 struct ec_parsed_tk *open = NULL, *close = NULL;
522 struct result child_result;
523 struct ec_parsed_tk *child;
524 enum expr_tk_type type;
527 memset(result, 0, sizeof(*result));
528 memset(&child_result, 0, sizeof(child_result));
530 type = get_tk_type(expr_gen_tk, parsed_tk->tk);
532 ret = ops->eval_var(&result->val, userctx, parsed_tk);
536 } else if (type == PRE_OP || type == POST_OP || type == BIN_OP) {
537 result->op = parsed_tk;
538 result->op_type = type;
541 TAILQ_FOREACH(child, &parsed_tk->children, next) {
543 type = get_tk_type(expr_gen_tk, child->tk);
544 if (type == PAREN_OPEN) {
547 } else if (type == PAREN_CLOSE) {
552 ret = eval_expression(&child_result, userctx, ops,
557 ret = merge_results(userctx, ops, result, &child_result);
561 memset(&child_result, 0, sizeof(child_result));
564 if (open != NULL && close != NULL) {
565 ret = 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_tk_expr_eval(void **user_result, const struct ec_tk *tk,
584 struct ec_parsed_tk *parsed, const struct ec_tk_expr_eval_ops *ops,
587 struct result result;
590 if (ops == NULL || ops->eval_var == NULL || ops->eval_pre_op == NULL ||
591 ops->eval_post_op == NULL || ops->eval_bin_op == NULL ||
592 ops->eval_parenthesis == NULL || ops->eval_free == NULL)
595 if (!ec_parsed_tk_matches(parsed))
598 ec_parsed_tk_dump(stdout, parsed); //XXX
599 ret = eval_expression(&result, userctx, ops, tk, parsed);
603 assert(result.has_val);
604 assert(result.op == NULL);
605 *user_result = result.val;
610 /* the test case is in a separate file ecoli_tk_expr_test.c */