better test coverage
[protos/libecoli.git] / lib / ecoli_node_expr.c
index 8d2f698..2be8f55 100644 (file)
 #include <ecoli_test.h>
 #include <ecoli_strvec.h>
 #include <ecoli_node.h>
+#include <ecoli_parsed.h>
+#include <ecoli_completed.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;
 
@@ -64,20 +68,27 @@ 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_parsed *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)
+               return -ENOENT;
+       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_completed *completed,
+               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)
+               return -ENOENT;
+       return ec_node_complete_child(node->child, completed, strvec);
 }
 
 static void ec_node_expr_free_priv(struct ec_node *gen_node)
@@ -85,7 +96,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_LOG(EC_LOG_DEBUG, "free %p %p %p\n", node, node->child, node->val_node);
        ec_node_free(node->val_node);
 
        for (i = 0; i < node->bin_ops_len; i++)
@@ -107,21 +118,37 @@ static void ec_node_expr_free_priv(struct ec_node *gen_node)
        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;
        unsigned int i;
        int ret;
 
+       ec_node_free(node->child);
+       node->child = NULL;
+
        if (node->val_node == NULL)
                return -EINVAL;
        if (node->bin_ops_len == 0 && node->pre_ops_len == 0 &&
                        node->post_ops_len == 0)
                return -EINVAL;
 
+       /*
+        * 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
+        */
+
        /* create the object, we will initialize it later: this is
         * needed because we have a circular dependency */
        ret = -ENOMEM;
@@ -153,12 +180,12 @@ 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)
                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(node->close_ops[i]))) < 0)
@@ -166,7 +193,7 @@ static int ec_node_expr_build(struct ec_node *gen_node)
        }
        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;
@@ -174,8 +201,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)
                                ),
@@ -221,7 +248,6 @@ fail:
 
 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),
@@ -235,18 +261,17 @@ 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 = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
+
        ret = -EINVAL;
        if (val_node == NULL)
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
-               goto fail;
-       ret = -EEXIST;
-       if (node->val_node != NULL)
-               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;
 
@@ -262,14 +287,13 @@ int ec_node_expr_add_bin_op(struct ec_node *gen_node, struct ec_node *op)
        struct ec_node **bin_ops;
        int ret;
 
-       // XXX check node type
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
 
        ret = -EINVAL;
        if (node == NULL || op == NULL)
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
-               goto fail;
 
        ret = -ENOMEM;
        bin_ops = ec_realloc(node->bin_ops,
@@ -280,7 +304,7 @@ 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;
 
@@ -296,14 +320,13 @@ int ec_node_expr_add_pre_op(struct ec_node *gen_node, struct ec_node *op)
        struct ec_node **pre_ops;
        int ret;
 
-       // XXX check node type
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
 
        ret = -EINVAL;
        if (node == NULL || op == NULL)
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
-               goto fail;
 
        ret = -ENOMEM;
        pre_ops = ec_realloc(node->pre_ops,
@@ -314,7 +337,7 @@ 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;
 
@@ -330,14 +353,13 @@ int ec_node_expr_add_post_op(struct ec_node *gen_node, struct ec_node *op)
        struct ec_node **post_ops;
        int ret;
 
-       // XXX check node type
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
 
        ret = -EINVAL;
        if (node == NULL || op == NULL)
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
-               goto fail;
 
        ret = -ENOMEM;
        post_ops = ec_realloc(node->post_ops,
@@ -348,7 +370,7 @@ 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;
 
@@ -365,14 +387,13 @@ int ec_node_expr_add_parenthesis(struct ec_node *gen_node,
        struct ec_node **open_ops, **close_ops;
        int ret;
 
-       // XXX check node type
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
 
        ret = -EINVAL;
        if (node == NULL || open == NULL || close == NULL)
                goto fail;
-       ret = -EPERM;
-       if (gen_node->flags & EC_NODE_F_BUILT)
-               goto fail;;
 
        ret = -ENOMEM;
        open_ops = ec_realloc(node->open_ops,
@@ -389,7 +410,7 @@ 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;
 
@@ -408,6 +429,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)
 {
@@ -463,12 +485,15 @@ 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) {
+                       ret = ops->eval_bin_op(&x->val, userctx, x->val,
+                                       y->op, y->val);
+                       if (ret < 0)
+                               return ret;
 
-               return 0;
+                       return 0;
+               }
        }
 
        if (x->has_val == 0 && x->op != NULL && y->has_val && y->op == NULL) {
@@ -495,7 +520,7 @@ static int merge_results(void *userctx,
                return 0;
        }
 
-       assert(true); /* we should not get here */
+       assert(false); /* we should not get here */
        return -EINVAL;
 }
 
@@ -515,7 +540,7 @@ static int eval_expression(struct result *result,
        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_parsed_get_node(parsed));
        if (type == VAL) {
                ret = ops->eval_var(&result->val, userctx, parsed);
                if (ret < 0)
@@ -526,9 +551,9 @@ static int eval_expression(struct result *result,
                result->op_type = type;
        }
 
-       TAILQ_FOREACH(child, &parsed->children, next) {
+       EC_PARSED_FOREACH_CHILD(child, parsed) {
 
-               type = get_node_type(expr_gen_node, child->node);
+               type = get_node_type(expr_gen_node, ec_parsed_get_node(child));
                if (type == PAREN_OPEN) {
                        open = child;
                        continue;
@@ -580,10 +605,13 @@ int ec_node_expr_eval(void **user_result, const struct ec_node *node,
                        ops->eval_parenthesis == NULL || ops->eval_free == NULL)
                return -EINVAL;
 
+       ret = ec_node_check_type(node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
+
        if (!ec_parsed_matches(parsed))
                return -EINVAL;
 
-       ec_parsed_dump(stdout, parsed); //XXX
        ret = eval_expression(&result, userctx, ops, node, parsed);
        if (ret < 0)
                return ret;