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.
36 #include <ecoli_malloc.h>
37 #include <ecoli_log.h>
38 #include <ecoli_test.h>
39 #include <ecoli_strvec.h>
41 #include <ecoli_tk_str.h>
42 #include <ecoli_tk_int.h>
43 #include <ecoli_tk_seq.h>
44 #include <ecoli_tk_many.h>
45 #include <ecoli_tk_or.h>
46 #include <ecoli_tk_expr.h>
47 #include <ecoli_tk_bypass.h>
55 /* the configuration nodes */
57 struct ec_tk **bin_ops;
58 unsigned int bin_ops_len;
59 struct ec_tk **pre_ops;
60 unsigned int pre_ops_len;
61 struct ec_tk **post_ops;
62 unsigned int post_ops_len;
63 struct ec_tk **open_ops;
64 struct ec_tk **close_ops;
65 unsigned int paren_len;
68 static struct ec_parsed_tk *ec_tk_expr_parse(const struct ec_tk *gen_tk,
69 const struct ec_strvec *strvec)
71 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
73 return ec_tk_parse_tokens(tk->child, strvec);
76 static struct ec_completed_tk *ec_tk_expr_complete(const struct ec_tk *gen_tk,
77 const struct ec_strvec *strvec)
79 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
81 return ec_tk_complete_tokens(tk->child, strvec);
84 static void ec_tk_expr_free_priv(struct ec_tk *gen_tk)
86 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
90 ec_log(EC_LOG_DEBUG, "free %p %p %p\n", tk, tk->child, tk->val_tk);
91 ec_tk_free(tk->val_tk);
93 for (i = 0; i < tk->bin_ops_len; i++)
94 ec_tk_free(tk->bin_ops[i]);
96 for (i = 0; i < tk->pre_ops_len; i++)
97 ec_tk_free(tk->pre_ops[i]);
99 for (i = 0; i < tk->post_ops_len; i++)
100 ec_tk_free(tk->post_ops[i]);
101 ec_free(tk->post_ops);
102 for (i = 0; i < tk->paren_len; i++) {
103 ec_tk_free(tk->open_ops[i]);
104 ec_tk_free(tk->close_ops[i]);
106 ec_free(tk->open_ops);
107 ec_free(tk->close_ops);
109 /* break the graph loop, and free the nodes */
110 if (tk->child != NULL) {
111 final = ec_tk_bypass_pop(tk->child);
112 ec_tk_free(tk->child);
117 static int ec_tk_expr_build(struct ec_tk *gen_tk)
119 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
120 struct ec_tk *term = NULL, *expr = NULL, *next = NULL,
121 *pre_op = NULL, *post_op = NULL,
122 *post = NULL, *final = NULL;
126 if (tk->val_tk == NULL)
128 if (tk->bin_ops_len == 0 && tk->pre_ops_len == 0 &&
129 tk->post_ops_len == 0)
132 /* create the object, we will initialize it later: this is
133 * needed because we have a circular dependency */
135 expr = ec_tk_bypass_empty("expr");
139 /* prefix unary operators */
140 pre_op = ec_tk_or("pre-op");
143 for (i = 0; i < tk->pre_ops_len; i++) {
144 if (ec_tk_or_add(pre_op, ec_tk_clone(tk->pre_ops[i])) < 0)
148 /* suffix unary operators */
149 post_op = ec_tk_or("post-op");
152 for (i = 0; i < tk->post_ops_len; i++) {
153 if (ec_tk_or_add(post_op, ec_tk_clone(tk->post_ops[i])) < 0)
157 term = ec_tk_or("term");
160 if (ec_tk_or_add(term, ec_tk_clone(tk->val_tk)) < 0)
162 if (ec_tk_or_add(term,
165 ec_tk_clone(expr))) < 0)
167 for (i = 0; i < tk->paren_len; i++) {
168 if (ec_tk_or_add(term, EC_TK_SEQ(NULL,
169 ec_tk_clone(tk->open_ops[i]),
171 ec_tk_clone(tk->close_ops[i]))) < 0)
175 for (i = 0; i < tk->bin_ops_len; i++) {
176 next = EC_TK_SEQ("next",
180 ec_tk_clone(tk->bin_ops[i]),
192 final = EC_TK_SEQ("final",
194 ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0)
199 /* free the initial references */
209 if (ec_tk_bypass_set(expr, ec_tk_clone(final)) < 0)
230 static struct ec_tk_ops ec_tk_expr_ops = {
232 .build = ec_tk_expr_build,
233 .parse = ec_tk_expr_parse,
234 .complete = ec_tk_expr_complete,
235 .free_priv = ec_tk_expr_free_priv,
238 struct ec_tk *ec_tk_expr(const char *id)
240 struct ec_tk_expr *tk = NULL;
241 struct ec_tk *gen_tk = NULL;
243 gen_tk = ec_tk_new(id, &ec_tk_expr_ops, sizeof(*tk));
246 tk = (struct ec_tk_expr *)gen_tk;
251 int ec_tk_expr_set_val_tk(struct ec_tk *gen_tk, struct ec_tk *val_tk)
253 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
260 if (gen_tk->flags & EC_TK_F_BUILT)
263 if (tk->val_tk != NULL)
267 gen_tk->flags &= ~EC_TK_F_BUILT;
276 /* add a binary operator */
277 int ec_tk_expr_add_bin_op(struct ec_tk *gen_tk, struct ec_tk *op)
279 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
280 struct ec_tk **bin_ops;
286 if (tk == NULL || op == NULL)
289 if (gen_tk->flags & EC_TK_F_BUILT)
293 bin_ops = ec_realloc(tk->bin_ops,
294 (tk->bin_ops_len + 1) * sizeof(*tk->bin_ops));
298 tk->bin_ops = bin_ops;
299 bin_ops[tk->bin_ops_len] = op;
301 gen_tk->flags &= ~EC_TK_F_BUILT;
310 /* add a unary pre-operator */
311 int ec_tk_expr_add_pre_op(struct ec_tk *gen_tk, struct ec_tk *op)
313 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
314 struct ec_tk **pre_ops;
320 if (tk == NULL || op == NULL)
323 if (gen_tk->flags & EC_TK_F_BUILT)
327 pre_ops = ec_realloc(tk->pre_ops,
328 (tk->pre_ops_len + 1) * sizeof(*tk->pre_ops));
332 tk->pre_ops = pre_ops;
333 pre_ops[tk->pre_ops_len] = op;
335 gen_tk->flags &= ~EC_TK_F_BUILT;
344 /* add a unary post-operator */
345 int ec_tk_expr_add_post_op(struct ec_tk *gen_tk, struct ec_tk *op)
347 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
348 struct ec_tk **post_ops;
354 if (tk == NULL || op == NULL)
357 if (gen_tk->flags & EC_TK_F_BUILT)
361 post_ops = ec_realloc(tk->post_ops,
362 (tk->post_ops_len + 1) * sizeof(*tk->post_ops));
363 if (post_ops == NULL)
366 tk->post_ops = post_ops;
367 post_ops[tk->post_ops_len] = op;
369 gen_tk->flags &= ~EC_TK_F_BUILT;
378 /* add parenthesis symbols */
379 int ec_tk_expr_add_parenthesis(struct ec_tk *gen_tk,
380 struct ec_tk *open, struct ec_tk *close)
382 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
383 struct ec_tk **open_ops, **close_ops;
389 if (tk == NULL || open == NULL || close == NULL)
392 if (gen_tk->flags & EC_TK_F_BUILT)
396 open_ops = ec_realloc(tk->open_ops,
397 (tk->paren_len + 1) * sizeof(*tk->open_ops));
398 if (open_ops == NULL)
400 close_ops = ec_realloc(tk->close_ops,
401 (tk->paren_len + 1) * sizeof(*tk->close_ops));
402 if (close_ops == NULL)
405 tk->open_ops = open_ops;
406 tk->close_ops = close_ops;
407 open_ops[tk->paren_len] = open;
408 close_ops[tk->paren_len] = close;
410 gen_tk->flags &= ~EC_TK_F_BUILT;
420 static int ec_tk_expr_testcase_manual(void)
422 struct ec_tk *term = NULL, *factor = NULL, *expr = NULL, *val = NULL,
423 *pre_op = NULL, *post_op = NULL, *post = NULL, *final = NULL;
426 // XXX check all APIs: pointers are "moved", they are freed by
429 /* Example that generates an expression "manually". We keep it
430 * here for reference. */
432 /* create the object, we will initialize it later: this is
433 * needed because we have a circular dependency */
434 expr = ec_tk_bypass_empty("expr");
439 pre_op = EC_TK_OR("pre-op",
444 post_op = EC_TK_OR("post-op",
448 val = ec_tk_int("val", 0, UCHAR_MAX, 0);
449 term = EC_TK_OR("term",
452 ec_tk_str(NULL, "("),
463 factor = EC_TK_SEQ("factor",
467 ec_tk_str(NULL, "+"),
474 post = EC_TK_SEQ("post",
478 ec_tk_str(NULL, "*"),
485 final = EC_TK_SEQ("final",
487 ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0)
490 /* free the initial references */
502 if (ec_tk_bypass_set(expr, ec_tk_clone(final)) < 0)
508 ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1");
509 ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", "*");
510 ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "*", "1");
511 ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "+", "1");
512 ret |= EC_TEST_CHECK_TK_PARSE(expr, 5, "1", "*", "1", "+", "1");
513 ret |= EC_TEST_CHECK_TK_PARSE(
514 expr, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")");
515 ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1");
517 final = ec_tk_bypass_pop(expr);
535 static int ec_tk_expr_testcase(void)
540 ret = ec_tk_expr_testcase_manual();
544 tk = ec_tk_expr(NULL);
548 ec_tk_expr_set_val_tk(tk, ec_tk_int(NULL, 0, UCHAR_MAX, 0));
549 ec_tk_expr_add_bin_op(tk, ec_tk_str(NULL, "+"));
550 ec_tk_expr_add_bin_op(tk, ec_tk_str(NULL, "*"));
551 ec_tk_expr_add_pre_op(tk, ec_tk_str(NULL, "~"));
552 ec_tk_expr_add_pre_op(tk, ec_tk_str(NULL, "!"));
553 ec_tk_expr_add_parenthesis(tk, ec_tk_str(NULL, "("),
554 ec_tk_str(NULL, ")"));
555 ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "1");
556 ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "1", "*");
557 ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "1", "*", "1");
558 ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "1", "+", "1");
559 ret |= EC_TEST_CHECK_TK_PARSE(tk, 5, "1", "*", "1", "+", "1");
560 ret |= EC_TEST_CHECK_TK_PARSE(
561 tk, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")");
562 ret |= EC_TEST_CHECK_TK_PARSE(tk, 4, "1", "+", "~", "1");
568 static struct ec_test ec_tk_expr_test = {
570 .test = ec_tk_expr_testcase,
573 EC_REGISTER_TEST(ec_tk_expr_test);