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_weakref.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;
89 ec_log(EC_LOG_DEBUG, "free %p %p %p\n", tk, tk->child, tk->val_tk);
90 ec_tk_free(tk->val_tk);
92 for (i = 0; i < tk->bin_ops_len; i++)
93 ec_tk_free(tk->bin_ops[i]);
95 for (i = 0; i < tk->pre_ops_len; i++)
96 ec_tk_free(tk->pre_ops[i]);
98 for (i = 0; i < tk->post_ops_len; i++)
99 ec_tk_free(tk->post_ops[i]);
100 ec_free(tk->post_ops);
101 for (i = 0; i < tk->paren_len; i++) {
102 ec_tk_free(tk->open_ops[i]);
103 ec_tk_free(tk->close_ops[i]);
105 ec_free(tk->open_ops);
106 ec_free(tk->close_ops);
108 ec_tk_free(tk->child);
111 static int ec_tk_expr_build(struct ec_tk *gen_tk)
113 struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk;
114 struct ec_tk *term = NULL, *expr = NULL, *next = NULL,
115 *pre_op = NULL, *post_op = NULL,
116 *post = NULL, *weak = NULL;
120 if (tk->val_tk == NULL)
122 if (tk->bin_ops_len == 0 && tk->pre_ops_len == 0 &&
123 tk->post_ops_len == 0)
126 /* create the object, we will initialize it later: this is
127 * needed because we have a circular dependency */
129 weak = ec_tk_weakref_empty("weak");
133 /* prefix unary operators */
134 pre_op = ec_tk_or("pre-op");
137 for (i = 0; i < tk->pre_ops_len; i++) {
138 if (ec_tk_or_add(pre_op, ec_tk_clone(tk->pre_ops[i])) < 0)
142 /* suffix unary operators */
143 post_op = ec_tk_or("post-op");
146 for (i = 0; i < tk->post_ops_len; i++) {
147 if (ec_tk_or_add(post_op, ec_tk_clone(tk->post_ops[i])) < 0)
151 term = ec_tk_or("term");
154 if (ec_tk_or_add(term, ec_tk_clone(tk->val_tk)) < 0)
156 if (ec_tk_or_add(term,
159 ec_tk_clone(weak))) < 0)
161 for (i = 0; i < tk->paren_len; i++) {
162 if (ec_tk_or_add(term, EC_TK_SEQ(NULL,
163 ec_tk_clone(tk->open_ops[i]),
165 ec_tk_clone(tk->close_ops[i]))) < 0)
169 for (i = 0; i < tk->bin_ops_len; i++) {
170 next = EC_TK_SEQ("next",
174 ec_tk_clone(tk->bin_ops[i]),
186 expr = EC_TK_SEQ("expr",
188 ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0)
193 /* free the initial references */
203 /* no need to clone here, the node is not consumed */
204 if (ec_tk_weakref_set(weak, expr) < 0)
224 static struct ec_tk_ops ec_tk_expr_ops = {
226 .build = ec_tk_expr_build,
227 .parse = ec_tk_expr_parse,
228 .complete = ec_tk_expr_complete,
229 .free_priv = ec_tk_expr_free_priv,
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_ops, 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;
414 static int ec_tk_expr_testcase_manual(void)
416 struct ec_tk *term = NULL, *factor = NULL, *expr = NULL, *val = NULL,
417 *pre_op = NULL, *post_op = NULL, *post = NULL, *weak = NULL;
420 // XXX check all APIs: pointers are "moved", they are freed by
423 /* Example that generates an expression "manually". We keep it
424 * here for reference. */
426 weak = ec_tk_weakref_empty("weak");
431 pre_op = EC_TK_OR("pre-op",
436 post_op = EC_TK_OR("post-op",
440 val = ec_tk_int("val", 0, UCHAR_MAX, 0);
441 term = EC_TK_OR("term",
444 ec_tk_str(NULL, "("),
455 factor = EC_TK_SEQ("factor",
459 ec_tk_str(NULL, "+"),
466 post = EC_TK_SEQ("post",
470 ec_tk_str(NULL, "*"),
477 expr = EC_TK_SEQ("expr",
479 ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0)
482 /* free the initial references */
494 /* no need to clone here, the node is not consumed */
495 if (ec_tk_weakref_set(weak, expr) < 0)
500 ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1");
501 ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", "*");
502 ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "*", "1");
503 ret |= EC_TEST_CHECK_TK_PARSE(expr, 3, "1", "+", "1");
504 ret |= EC_TEST_CHECK_TK_PARSE(expr, 5, "1", "*", "1", "+", "1");
505 ret |= EC_TEST_CHECK_TK_PARSE(
506 expr, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")");
507 ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1");
525 static int ec_tk_expr_testcase(void)
530 ret = ec_tk_expr_testcase_manual();
534 tk = ec_tk_expr(NULL);
538 ec_tk_expr_set_val_tk(tk, ec_tk_int(NULL, 0, UCHAR_MAX, 0));
539 ec_tk_expr_add_bin_op(tk, ec_tk_str(NULL, "+"));
540 ec_tk_expr_add_bin_op(tk, ec_tk_str(NULL, "*"));
541 ec_tk_expr_add_pre_op(tk, ec_tk_str(NULL, "~"));
542 ec_tk_expr_add_pre_op(tk, ec_tk_str(NULL, "!"));
543 ec_tk_expr_add_parenthesis(tk, ec_tk_str(NULL, "("),
544 ec_tk_str(NULL, ")"));
545 ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "1");
546 ret |= EC_TEST_CHECK_TK_PARSE(tk, 1, "1", "*");
547 ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "1", "*", "1");
548 ret |= EC_TEST_CHECK_TK_PARSE(tk, 3, "1", "+", "1");
549 ret |= EC_TEST_CHECK_TK_PARSE(tk, 5, "1", "*", "1", "+", "1");
550 ret |= EC_TEST_CHECK_TK_PARSE(
551 tk, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")");
552 ret |= EC_TEST_CHECK_TK_PARSE(tk, 4, "1", "+", "~", "1");
558 static struct ec_test ec_tk_expr_test = {
560 .test = ec_tk_expr_testcase,
563 EC_REGISTER_TEST(ec_tk_expr_test);