free children in free_priv
[protos/libecoli.git] / lib / ecoli_node_expr.c
index 672b62e..eb7bff3 100644 (file)
@@ -1,28 +1,5 @@
-/*
- * Copyright (c) 2016-2017, Olivier MATZ <zer0@droids-corp.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the University of California, Berkeley nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
  */
 
 #include <stdio.h>
 #include <ecoli_test.h>
 #include <ecoli_strvec.h>
 #include <ecoli_node.h>
-#include <ecoli_parsed.h>
-#include <ecoli_completed.h>
+#include <ecoli_parse.h>
+#include <ecoli_complete.h>
 #include <ecoli_node_seq.h>
 #include <ecoli_node_many.h>
 #include <ecoli_node_or.h>
-#include <ecoli_node_weakref.h>
 #include <ecoli_node_expr.h>
 
+EC_LOG_TYPE_REGISTER(node_expr);
+
 struct ec_node_expr {
        struct ec_node gen;
 
@@ -66,20 +44,33 @@ struct ec_node_expr {
        unsigned int paren_len;
 };
 
-static struct ec_parsed *ec_node_expr_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int ec_node_expr_parse(const struct ec_node *gen_node,
+                       struct ec_parse *state,
+                       const struct ec_strvec *strvec)
 {
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
 
-       return ec_node_parse_strvec(node->child, strvec);
+       if (node->child == NULL) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       return ec_node_parse_child(node->child, state, strvec);
 }
 
-static struct ec_completed *ec_node_expr_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_expr_complete(const struct ec_node *gen_node,
+               struct ec_comp *comp,
+               const struct ec_strvec *strvec)
 {
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
 
-       return ec_node_complete_strvec(node->child, strvec);
+       if (node->child == NULL) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       return ec_node_complete_child(node->child, comp, strvec);
 }
 
 static void ec_node_expr_free_priv(struct ec_node *gen_node)
@@ -87,7 +78,7 @@ static void ec_node_expr_free_priv(struct ec_node *gen_node)
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
        unsigned int i;
 
-       ec_log(EC_LOG_DEBUG, "free %p %p %p\n", node, node->child, node->val_node);
+       ec_node_free(node->child);
        ec_node_free(node->val_node);
 
        for (i = 0; i < node->bin_ops_len; i++)
@@ -105,30 +96,46 @@ static void ec_node_expr_free_priv(struct ec_node *gen_node)
        }
        ec_free(node->open_ops);
        ec_free(node->close_ops);
-
-       ec_node_free(node->child);
 }
 
