pass state to completed api
authorOlivier Matz <zer0@droids-corp.org>
Thu, 20 Jul 2017 21:07:51 +0000 (23:07 +0200)
committerOlivier Matz <zer0@droids-corp.org>
Thu, 20 Jul 2017 21:07:51 +0000 (23:07 +0200)
18 files changed:
lib/ecoli_completed.c
lib/ecoli_completed.h
lib/ecoli_node.h
lib/ecoli_node_cmd.c
lib/ecoli_node_expr.c
lib/ecoli_node_many.c
lib/ecoli_node_once.c
lib/ecoli_node_option.c
lib/ecoli_node_or.c
lib/ecoli_node_seq.c
lib/ecoli_node_sh_lex.c
lib/ecoli_node_str.c
lib/ecoli_node_subset.c
lib/ecoli_node_weakref.c
lib/ecoli_parsed.c
lib/ecoli_parsed.h
lib/main-readline.c
lib/todo.txt

index 8a34c74..18e92ed 100644 (file)
@@ -53,8 +53,8 @@ struct ec_completed *ec_completed(void)
        return completed;
 }
 
-struct ec_completed_elt *ec_completed_elt(const struct ec_node *node,
-       const char *add)
+static struct ec_completed_elt *
+ec_completed_elt(const struct ec_node *node, const char *add)
 {
        struct ec_completed_elt *elt = NULL;
 
@@ -74,11 +74,70 @@ struct ec_completed_elt *ec_completed_elt(const struct ec_node *node,
        return elt;
 }
 
-/* XXX define when to use ec_node_complete() or node->complete()
- * (same for parse)
- * suggestion: node->op() is internal, user calls the function
- * other idea: have 2 functions
- */
+struct ec_completed *
+ec_node_complete_child(struct ec_node *node,
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
+{
+       struct ec_completed *completed;
+       struct ec_parsed *child;
+       int ret;
+
+       /* build the node if required */
+       if (node->type->build != NULL) {
+               if ((node->flags & EC_NODE_F_BUILT) == 0) {
+                       ret = node->type->build(node);
+                       if (ret < 0) {
+                               errno = -ret;
+                               return NULL;
+                       }
+               }
+       }
+       node->flags |= EC_NODE_F_BUILT;
+
+       if (node->type->complete == NULL) {
+               errno = ENOTSUP;
+               return NULL;
+       }
+
+       child = ec_parsed();
+       if (child == NULL)
+               return NULL;
+
+       child->node = node;
+       ec_parsed_add_child(state, child);
+       completed = node->type->complete(node, child, strvec);
+
+#if 0 // XXX dump
+       printf("----------------------------------------------------------\n");
+       ec_node_dump(stdout, node);
+       ec_strvec_dump(stdout, strvec);
+       ec_completed_dump(stdout, completed);
+       ec_parsed_dump(stdout, state);
+#endif
+
+       ec_parsed_del_child(state, child);
+       assert(TAILQ_EMPTY(&child->children));
+       ec_parsed_free(child);
+
+       return completed;
+}
+
+struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
+       const struct ec_strvec *strvec)
+{
+       struct ec_parsed *state = ec_parsed();
+       struct ec_completed *completed;
+
+       if (state == NULL)
+               return NULL;
+
+       completed = ec_node_complete_child(node, state, strvec);
+       ec_parsed_free(state);
+
+       return completed;
+}
+
 struct ec_completed *ec_node_complete(struct ec_node *node,
        const char *str)
 {
@@ -107,12 +166,13 @@ struct ec_completed *ec_node_complete(struct ec_node *node,
 
 /* default completion function: return a no-match element */
 struct ec_completed *ec_node_default_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+                                       struct ec_parsed *state,
+                                       const struct ec_strvec *strvec)
 {
        struct ec_completed *completed;
-       struct ec_completed_elt *completed_elt;
 
        (void)strvec;
+       (void)state;
 
        completed = ec_completed();
        if (completed == NULL)
@@ -121,55 +181,14 @@ struct ec_completed *ec_node_default_complete(const struct ec_node *gen_node,
        if (ec_strvec_len(strvec) != 1)
                return completed;
 
-       completed_elt = ec_completed_elt(gen_node, NULL);
-       if (completed_elt == NULL) {
+       if (ec_completed_add_elt(completed, gen_node, NULL) < 0) {
                ec_completed_free(completed);
                return NULL;
        }
 
-       ec_completed_add_elt(completed, completed_elt);
-
        return completed;
 }
 
-struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
-       const struct ec_strvec *strvec)
-{
-       int ret;
-
-       /* build the node if required */
-       if (node->type->build != NULL) {
-               if ((node->flags & EC_NODE_F_BUILT) == 0) {
-                       ret = node->type->build(node);
-                       if (ret < 0) {
-                               errno = -ret;
-                               return NULL;
-                       }
-               }
-       }
-       node->flags |= EC_NODE_F_BUILT;
-
-       if (node->type->complete == NULL) {
-               errno = ENOTSUP;
-               return NULL;
-       }
-
-#if 0 // XXX dump
-       {
-               struct ec_completed *c;
-               c = node->type->complete(node, strvec);
-
-               printf("--------------------------------------------------------------\n");
-               ec_node_dump(stdout, node);
-               ec_strvec_dump(stdout, strvec);
-               ec_completed_dump(stdout, c);
-               return c;
-       }
-#else
-       return node->type->complete(node, strvec);
-#endif
-}
-
 /* count the number of identical chars at the beginning of 2 strings */
 static size_t strcmp_count(const char *s1, const char *s2)
 {
@@ -181,8 +200,8 @@ static size_t strcmp_count(const char *s1, const char *s2)
        return i;
 }
 
-void ec_completed_add_elt(
-       struct ec_completed *completed, struct ec_completed_elt *elt)
+static int __ec_completed_add_elt(struct ec_completed *completed,
+                               struct ec_completed_elt *elt)
 {
        size_t n;
 
@@ -198,6 +217,20 @@ void ec_completed_add_elt(
                        completed->smallest_start[n] = '\0';
                }
        }
+
+       return 0;
+}
+
+int ec_completed_add_elt(struct ec_completed *completed,
+                       const struct ec_node *node, const char *add)
+{
+       struct ec_completed_elt *elt;
+
+       elt = ec_completed_elt(node, add);
+       if (elt == NULL)
+               return -ENOMEM;
+
+       return __ec_completed_add_elt(completed, elt);
 }
 
 void ec_completed_elt_free(struct ec_completed_elt *elt)
@@ -217,7 +250,7 @@ void ec_completed_merge(struct ec_completed *completed1,
        while (!TAILQ_EMPTY(&completed2->elts)) {
                elt = TAILQ_FIRST(&completed2->elts);
                TAILQ_REMOVE(&completed2->elts, elt, next);
-               ec_completed_add_elt(completed1, elt);
+               __ec_completed_add_elt(completed1, elt);
        }
 
        ec_completed_free(completed2);
index d9fcdc3..993db7f 100644 (file)
@@ -42,7 +42,6 @@ struct ec_completed_elt {
 
 TAILQ_HEAD(ec_completed_elt_list, ec_completed_elt);
 
-
 struct ec_completed {
        struct ec_completed_elt_list elts;
        unsigned count;
@@ -59,11 +58,16 @@ struct ec_completed *ec_node_complete(struct ec_node *node,
 struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
        const struct ec_strvec *strvec);
 
+/* internal: used by nodes */
+struct ec_completed *ec_node_complete_child(struct ec_node *node,
+                                       struct ec_parsed *state,
+                                       const struct ec_strvec *strvec);
+
 struct ec_completed *ec_completed(void);
-struct ec_completed_elt *ec_completed_elt(const struct ec_node *node,
-       const char *add);
-void ec_completed_add_elt(struct ec_completed *completed,
-       struct ec_completed_elt *elt);
+
+/* XXX add completion type: full, partial, none */
+int ec_completed_add_elt(struct ec_completed *completed,
+                       const struct ec_node *node, const char *add);
 void ec_completed_elt_free(struct ec_completed_elt *elt);
 void ec_completed_merge(struct ec_completed *completed1,
        struct ec_completed *completed2);
@@ -71,7 +75,8 @@ void ec_completed_free(struct ec_completed *completed);
 void ec_completed_dump(FILE *out,
        const struct ec_completed *completed);
 struct ec_completed *ec_node_default_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec);
+                                       struct ec_parsed *state,
+                                       const struct ec_strvec *strvec);
 
 /* cannot return NULL */
 const char *ec_completed_smallest_start(
index 9115ebc..e027f1d 100644 (file)
@@ -58,6 +58,7 @@ typedef int (*ec_node_parse_t)(const struct ec_node *node,
                        struct ec_parsed *state,
                        const struct ec_strvec *strvec);
 typedef struct ec_completed *(*ec_node_complete_t)(const struct ec_node *node,
+                                               struct ec_parsed *state,
                                                const struct ec_strvec *strvec);
 typedef const char * (*ec_node_desc_t)(const struct ec_node *);
 typedef void (*ec_node_init_priv_t)(struct ec_node *);
index 8cf76ab..2082bdd 100644 (file)
@@ -172,16 +172,26 @@ ec_node_cmd_eval_bin_op(void **result, void *userctx, void *operand1,
                ec_node_free(in2);
                *result = out;
        } else if (!strcmp(ec_strvec_val(vec, 0), ",")) {
-               out = EC_NODE_SUBSET(NULL, ec_node_clone(in1), ec_node_clone(in2));
-               if (out == NULL)
-                       return -EINVAL;
-               ec_node_free(in1);
-               ec_node_free(in2);
-               *result = out;
+               if (!strcmp(in2->type->name, "subset")) {
+                       if (ec_node_subset_add(in2, ec_node_clone(in1)) < 0)
+                               return -EINVAL;
+                       ec_node_free(in1);
+                       *result = in2;
+               } else {
+                       out = EC_NODE_SUBSET(NULL, ec_node_clone(in1),
+                                       ec_node_clone(in2));
+                       if (out == NULL)
+                               return -EINVAL;
+                       ec_node_free(in1);
+                       ec_node_free(in2);
+                       *result = out;
+               }
        } else {
                return -EINVAL;
        }
 
+       printf("eval bin_op out %p\n", *result);
+
        return 0;
 }
 
@@ -246,11 +256,12 @@ static int ec_node_cmd_parse(const struct ec_node *gen_node,
 }
 
 static struct ec_completed *ec_node_cmd_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+                                               struct ec_parsed *state,
+                                               const struct ec_strvec *strvec)
 {
        struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node;
 
-       return ec_node_complete_strvec(node->cmd, strvec);
+       return ec_node_complete_child(node->cmd, state, strvec);
 }
 
 static void ec_node_cmd_free_priv(struct ec_node *gen_node)
@@ -486,7 +497,7 @@ static int ec_node_cmd_testcase(void)
        int ret = 0;
 
        node = EC_NODE_CMD(NULL,
-               "command [option] (subset1, subset2) x | y",
+               "command [option] (subset1, subset2, subset3) x | y",
                ec_node_int("x", 0, 10, 10),
                ec_node_int("y", 20, 30, 10)
        );
index 5aa8a2e..78b6755 100644 (file)
@@ -76,11 +76,12 @@ static int ec_node_expr_parse(const struct ec_node *gen_node,
 }
 
 static struct ec_completed *ec_node_expr_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+                                               struct ec_parsed *state,
+                                               const struct ec_strvec *strvec)
 {
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
 
-       return ec_node_complete_strvec(node->child, strvec);
+       return ec_node_complete_child(node->child, state, strvec);
 }
 
 static void ec_node_expr_free_priv(struct ec_node *gen_node)
index c07ae5e..87534a3 100644 (file)
@@ -100,61 +100,91 @@ fail:
        return ret;
 }
 