-static int ec_node_expr_build(struct ec_node *gen_node)
+static int ec_node_expr_build(struct ec_node_expr *node)
 {
-       struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
        struct ec_node *term = NULL, *expr = NULL, *next = NULL,
-               *pre_op = NULL, *post_op = NULL,
-               *post = NULL, *weak = NULL;
+               *pre_op = NULL, *post_op = NULL, *ref = NULL,
+               *post = NULL;
        unsigned int i;
-       int ret;
 
-       if (node->val_node == NULL)
-               return -EINVAL;
+       ec_node_free(node->child);
+       node->child = NULL;
+
+       if (node->val_node == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
        if (node->bin_ops_len == 0 && node->pre_ops_len == 0 &&
-                       node->post_ops_len == 0)
-               return -EINVAL;
-
-       /* create the object, we will initialize it later: this is
-        * needed because we have a circular dependency */
-       ret = -ENOMEM;
-       weak = ec_node("weakref", "weak");
-       if (weak == NULL)
+                       node->post_ops_len == 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       /*
+        * Example of created grammar:
+        *
+        * pre_op = "!"
+        * post_op = "^"
+        * post = val |
+        *        pre_op expr |
+        *        "(" expr ")"
+        * term = post post_op*
+        * prod = term ( "*" term )*
+        * sum = prod ( "+" prod )*
+        * expr = sum
+        */
+
+       /* we use this as a ref, will be set later */
+       ref = ec_node("seq", "ref");
+       if (ref == NULL)
                return -1;
 
        /* prefix unary operators */
@@ -155,20 +162,20 @@ static int ec_node_expr_build(struct ec_node *gen_node)
        if (ec_node_or_add(post, ec_node_clone(node->val_node)) < 0)
                goto fail;
        if (ec_node_or_add(post,
-               EC_NODE_SEQ(NULL,
+               EC_NODE_SEQ(EC_NO_ID,
                        ec_node_clone(pre_op),
-                       ec_node_clone(weak))) < 0)
+                       ec_node_clone(ref))) < 0)
                goto fail;
        for (i = 0; i < node->paren_len; i++) {
-               if (ec_node_or_add(post, EC_NODE_SEQ(NULL,
+               if (ec_node_or_add(post, EC_NODE_SEQ(EC_NO_ID,
                                        ec_node_clone(node->open_ops[i]),
-                                       ec_node_clone(weak),
+                                       ec_node_clone(ref),
                                        ec_node_clone(node->close_ops[i]))) < 0)
                        goto fail;
        }
        term = EC_NODE_SEQ("term",
                ec_node_clone(post),
-               ec_node_many(NULL, ec_node_clone(post_op), 0, 0)
+               ec_node_many(EC_NO_ID, ec_node_clone(post_op), 0, 0)
        );
        if (term == NULL)
                goto fail;
@@ -176,8 +183,8 @@ static int ec_node_expr_build(struct ec_node *gen_node)
        for (i = 0; i < node->bin_ops_len; i++) {
                next = EC_NODE_SEQ("next",
                        ec_node_clone(term),
-                       ec_node_many(NULL,
-                               EC_NODE_SEQ(NULL,
+                       ec_node_many(EC_NO_ID,
+                               EC_NODE_SEQ(EC_NO_ID,
                                        ec_node_clone(node->bin_ops[i]),
                                        ec_node_clone(term)
                                ),
@@ -200,11 +207,10 @@ static int ec_node_expr_build(struct ec_node *gen_node)
        ec_node_free(post);
        post = NULL;
 
-       /* no need to clone here, the node is not consumed */
-       if (ec_node_weakref_set(weak, expr) < 0)
+       if (ec_node_seq_add(ref, ec_node_clone(expr)) < 0)
                goto fail;
-       ec_node_free(weak);
-       weak = NULL;
+       ec_node_free(ref);
+       ref = NULL;
 
        node->child = expr;
 
@@ -216,18 +222,40 @@ fail:
        ec_node_free(pre_op);
        ec_node_free(post_op);
        ec_node_free(post);
-       ec_node_free(weak);
+       ec_node_free(ref);
 
-       return ret;
+       return -1;
+}
+
+static size_t
+ec_node_expr_get_children_count(const struct ec_node *gen_node)
+{
+       struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
+
+       if (node->child)
+               return 1;
+       return 0;
+}
+
+static struct ec_node *
+ec_node_expr_get_child(const struct ec_node *gen_node, size_t i)
+{
+       struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
+
+       if (i >= 1)
+               return NULL;
+
+       return node->child;
 }
 
 static struct ec_node_type ec_node_expr_type = {
        .name = "expr",
-       .build = ec_node_expr_build,
        .parse = ec_node_expr_parse,
        .complete = ec_node_expr_complete,
        .size = sizeof(struct ec_node_expr),
        .free_priv = ec_node_expr_free_priv,
+       .get_children_count = ec_node_expr_get_children_count,
+       .get_child = ec_node_expr_get_child,
 };
 
 EC_NODE_TYPE_REGISTER(ec_node_expr_type);
@@ -235,26 +263,24 @@ EC_NODE_TYPE_REGISTER(ec_node_expr_type);
 int ec_node_expr_set_val_node(struct ec_node *gen_node, struct ec_node *val_node)
 {
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
-       int ret;
 
-       ret = -EINVAL;
-       if (val_node == NULL)
-               goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
+       if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
                goto fail;
-       ret = -EEXIST;
-       if (node->val_node != NULL)
+
+       if (val_node == NULL) {
+               errno = EINVAL;
                goto fail;
+       }
 
+       ec_node_free(node->val_node);
        node->val_node = val_node;
-       gen_node->flags &= ~EC_NODE_F_BUILT;
+       ec_node_expr_build(node);
 
        return 0;
 
 fail:
        ec_node_free(val_node);
-       return ret;
+       return -1;
 }
 
 /* add a binary operator */
@@ -262,18 +288,15 @@ int ec_node_expr_add_bin_op(struct ec_node *gen_node, struct ec_node *op)
 {
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
        struct ec_node **bin_ops;
-       int ret;
-
-       // XXX check node type
 
-       ret = -EINVAL;
-       if (node == NULL || op == NULL)
+       if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
+
+       if (node == NULL || op == NULL) {
+               errno = EINVAL;
                goto fail;
+       }
 
-       ret = -ENOMEM;
        bin_ops = ec_realloc(node->bin_ops,
                (node->bin_ops_len + 1) * sizeof(*node->bin_ops));
        if (bin_ops == NULL)
@@ -282,13 +305,13 @@ int ec_node_expr_add_bin_op(struct ec_node *gen_node, struct ec_node *op)
        node->bin_ops = bin_ops;
        bin_ops[node->bin_ops_len] = op;
        node->bin_ops_len++;
-       gen_node->flags &= ~EC_NODE_F_BUILT;
+       ec_node_expr_build(node);
 
        return 0;
 
 fail:
        ec_node_free(op);
-       return ret;
+       return -1;
 }
 
 /* add a unary pre-operator */
@@ -296,18 +319,15 @@ int ec_node_expr_add_pre_op(struct ec_node *gen_node, struct ec_node *op)
 {
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
        struct ec_node **pre_ops;
-       int ret;
 
-       // XXX check node type
-
-       ret = -EINVAL;
-       if (node == NULL || op == NULL)
+       if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
+
+       if (node == NULL || op == NULL) {
+               errno = EINVAL;
                goto fail;
+       }
 
-       ret = -ENOMEM;
        pre_ops = ec_realloc(node->pre_ops,
                (node->pre_ops_len + 1) * sizeof(*node->pre_ops));
        if (pre_ops == NULL)
@@ -316,13 +336,13 @@ int ec_node_expr_add_pre_op(struct ec_node *gen_node, struct ec_node *op)
        node->pre_ops = pre_ops;
        pre_ops[node->pre_ops_len] = op;
        node->pre_ops_len++;
-       gen_node->flags &= ~EC_NODE_F_BUILT;
+       ec_node_expr_build(node);
 
        return 0;
 
 fail:
        ec_node_free(op);
-       return ret;
+       return -1;
 }
 
 /* add a unary post-operator */
@@ -330,18 +350,15 @@ int ec_node_expr_add_post_op(struct ec_node *gen_node, struct ec_node *op)
 {
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
        struct ec_node **post_ops;
-       int ret;
-
-       // XXX check node type
 
-       ret = -EINVAL;
-       if (node == NULL || op == NULL)
+       if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
+
+       if (node == NULL || op == NULL) {
+               errno = EINVAL;
                goto fail;
+       }
 
-       ret = -ENOMEM;
        post_ops = ec_realloc(node->post_ops,
                (node->post_ops_len + 1) * sizeof(*node->post_ops));
        if (post_ops == NULL)
@@ -350,13 +367,13 @@ int ec_node_expr_add_post_op(struct ec_node *gen_node, struct ec_node *op)
        node->post_ops = post_ops;
        post_ops[node->post_ops_len] = op;
        node->post_ops_len++;
-       gen_node->flags &= ~EC_NODE_F_BUILT;
+       ec_node_expr_build(node);
 
        return 0;
 
 fail:
        ec_node_free(op);
-       return ret;
+       return -1;
 }
 
 /* add parenthesis symbols */
@@ -365,18 +382,15 @@ int ec_node_expr_add_parenthesis(struct ec_node *gen_node,
 {
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
        struct ec_node **open_ops, **close_ops;
-       int ret;
 
-       // XXX check node type
+       if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
+               goto fail;
 
-       ret = -EINVAL;
-       if (node == NULL || open == NULL || close == NULL)
+       if (node == NULL || open == NULL || close == NULL) {
+               errno = EINVAL;
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
-               goto fail;;
+       }
 
-       ret = -ENOMEM;
        open_ops = ec_realloc(node->open_ops,
                (node->paren_len + 1) * sizeof(*node->open_ops));
        if (open_ops == NULL)
@@ -391,14 +405,14 @@ int ec_node_expr_add_parenthesis(struct ec_node *gen_node,
        open_ops[node->paren_len] = open;
        close_ops[node->paren_len] = close;
        node->paren_len++;
-       gen_node->flags &= ~EC_NODE_F_BUILT;
+       ec_node_expr_build(node);
 
        return 0;
 
 fail:
        ec_node_free(open);
        ec_node_free(close);
-       return ret;
+       return -1;
 }
 
 enum expr_node_type {
@@ -410,6 +424,7 @@ enum expr_node_type {
        PAREN_OPEN,
        PAREN_CLOSE,
 };
+
 static enum expr_node_type get_node_type(const struct ec_node *expr_gen_node,
        const struct ec_node *check)
 {
@@ -447,7 +462,7 @@ static enum expr_node_type get_node_type(const struct ec_node *expr_gen_node,
 struct result {
        bool has_val;
        void *val;
-       const struct ec_parsed *op;
+       const struct ec_parse *op;
        enum expr_node_type op_type;
 };
 
@@ -456,8 +471,6 @@ static int merge_results(void *userctx,
        const struct ec_node_expr_eval_ops *ops,
        struct result *x, const struct result *y)
 {
-       int ret;
-
        if (y->has_val == 0 && y->op == NULL)
                return 0;
        if (x->has_val == 0 && x->op == NULL) {
@@ -465,19 +478,21 @@ static int merge_results(void *userctx,
                return 0;
        }
 
-       if (x->has_val && x->op == NULL && y->has_val && y->op != NULL) {
-               ret = ops->eval_bin_op(&x->val, userctx, x->val, y->op, y->val);
-               if (ret < 0)
-                       return ret;
+       if (x->has_val && y->has_val && y->op != NULL) {
+               if (y->op_type == BIN_OP) {
+                       if (ops->eval_bin_op(&x->val, userctx, x->val,
+                                       y->op, y->val) < 0)
+                               return -1;
 
-               return 0;
+                       return 0;
+               }
        }
 
        if (x->has_val == 0 && x->op != NULL && y->has_val && y->op == NULL) {
                if (x->op_type == PRE_OP) {
-                       ret = ops->eval_pre_op(&x->val, userctx, y->val, x->op);
-                       if (ret < 0)
-                               return ret;
+                       if (ops->eval_pre_op(&x->val, userctx, y->val,
+                                               x->op) < 0)
+                               return -1;
                        x->has_val = true;
                        x->op_type = NONE;
                        x->op = NULL;
@@ -490,47 +505,44 @@ static int merge_results(void *userctx,
        }
 
        if (x->has_val && x->op == NULL && y->has_val == 0 && y->op != NULL) {
-               ret = ops->eval_post_op(&x->val, userctx, x->val, y->op);
-               if (ret < 0)
-                       return ret;
+               if (ops->eval_post_op(&x->val, userctx, x->val, y->op) < 0)
+                       return -1;
 
                return 0;
        }
 
-       assert(true); /* we should not get here */
-       return -EINVAL;
+       assert(false); /* we should not get here */
+       return -1;
 }
 
 static int eval_expression(struct result *result,
        void *userctx,
        const struct ec_node_expr_eval_ops *ops,
        const struct ec_node *expr_gen_node,
-       const struct ec_parsed *parsed)
+       const struct ec_parse *parse)
 
 {
-       struct ec_parsed *open = NULL, *close = NULL;
+       struct ec_parse *open = NULL, *close = NULL;
        struct result child_result;
-       struct ec_parsed *child;
+       struct ec_parse *child;
        enum expr_node_type type;
-       int ret;
 
        memset(result, 0, sizeof(*result));
        memset(&child_result, 0, sizeof(child_result));
 
-       type = get_node_type(expr_gen_node, parsed->node);
+       type = get_node_type(expr_gen_node, ec_parse_get_node(parse));
        if (type == VAL) {
-               ret = ops->eval_var(&result->val, userctx, parsed);
-               if (ret < 0)
+               if (ops->eval_var(&result->val, userctx, parse) < 0)
                        goto fail;
                result->has_val = 1;
        } else if (type == PRE_OP || type == POST_OP || type == BIN_OP) {
-               result->op = parsed;
+               result->op = parse;
                result->op_type = type;
        }
 
-       TAILQ_FOREACH(child, &parsed->children, next) {
+       EC_PARSE_FOREACH_CHILD(child, parse) {
 
-               type = get_node_type(expr_gen_node, child->node);
+               type = get_node_type(expr_gen_node, ec_parse_get_node(child));
                if (type == PAREN_OPEN) {
                        open = child;
                        continue;
@@ -539,22 +551,19 @@ static int eval_expression(struct result *result,
                        continue;
                }
 
-               ret = eval_expression(&child_result, userctx, ops,
-                       expr_gen_node, child);
-               if (ret < 0)
+               if (eval_expression(&child_result, userctx, ops,
+                       expr_gen_node, child) < 0)
                        goto fail;
 
-               ret = merge_results(userctx, ops, result, &child_result);
-               if (ret < 0)
+               if (merge_results(userctx, ops, result, &child_result) < 0)
                        goto fail;
 
                memset(&child_result, 0, sizeof(child_result));
        }
 
        if (open != NULL && close != NULL) {
-               ret = ops->eval_parenthesis(&result->val, userctx, open, close,
-                       result->val);
-               if (ret < 0)
+               if (ops->eval_parenthesis(&result->val, userctx, open, close,
+                       result->val) < 0)
                        goto fail;
        }
 
@@ -567,28 +576,33 @@ fail:
                ops->eval_free(child_result.val, userctx);
        memset(result, 0, sizeof(*result));
 
-       return ret;
+       return -1;
 }
 
 int ec_node_expr_eval(void **user_result, const struct ec_node *node,
-       struct ec_parsed *parsed, const struct ec_node_expr_eval_ops *ops,
+       struct ec_parse *parse, const struct ec_node_expr_eval_ops *ops,
        void *userctx)
 {
        struct result result;
-       int ret;
 
        if (ops == NULL || ops->eval_var == NULL || ops->eval_pre_op == NULL ||
                        ops->eval_post_op == NULL || ops->eval_bin_op == NULL ||
-                       ops->eval_parenthesis == NULL || ops->eval_free == NULL)
-               return -EINVAL;
+                       ops->eval_parenthesis == NULL ||
+                       ops->eval_free == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
 
-       if (!ec_parsed_matches(parsed))
-               return -EINVAL;
+       if (ec_node_check_type(node, &ec_node_expr_type) < 0)
+               return -1;
 
-       ec_parsed_dump(stdout, parsed); //XXX
-       ret = eval_expression(&result, userctx, ops, node, parsed);
-       if (ret < 0)
-               return ret;
+       if (!ec_parse_matches(parse)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (eval_expression(&result, userctx, ops, node, parse) < 0)
+               return -1;
 
        assert(result.has_val);
        assert(result.op == NULL);