-#if 0 //XXX missing node_many_complete
-static struct ec_completed *ec_node_many_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static struct ec_completed *
+__ec_node_many_complete(struct ec_node_many *node, unsigned int max,
+                       struct ec_parsed *state, const struct ec_strvec *strvec)
 {
-       struct ec_node_many *node = (struct ec_node_many *)gen_node;
        struct ec_completed *completed, *child_completed;
-       struct ec_strvec *childvec;
-       struct ec_parsed *parsed;
-       size_t len = 0;
+       struct ec_strvec *childvec = NULL;
        unsigned int i;
+       int ret;
 
        completed = ec_completed();
        if (completed == NULL)
                return NULL;
 
-       if (node->len == 0)
+       /* first, try to complete with the child node */
+       child_completed = ec_node_complete_child(node->child, state, strvec);
+       if (child_completed == NULL)
+               goto fail;
+       ec_completed_merge(completed, child_completed);
+       child_completed = NULL;
+
+       /* we're done, we reached the max number of nodes */
+       if (max == 1)
                return completed;
 
-       for (i = 0; i < node->len; i++) {
-               childvec = ec_strvec_ndup(strvec, len,
-                       ec_strvec_len(strvec) - len);
+       /* if there is a maximum, decrease it before recursion */
+       if (max != 0)
+               max--;
+
+       /* then, if the node matches the beginning of the strvec, try to
+        * complete the rest */
+       for (i = 0; i < ec_strvec_len(strvec); i++) {
+               childvec = ec_strvec_ndup(strvec, 0, i);
                if (childvec == NULL)
-                       goto fail; // XXX fail ?
+                       goto fail;
 
-               child_completed = ec_node_complete_strvec(node->table[i],
-                       childvec);
-               if (child_completed == NULL)
+               ret = ec_node_parse_child(node->child, state, childvec);
+               if (ret < 0 && ret != EC_PARSED_NOMATCH)
                        goto fail;
 
-               ec_completed_merge(completed, child_completed);
+               ec_strvec_free(childvec);
+               childvec = NULL;
+
+               if ((unsigned int)ret != i) {
+                       if (ret != EC_PARSED_NOMATCH)
+                               ec_parsed_del_last_child(state);
+                       continue;
+               }
 
-               parsed = ec_node_parse_strvec(node->table[i], childvec);
-               if (parsed == NULL)
+               childvec = ec_strvec_ndup(strvec, i, ec_strvec_len(strvec) - i);
+               if (childvec == NULL) {
+                       ec_parsed_del_last_child(state);
                        goto fail;
+               }
 
+               child_completed = __ec_node_many_complete(node, max,
+                                                       state, childvec);
+               ec_parsed_del_last_child(state);
                ec_strvec_free(childvec);
                childvec = NULL;
 
-               if (!ec_parsed_matches(parsed)) {
-                       ec_parsed_free(parsed);
-                       break;
-               }
+               if (child_completed == NULL)
+                       goto fail;
 
-               len += ec_strvec_len(parsed->strvec);
-               ec_parsed_free(parsed);
+               ec_completed_merge(completed, child_completed);
+               child_completed = NULL;
        }
 
        return completed;
 
 fail:
        ec_strvec_free(childvec);
+       ec_completed_free(child_completed);
        ec_completed_free(completed);
        return NULL;
 }
-#endif
+
+static struct ec_completed *
+ec_node_many_complete(const struct ec_node *gen_node,
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
+{
+       struct ec_node_many *node = (struct ec_node_many *)gen_node;
+
+       return __ec_node_many_complete(node, node->max, state, strvec);
+}
 
 static void ec_node_many_free_priv(struct ec_node *gen_node)
 {
@@ -166,8 +196,7 @@ static void ec_node_many_free_priv(struct ec_node *gen_node)
 static struct ec_node_type ec_node_many_type = {
        .name = "many",
        .parse = ec_node_many_parse,
-       .complete = ec_node_default_complete,
-//XXX  .complete = ec_node_many_complete,
+       .complete = ec_node_many_complete,
        .size = sizeof(struct ec_node_many),
        .free_priv = ec_node_many_free_priv,
 };
@@ -236,13 +265,46 @@ static int ec_node_many_testcase(void)
        ec_node_free(node);
 
        /* test completion */
-       /* XXX */
+       node = ec_node_many(NULL, ec_node_str(NULL, "foo"), 2, 4);
+       if (node == NULL) {
+               ec_log(EC_LOG_ERR, "cannot create node\n");
+               return -1;
+       }
+       ret |= EC_TEST_CHECK_COMPLETE(node,
+               "", EC_NODE_ENDLIST,
+               "foo", EC_NODE_ENDLIST,
+               "foo");
+       ret |= EC_TEST_CHECK_COMPLETE(node,
+               "f", EC_NODE_ENDLIST,
+               "oo", EC_NODE_ENDLIST,
+               "oo");
+       ret |= EC_TEST_CHECK_COMPLETE(node,
+               "foo", EC_NODE_ENDLIST,
+               "", EC_NODE_ENDLIST,
+               "");
+       ret |= EC_TEST_CHECK_COMPLETE(node,
+               "foo", "", EC_NODE_ENDLIST,
+               "foo", EC_NODE_ENDLIST,
+               "foo");
+       ret |= EC_TEST_CHECK_COMPLETE(node,
+               "foo", "foo", "", EC_NODE_ENDLIST,
+               "foo", EC_NODE_ENDLIST,
+               "foo");
+       ret |= EC_TEST_CHECK_COMPLETE(node,
+               "foo", "foo", "foo", "", EC_NODE_ENDLIST,
+               "foo", EC_NODE_ENDLIST,
+               "foo");
+       ret |= EC_TEST_CHECK_COMPLETE(node,
+               "foo", "foo", "foo", "foo", "", EC_NODE_ENDLIST,
+               EC_NODE_ENDLIST,
+               "");
+       ec_node_free(node);
 
        return ret;
 }
 
 static struct ec_test ec_node_many_test = {
-       .name = "many",
+       .name = "node_many",
        .test = ec_node_many_testcase,
 };
 
index 3142504..deb9baa 100644 (file)
@@ -87,7 +87,8 @@ ec_node_once_parse(const struct ec_node *gen_node,
 
 static struct ec_completed *
 ec_node_once_complete(const struct ec_node *gen_node,
-                       const struct ec_strvec *strvec)
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
 {
        struct ec_node_once *node = (struct ec_node_once *)gen_node;
        struct ec_completed *completed = NULL, *child_completed = NULL;
@@ -100,12 +101,11 @@ ec_node_once_complete(const struct ec_node *gen_node,
        /* count the number of occurences of the node: if already parsed,
         * do not match
         */
-       //count = count_node(ec_parsed_get_root(state), node->child); //XXX
-       count = 1;
+       count = count_node(ec_parsed_get_root(state), node->child); //XXX
        if (count > 0)
                return completed;
 
-       child_completed = ec_node_complete_strvec(node->child, strvec);
+       child_completed = ec_node_complete_child(node->child, state, strvec);
        if (child_completed == NULL)
                goto fail;
 
index 76561ee..0c72f98 100644 (file)
@@ -65,11 +65,12 @@ ec_node_option_parse(const struct ec_node *gen_node,
 
 static struct ec_completed *
 ec_node_option_complete(const struct ec_node *gen_node,
+                       struct ec_parsed *state,
                        const struct ec_strvec *strvec)
 {
        struct ec_node_option *node = (struct ec_node_option *)gen_node;
 
-       return ec_node_complete_strvec(node->child, strvec);
+       return ec_node_complete_child(node->child, state, strvec);
 }
 
 static void ec_node_option_free_priv(struct ec_node *gen_node)
index 5563a78..8925cc7 100644 (file)
@@ -67,8 +67,10 @@ ec_node_or_parse(const struct ec_node *gen_node,
        return EC_PARSED_NOMATCH;
 }
 
-static struct ec_completed *ec_node_or_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_or_complete(const struct ec_node *gen_node,
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
 {
        struct ec_node_or *node = (struct ec_node_or *)gen_node;
        struct ec_completed *completed, *child_completed;
@@ -79,8 +81,8 @@ static struct ec_completed *ec_node_or_complete(const struct ec_node *gen_node,
                return NULL;
 
        for (n = 0; n < node->len; n++) {
-               child_completed = ec_node_complete_strvec(node->table[n],
-                       strvec);
+               child_completed = ec_node_complete_child(node->table[n],
+                       state, strvec);
 
                if (child_completed == NULL) // XXX fail instead?
                        continue;
index a434363..8b7b2ee 100644 (file)
@@ -90,12 +90,12 @@ fail:
 
 static struct ec_completed *
 __ec_node_seq_complete(struct ec_node **table, size_t table_len,
-       const struct ec_strvec *strvec)
+               struct ec_parsed *state, const struct ec_strvec *strvec)
 {
        struct ec_completed *completed, *child_completed;
        struct ec_strvec *childvec = NULL;
-       struct ec_parsed *parsed;
        unsigned int i;
+       int ret;
 
        completed = ec_completed();
        if (completed == NULL)
@@ -116,41 +116,43 @@ __ec_node_seq_complete(struct ec_node **table, size_t table_len,
         */
 
        /* first, try to complete with the first node of the table */
-       child_completed = ec_node_complete_strvec(table[0], strvec);
+       child_completed = ec_node_complete_child(table[0], state, strvec);
        if (child_completed == NULL)
                goto fail;
+
        ec_completed_merge(completed, child_completed);
        child_completed = NULL;
 
-       /* then, if the node matches the beginning of the strvec, try to
-        * complete the rest */
+       /* then, if the first node of the table matches the beginning of the
+        * strvec, try to complete the rest */
        for (i = 0; i < ec_strvec_len(strvec); i++) {
                childvec = ec_strvec_ndup(strvec, 0, i);
                if (childvec == NULL)
                        goto fail;
 
-               parsed = ec_node_parse_strvec(table[0], childvec);
-               if (parsed == NULL)
+               ret = ec_node_parse_child(table[0], state, childvec);
+               if (ret < 0 && ret != EC_PARSED_NOMATCH)
                        goto fail;
 
                ec_strvec_free(childvec);
                childvec = NULL;
 
-               if (!ec_parsed_matches(parsed) || ec_parsed_len(parsed) != i) {
-                       ec_parsed_free(parsed);
-                       parsed = NULL;
+               if ((unsigned int)ret != i) {
+                       if (ret != EC_PARSED_NOMATCH)
+                               ec_parsed_del_last_child(state);
                        continue;
                }
-               ec_parsed_free(parsed);
-               parsed = NULL;
 
                childvec = ec_strvec_ndup(strvec, i, ec_strvec_len(strvec) - i);
-               if (childvec == NULL)
+               if (childvec == NULL) {
+                       ec_parsed_del_last_child(state);
                        goto fail;
+               }
 
                child_completed = __ec_node_seq_complete(&table[1],
                                                        table_len - 1,
-                                                       childvec);
+                                                       state, childvec);
+               ec_parsed_del_last_child(state);
                ec_strvec_free(childvec);
                childvec = NULL;
 
@@ -165,18 +167,19 @@ __ec_node_seq_complete(struct ec_node **table, size_t table_len,
 
 fail:
        ec_strvec_free(childvec);
-       ec_parsed_free(parsed);
        ec_completed_free(child_completed);
        ec_completed_free(completed);
        return NULL;
 }
 
-static struct ec_completed *ec_node_seq_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_seq_complete(const struct ec_node *gen_node,
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
 {
        struct ec_node_seq *node = (struct ec_node_seq *)gen_node;
 
-       return __ec_node_seq_complete(node->table, node->len, strvec);
+       return __ec_node_seq_complete(node->table, node->len, state, strvec);
 }
 
 static void ec_node_seq_free_priv(struct ec_node *gen_node)
index 7b61c52..ec15fc7 100644 (file)
@@ -279,8 +279,10 @@ ec_node_sh_lex_parse(const struct ec_node *gen_node,
        return ret;
 }
 
-static struct ec_completed *ec_node_sh_lex_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_sh_lex_complete(const struct ec_node *gen_node,
+                       struct ec_parsed *state,
+                       const struct ec_strvec *strvec)
 {
        struct ec_node_sh_lex *node = (struct ec_node_sh_lex *)gen_node;
        struct ec_completed *completed, *child_completed = NULL;
@@ -303,7 +305,7 @@ static struct ec_completed *ec_node_sh_lex_complete(const struct ec_node *gen_no
 
 //     ec_strvec_dump(new_vec, stdout);
 
-       child_completed = ec_node_complete_strvec(node->child, new_vec);
+       child_completed = ec_node_complete_child(node->child, state, new_vec);
        if (child_completed == NULL)
                goto fail;
 
index 9f2497c..011a86c 100644 (file)
@@ -65,15 +65,18 @@ ec_node_str_parse(const struct ec_node *gen_node,
        return 1;
 }
 
-static struct ec_completed *ec_node_str_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_str_complete(const struct ec_node *gen_node,
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
 {
        struct ec_node_str *node = (struct ec_node_str *)gen_node;
        struct ec_completed *completed;
-       struct ec_completed_elt *completed_elt;
        const char *str, *add;
        size_t n = 0;
 
+       (void)state;
+
        completed = ec_completed();
        if (completed == NULL)
                return NULL;
@@ -92,14 +95,11 @@ static struct ec_completed *ec_node_str_complete(const struct ec_node *gen_node,
        else
                add = node->string + n;
 
-       completed_elt = ec_completed_elt(gen_node, add);
-       if (completed_elt == NULL) {
+       if (ec_completed_add_elt(completed, gen_node, add) < 0) {
                ec_completed_free(completed);
                return NULL;
        }
 
-       ec_completed_add_elt(completed, completed_elt);
-
        return completed;
 }
 
index f1c09f8..6b5fee0 100644 (file)
@@ -115,12 +115,8 @@ __ec_node_subset_parse(struct parse_result *out, struct ec_node **table,
 
                /* if result is not the best, ignore */
                if (result.parsed_len < best_result.parsed_len) {
-                       struct ec_parsed *child_parsed;
-
                        memset(&result, 0, sizeof(result));
-                       child_parsed = ec_parsed_get_last_child(state);
-                       ec_parsed_del_child(state, child_parsed);
-                       ec_parsed_free(child_parsed);
+                       ec_parsed_del_last_child(state);
                        continue;
                }
 
@@ -179,7 +175,7 @@ ec_node_subset_parse(const struct ec_node *gen_node,
 
 static struct ec_completed *
 __ec_node_subset_complete(struct ec_node **table, size_t table_len,
-       const struct ec_strvec *strvec)
+                       struct ec_parsed *state, const struct ec_strvec *strvec)
 {
        struct ec_completed *completed = NULL;
        struct ec_completed *child_completed = NULL;
@@ -187,6 +183,7 @@ __ec_node_subset_complete(struct ec_node **table, size_t table_len,
        struct ec_parsed *parsed = NULL;
        struct ec_node *save;
        size_t i, len;
+       int ret;
 
        /*
         * example with table = [a, b, c]
@@ -206,8 +203,8 @@ __ec_node_subset_complete(struct ec_node **table, size_t table_len,
                if (table[i] == NULL)
                        continue;
 
-               child_completed = ec_node_complete_strvec(table[i],
-                       strvec);
+               child_completed = ec_node_complete_child(table[i],
+                       state, strvec);
 
                if (child_completed == NULL)
                        goto fail;
@@ -222,29 +219,28 @@ __ec_node_subset_complete(struct ec_node **table, size_t table_len,
                if (table[i] == NULL)
                        continue;
 
-               parsed = ec_node_parse_strvec(table[i], strvec);
-               if (parsed == NULL)
-                       goto fail;
-
-               if (!ec_parsed_matches(parsed)) {
-                       ec_parsed_free(parsed);
-                       parsed = NULL;
+               ret = ec_node_parse_child(table[i], state, strvec);
+               if (ret == EC_PARSED_NOMATCH)
                        continue;
-               }
+               else if (ret < 0)
+                       goto fail;
 
-               len = ec_parsed_len(parsed);
+               len = ret;
                childvec = ec_strvec_ndup(strvec, len,
                                        ec_strvec_len(strvec) - len);
-               if (childvec == NULL)
+               if (childvec == NULL) {
+                       ec_parsed_del_last_child(state);
                        goto fail;
+               }
 
                save = table[i];
                table[i] = NULL;
-               child_completed = __ec_node_subset_complete(table,
-                                                       table_len, childvec);
+               child_completed = __ec_node_subset_complete(table, table_len,
+                                                       state, childvec);
                table[i] = save;
                ec_strvec_free(childvec);
                childvec = NULL;
+               ec_parsed_del_last_child(state);
 
                if (child_completed == NULL)
                        goto fail;
@@ -265,12 +261,14 @@ fail:
        return NULL;
 }
 
-static struct ec_completed *ec_node_subset_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_subset_complete(const struct ec_node *gen_node,
+                       struct ec_parsed *state,
+                       const struct ec_strvec *strvec)
 {
        struct ec_node_subset *node = (struct ec_node_subset *)gen_node;
 
-       return __ec_node_subset_complete(node->table, node->len, strvec);
+       return __ec_node_subset_complete(node->table, node->len, state, strvec);
 }
 
 static void ec_node_subset_free_priv(struct ec_node *gen_node)
index 063ae4d..9ad52fb 100644 (file)
@@ -60,11 +60,12 @@ ec_node_weakref_parse(const struct ec_node *gen_node,
 
 static struct ec_completed *
 ec_node_weakref_complete(const struct ec_node *gen_node,
+                       struct ec_parsed *state,
                        const struct ec_strvec *strvec)
 {
        struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
 
-       return ec_node_complete_strvec(node->child, strvec);
+       return ec_node_complete_child(node->child, state, strvec);
 }
 
 static struct ec_node_type ec_node_weakref_type = {
index 38f42b8..140edea 100644 (file)
@@ -64,6 +64,7 @@ int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
        if (child == NULL)
                return -ENOMEM;
 
+       child->node = node;
        ec_parsed_add_child(state, child);
        ret = node->type->parse(node, child, strvec);
        if (ret == EC_PARSED_NOMATCH) {
@@ -79,7 +80,6 @@ int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
        if (match_strvec == NULL)
                return -ENOMEM;
 
-       child->node = node;
        child->strvec = match_strvec;
 
        return ret;
@@ -198,17 +198,21 @@ static void __ec_parsed_dump(FILE *out,
                        fprintf(out, "|");
        }
 
-       fprintf(out, "node_type=%s id=%s vec=[", typename, id);
+       fprintf(out, "node_type=%s id=%s vec=", typename, id);
        vec = ec_parsed_strvec(parsed);
-       for (i = 0; i < ec_strvec_len(vec); i++)
-               fprintf(out, "%s<%s>",
-                       i == 0 ? "" : ",",
-                       ec_strvec_val(vec, i));
-       // XXX
-       if (!strcmp(typename, "int") || !strcmp(typename, "str"))
-               fprintf(out, "] <<<<<\n");
-       else
-               fprintf(out, "]\n");
+       if (vec == NULL) {
+               fprintf(out, "none\n");
+       } else {
+               for (i = 0; i < ec_strvec_len(vec); i++)
+                       fprintf(out, "%s<%s>",
+                               i == 0 ? "" : ",",
+                               ec_strvec_val(vec, i));
+               // XXX
+               if (!strcmp(typename, "int") || !strcmp(typename, "str"))
+                       fprintf(out, "] <<<<<\n");
+               else
+                       fprintf(out, "]\n");
+       }
 
        TAILQ_FOREACH(child, &parsed->children, next)
                __ec_parsed_dump(out, child, indent + 2);
@@ -250,6 +254,15 @@ ec_parsed_get_last_child(struct ec_parsed *parsed)
        return TAILQ_LAST(&parsed->children, ec_parsed_list);
 }
 
+void ec_parsed_del_last_child(struct ec_parsed *parsed)
+{
+       struct ec_parsed *child;
+
+       child = ec_parsed_get_last_child(parsed);
+       ec_parsed_del_child(parsed, child);
+       ec_parsed_free(child);
+}
+
 struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
 {
        if (parsed == NULL)
index dbef739..1ebea9e 100644 (file)
@@ -66,8 +66,17 @@ struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
                                const struct ec_strvec *strvec);
 
 #define EC_PARSED_NOMATCH INT_MIN
-/* internal: used by nodes */
-/* return:
+/* internal: used by nodes
+ *
+ * state is the current parse tree, which is built bit by bit while
+ *   parsing the node tree: ec_node_parse_child() creates a new child in
+ *   this state parse tree, and calls the parse() method for the child
+ *   node, with state pointing to this new child. If it does not match,
+ *   the child is removed in the state, else it is kept, with its
+ *   possible descendants.
+ *
+ * return:
+ * XXX change EC_PARSED_NOMATCH to INT_MAX?
  * EC_PARSED_NOMATCH (negative) if it does not match
  * any other negative value (-errno) for other errors
  * the number of matched strings in strvec
@@ -82,12 +91,13 @@ void ec_parsed_del_child(struct ec_parsed *parsed,
                        struct ec_parsed *child);
 struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed);
 struct ec_parsed *ec_parsed_get_last_child(struct ec_parsed *parsed);
+void ec_parsed_del_last_child(struct ec_parsed *parsed);
+
 void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed);
 
 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
        const char *id);
 
-const char *ec_parsed_to_string(const struct ec_parsed *parsed);
 size_t ec_parsed_len(const struct ec_parsed *parsed);
 size_t ec_parsed_matches(const struct ec_parsed *parsed);
 
index 1d64402..9d898ff 100644 (file)
@@ -45,6 +45,8 @@
 #include <ecoli_node_int.h>
 #include <ecoli_node_option.h>
 #include <ecoli_node_cmd.h>
+#include <ecoli_node_many.h>
+#include <ecoli_node_once.h>
 
 static struct ec_node *commands;
 
@@ -234,6 +236,24 @@ static int create_commands(void)
                goto fail;
 
 
+       cmd = EC_NODE_CMD(NULL, "sell vegetable",
+                       ec_node_many("vegetable",
+                               EC_NODE_OR(NULL,
+                                       ec_node_once(NULL,
+                                               ec_node_str(NULL, "potatoes")),
+                                       ec_node_once(NULL,
+                                               ec_node_str(NULL, "carrots")),
+                                       ec_node_once(NULL,
+                                               ec_node_str(NULL, "pumpkins"))),
+                       1, 0));
+       if (cmd == NULL)
+               goto fail;
+       ec_keyval_set(ec_node_attrs(cmd), "help",
+               "sell vegetables", NULL);
+       if (ec_node_or_add(cmdlist, cmd) < 0)
+               goto fail;
+
+
        cmd = EC_NODE_SEQ(NULL,
                ec_node_str(NULL, "bye")
        );
index 40e0e62..c34e104 100644 (file)
@@ -30,7 +30,7 @@ X rename:
   - ec_completed_tk -> ec_completed
   - tk, gen_tk, token, ... -> node
   - tokens -> input_str / input_strvec ?
-- use is_err() for errno in ptrs
+- use is_err() or errno for funcs returning ptrs
 
 dependencies
 ============
@@ -104,6 +104,7 @@ new nodes
 - ether, ip, network
 - fusion node: need to match several children, same for completion
 - float
+- not
 
 encoding
 ========