change parse api
authorOlivier Matz <zer0@droids-corp.org>
Mon, 17 Jul 2017 19:49:06 +0000 (21:49 +0200)
committerOlivier Matz <zer0@droids-corp.org>
Mon, 17 Jul 2017 19:49:06 +0000 (21:49 +0200)
22 files changed:
lib/ecoli_completed.c
lib/ecoli_node.h
lib/ecoli_node_cmd.c
lib/ecoli_node_empty.c
lib/ecoli_node_expr.c
lib/ecoli_node_int.c
lib/ecoli_node_many.c
lib/ecoli_node_option.c
lib/ecoli_node_or.c
lib/ecoli_node_re.c
lib/ecoli_node_re_lex.c
lib/ecoli_node_seq.c
lib/ecoli_node_sh_lex.c
lib/ecoli_node_space.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/ecoli_test.c
lib/main-readline.c
lib/todo.txt

index 8ef14d5..8a34c74 100644 (file)
@@ -154,7 +154,20 @@ struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
                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 */
index 27a52c8..9115ebc 100644 (file)
@@ -40,17 +40,6 @@ struct ec_completed;
 struct ec_strvec;
 struct ec_keyval;
 
-/* return 0 on success, else -errno. */
-typedef int (*ec_node_build_t)(struct ec_node *node);
-
-typedef struct ec_parsed *(*ec_node_parse_t)(const struct ec_node *node,
-       const struct ec_strvec *strvec);
-typedef struct ec_completed *(*ec_node_complete_t)(const struct ec_node *node,
-       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 *);
-typedef void (*ec_node_free_priv_t)(struct ec_node *);
-
 #define EC_NODE_TYPE_REGISTER(t)                                               \
        static void ec_node_init_##t(void);                             \
        static void __attribute__((constructor, used))                  \
@@ -62,6 +51,18 @@ typedef void (*ec_node_free_priv_t)(struct ec_node *);
 
 TAILQ_HEAD(ec_node_type_list, ec_node_type);
 
+/* return 0 on success, else -errno. */
+typedef int (*ec_node_build_t)(struct ec_node *node);
+
+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,
+                                               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 *);
+typedef void (*ec_node_free_priv_t)(struct ec_node *);
+
 /**
  * A structure describing a node type.
  */
index 9a6c4eb..8cf76ab 100644 (file)
@@ -236,12 +236,13 @@ static const struct ec_node_expr_eval_ops test_ops = {
        .eval_free = ec_node_cmd_eval_free,
 };
 
-static struct ec_parsed *ec_node_cmd_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int ec_node_cmd_parse(const struct ec_node *gen_node,
+                       struct ec_parsed *state,
+                       const struct ec_strvec *strvec)
 {
        struct ec_node_cmd *node = (struct ec_node_cmd *)gen_node;
 
-       return ec_node_parse_strvec(node->cmd, strvec);
+       return ec_node_parse_child(node->cmd, state, strvec);
 }
 
 static struct ec_completed *ec_node_cmd_complete(const struct ec_node *gen_node,
index e52956e..6a6ed61 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 #include <ecoli_malloc.h>
 #include <ecoli_log.h>
@@ -42,29 +43,14 @@ struct ec_node_empty {
        struct ec_node gen;
 };
 
-static struct ec_parsed *ec_node_empty_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int ec_node_empty_parse(const struct ec_node *gen_node,
+                       struct ec_parsed *state,
+                       const struct ec_strvec *strvec)
 {
-       struct ec_parsed *parsed;
-       struct ec_strvec *match_strvec;
-
+       (void)gen_node;
+       (void)state;
        (void)strvec;
-
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
-
-       match_strvec = ec_strvec();
-       if (match_strvec == NULL)
-               goto fail;
-
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
-
- fail:
-       ec_parsed_free(parsed);
-       return NULL;
+       return 0;
 }
 
 static struct ec_node_type ec_node_empty_type = {
index c158834..5aa8a2e 100644 (file)
@@ -66,12 +66,13 @@ 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);
+       return ec_node_parse_child(node->child, state, strvec);
 }
 
 static struct ec_completed *ec_node_expr_complete(const struct ec_node *gen_node,
index bf73a13..2ba1b28 100644 (file)
@@ -77,37 +77,24 @@ static int parse_llint(struct ec_node_int *node, const char *str,
        return 0;
 }
 
-static struct ec_parsed *ec_node_int_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int ec_node_int_parse(const struct ec_node *gen_node,
+                       struct ec_parsed *state,
+                       const struct ec_strvec *strvec)
 {
        struct ec_node_int *node = (struct ec_node_int *)gen_node;
-       struct ec_parsed *parsed;
-       struct ec_strvec *match_strvec;
        const char *str;
        long long val;
 
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
+       (void)state;
 
        if (ec_strvec_len(strvec) == 0)
-               return parsed;
+               return EC_PARSED_NOMATCH;
 
        str = ec_strvec_val(strvec, 0);
        if (parse_llint(node, str, &val) < 0)
-               return parsed;
+               return EC_PARSED_NOMATCH;
 
-       match_strvec = ec_strvec_ndup(strvec, 0, 1);
-       if (match_strvec == NULL)
-               goto fail;
-
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
-
- fail:
-       ec_parsed_free(parsed);
-       return NULL;
+       return 1;
 }
 
 static struct ec_node_type ec_node_int_type = {
index b5dff92..f0843b1 100644 (file)
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <assert.h>
 #include <stdarg.h>
+#include <errno.h>
 
 #include <ecoli_malloc.h>
 #include <ecoli_log.h>
@@ -49,66 +50,54 @@ struct ec_node_many {
        struct ec_node *child;
 };
 
-static struct ec_parsed *ec_node_many_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int ec_node_many_parse(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;
-       struct ec_parsed *parsed, *child_parsed;
-       struct ec_strvec *match_strvec;
+       struct ec_parsed *child_parsed;
        struct ec_strvec *childvec = NULL;
-       size_t off = 0, len, count;
-
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
+       size_t off = 0, count;
+       int ret;
 
        for (count = 0; node->max == 0 || count < node->max; count++) {
                childvec = ec_strvec_ndup(strvec, off,
                        ec_strvec_len(strvec) - off);
-               if (childvec == NULL)
-                       goto fail;
-
-               child_parsed = ec_node_parse_strvec(node->child, childvec);
-               if (child_parsed == NULL)
+               if (childvec == NULL) {
+                       ret = -ENOMEM;
                        goto fail;
+               }
 
+               ret = ec_node_parse_child(node->child, state, childvec);
                ec_strvec_free(childvec);
                childvec = NULL;
 
-               if (!ec_parsed_matches(child_parsed)) {
-                       ec_parsed_free(child_parsed);
+               if (ret == EC_PARSED_NOMATCH)
                        break;
-               }
-
-               ec_parsed_add_child(parsed, child_parsed);
+               else if (ret < 0)
+                       goto fail;
 
                /* it matches an empty strvec, no need to continue */
-               len = ec_parsed_len(child_parsed);
-               if (len == 0) {
+               if (ret == 0) {
+                       child_parsed = ec_parsed_get_last_child(state);
+                       ec_parsed_del_child(state, child_parsed);
                        ec_parsed_free(child_parsed);
                        break;
                }
 
-               off += len;
+               off += ret;
        }
 
        if (count < node->min) {
-               ec_parsed_free_children(parsed);
-               return parsed;
+               ec_parsed_free_children(state);
+               return EC_PARSED_NOMATCH;
        }
 
-       match_strvec = ec_strvec_ndup(strvec, 0, off);
-       if (match_strvec == NULL)
-               goto fail;
-
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
+       return off;
 
 fail:
        ec_strvec_free(childvec);
-       ec_parsed_free(parsed);
-       return NULL;
+       return ret;
 }
 
 #if 0 //XXX missing node_many_complete
index 305734f..76561ee 100644 (file)
@@ -46,43 +46,26 @@ struct ec_node_option {
        struct ec_node *child;
 };
 
-static struct ec_parsed *ec_node_option_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_option_parse(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;
-       struct ec_parsed *parsed = NULL, *child_parsed;
-       struct ec_strvec *match_strvec;
-
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
-
-       child_parsed = ec_node_parse_strvec(node->child, strvec);
-       if (child_parsed == NULL)
-               goto fail;
-
-       if (ec_parsed_matches(child_parsed)) {
-               ec_parsed_add_child(parsed, child_parsed);
-               match_strvec = ec_strvec_dup(child_parsed->strvec);
-       } else {
-               ec_parsed_free(child_parsed);
-               match_strvec = ec_strvec();
-       }
-
-       if (match_strvec == NULL)
-               goto fail;
+       int ret;
 
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
+       ret = ec_node_parse_child(node->child, state, strvec);
+       if (ret == EC_PARSED_NOMATCH)
+               return 0;
+       else if (ret < 0)
+               return ret;
 
-       return parsed;
-
- fail:
-       ec_parsed_free(parsed);
-       return NULL;
+       return ret;
 }
 
-static struct ec_completed *ec_node_option_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_option_complete(const struct ec_node *gen_node,
+                       const struct ec_strvec *strvec)
 {
        struct ec_node_option *node = (struct ec_node_option *)gen_node;
 
index a4df91f..5563a78 100644 (file)
@@ -48,45 +48,23 @@ struct ec_node_or {
        unsigned int len;
 };
 
-static struct ec_parsed *ec_node_or_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_or_parse(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_parsed *parsed, *child_parsed = NULL;
-       struct ec_strvec *match_strvec;
        unsigned int i;
-
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
+       int ret;
 
        for (i = 0; i < node->len; i++) {
-               child_parsed = ec_node_parse_strvec(node->table[i], strvec);
-               if (child_parsed == NULL)
-                       goto fail;
-               if (ec_parsed_matches(child_parsed))
-                       break;
-               ec_parsed_free(child_parsed);
-               child_parsed = NULL;
+               ret = ec_node_parse_child(node->table[i], state, strvec);
+               if (ret == EC_PARSED_NOMATCH)
+                       continue;
+               return ret;
        }
 
-       /* no match */
-       if (i == node->len)
-               return parsed;
-
-       match_strvec = ec_strvec_dup(child_parsed->strvec);
-       if (match_strvec == NULL)
-               goto fail;
-
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-       ec_parsed_add_child(parsed, child_parsed);
-
-       return parsed;
-
- fail:
-       ec_parsed_free(child_parsed);
-       ec_parsed_free(parsed);
-       return NULL;
+       return EC_PARSED_NOMATCH;
 }
 
 static struct ec_completed *ec_node_or_complete(const struct ec_node *gen_node,
index 3d2a064..63e2d3e 100644 (file)
@@ -46,39 +46,27 @@ struct ec_node_re {
        regex_t re;
 };
 
-static struct ec_parsed *ec_node_re_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_re_parse(const struct ec_node *gen_node,
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
 {
        struct ec_node_re *node = (struct ec_node_re *)gen_node;
-       struct ec_strvec *match_strvec;
-       struct ec_parsed *parsed = NULL;
        const char *str;
        regmatch_t pos;
 
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
+       (void)state;
 
        if (ec_strvec_len(strvec) == 0)
-               return parsed;
+               return EC_PARSED_NOMATCH;
 
        str = ec_strvec_val(strvec, 0);
        if (regexec(&node->re, str, 1, &pos, 0) != 0)
-               return parsed;
+               return EC_PARSED_NOMATCH;
        if (pos.rm_so != 0 || pos.rm_eo != (int)strlen(str))
-               return parsed;
-
-       match_strvec = ec_strvec_ndup(strvec, 0, 1);
-       if (match_strvec == NULL)
-               goto fail;
+               return EC_PARSED_NOMATCH;
 
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
-
- fail:
-       ec_parsed_free(parsed);
-       return NULL;
+       return 1;
 }
 
 static void ec_node_re_free_priv(struct ec_node *gen_node)
index e9e3ace..c4d5104 100644 (file)
@@ -88,55 +88,48 @@ fail:
        return NULL;
 }
 
-static struct ec_parsed *ec_node_re_lex_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_re_lex_parse(const struct ec_node *gen_node,
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
 {
        struct ec_node_re_lex *node = (struct ec_node_re_lex *)gen_node;
-       struct ec_strvec *new_vec = NULL, *match_strvec;
-       struct ec_parsed *parsed = NULL, *child_parsed;
+       struct ec_strvec *new_vec = NULL;
+       struct ec_parsed *child_parsed;
        const char *str;
+       int ret;
 
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               return NULL;
-
-       if (ec_strvec_len(strvec) == 0)
-               return parsed;
-
-       str = ec_strvec_val(strvec, 0);
-       new_vec = tokenize(node->table, node->len, str);
-       if (new_vec == NULL)
-               goto fail;
-
-       printf("--------\n");
-       ec_strvec_dump(stdout, new_vec);
-       child_parsed = ec_node_parse_strvec(node->child, new_vec);
-       if (child_parsed == NULL)
+       if (ec_strvec_len(strvec) == 0) {
+               new_vec = ec_strvec();
+       } else {
+               str = ec_strvec_val(strvec, 0);
+               new_vec = tokenize(node->table, node->len, str);
+       }
+       if (new_vec == NULL) {
+               ret = -ENOMEM;
                goto fail;
+       }
 
-       if (!ec_parsed_matches(child_parsed) ||
-                       ec_parsed_len(child_parsed) !=
-                               ec_strvec_len(new_vec)) {
-               ec_strvec_free(new_vec);
-               ec_parsed_free(child_parsed);
-               return parsed;
+       ret = ec_node_parse_child(node->child, state, new_vec);
+       if (ret >= 0) {
+               if ((unsigned)ret == ec_strvec_len(new_vec)) {
+                       ret = 1;
+               } else {
+                       child_parsed = ec_parsed_get_last_child(state);
+                       ec_parsed_del_child(state, child_parsed);
+                       ec_parsed_free(child_parsed);
+                       ret = EC_PARSED_NOMATCH;
+               }
        }
+
        ec_strvec_free(new_vec);
        new_vec = NULL;
 
-       ec_parsed_add_child(parsed, child_parsed);
-       match_strvec = ec_strvec_ndup(strvec, 0, 1);
-       if (match_strvec == NULL)
-               goto fail;
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
+       return ret;
 
  fail:
        ec_strvec_free(new_vec);
-       ec_parsed_free(parsed);
-
-       return NULL;
+       return ret;
 }
 
 static void ec_node_re_lex_free_priv(struct ec_node *gen_node)
index 76258d3..a434363 100644 (file)
@@ -49,56 +49,43 @@ struct ec_node_seq {
        unsigned int len;
 };
 
-static struct ec_parsed *ec_node_seq_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_seq_parse(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;
-       struct ec_parsed *parsed, *child_parsed;
-       struct ec_strvec *match_strvec;
        struct ec_strvec *childvec = NULL;
        size_t len = 0;
        unsigned int i;
-
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
+       int ret;
 
        for (i = 0; i < node->len; i++) {
                childvec = ec_strvec_ndup(strvec, len,
                        ec_strvec_len(strvec) - len);
-               if (childvec == NULL)
-                       goto fail;
-
-               child_parsed = ec_node_parse_strvec(node->table[i], childvec);
-               if (child_parsed == NULL)
+               if (childvec == NULL) {
+                       ret = -ENOMEM;
                        goto fail;
+               }
 
+               ret = ec_node_parse_child(node->table[i], state, childvec);
                ec_strvec_free(childvec);
                childvec = NULL;
-
-               if (!ec_parsed_matches(child_parsed)) {
-                       ec_parsed_free(child_parsed);
-                       // XXX ec_parsed_free_children needed? see subset.c
-                       ec_parsed_free_children(parsed);
-                       return parsed;
+               if (ret == EC_PARSED_NOMATCH) {
+                       ec_parsed_free_children(state);
+                       return EC_PARSED_NOMATCH;
+               } else if (ret < 0) {
+                       goto fail;
                }
 
-               ec_parsed_add_child(parsed, child_parsed);
-               len += ec_parsed_len(child_parsed);
+               len += ret;
        }
 
-       match_strvec = ec_strvec_ndup(strvec, 0, len);
-       if (match_strvec == NULL)
-               goto fail;
-
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
+       return len;
 
 fail:
        ec_strvec_free(childvec);
-       ec_parsed_free(parsed);
-       return NULL;
+       return ret;
 }
 
 static struct ec_completed *
index b92af1f..7b61c52 100644 (file)
@@ -235,53 +235,48 @@ static struct ec_strvec *tokenize(const char *str, int completion,
        return NULL;
 }
 
-static struct ec_parsed *ec_node_sh_lex_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_sh_lex_parse(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_strvec *new_vec = NULL, *match_strvec;
-       struct ec_parsed *parsed = NULL, *child_parsed;
+       struct ec_strvec *new_vec = NULL;
+       struct ec_parsed *child_parsed;
        const char *str;
+       int ret;
 
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               return NULL;
-
-       if (ec_strvec_len(strvec) == 0)
-               return parsed;
-
-       str = ec_strvec_val(strvec, 0);
-       new_vec = tokenize(str, 0, 0, NULL);
-       if (new_vec == NULL)
-               goto fail;
-
-       child_parsed = ec_node_parse_strvec(node->child, new_vec);
-       if (child_parsed == NULL)
+       if (ec_strvec_len(strvec) == 0) {
+               new_vec = ec_strvec();
+       } else {
+               str = ec_strvec_val(strvec, 0);
+               new_vec = tokenize(str, 0, 0, NULL);
+       }
+       if (new_vec == NULL) {
+               ret = -ENOMEM;
                goto fail;
+       }
 
-       if (!ec_parsed_matches(child_parsed) ||
-                       ec_parsed_len(child_parsed) !=
-                               ec_strvec_len(new_vec)) {
-               ec_strvec_free(new_vec);
-               ec_parsed_free(child_parsed);
-               return parsed;
+       ret = ec_node_parse_child(node->child, state, new_vec);
+       if (ret >= 0) {
+               if ((unsigned)ret == ec_strvec_len(new_vec)) {
+                       ret = 1;
+               } else {
+                       child_parsed = ec_parsed_get_last_child(state);
+                       ec_parsed_del_child(state, child_parsed);
+                       ec_parsed_free(child_parsed);
+                       ret = EC_PARSED_NOMATCH;
+               }
        }
+
        ec_strvec_free(new_vec);
        new_vec = NULL;
 
-       ec_parsed_add_child(parsed, child_parsed);
-       match_strvec = ec_strvec_ndup(strvec, 0, 1);
-       if (match_strvec == NULL)
-               goto fail;
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
+       return ret;
 
  fail:
        ec_strvec_free(new_vec);
-       ec_parsed_free(parsed);
-
-       return NULL;
+       return ret;
 }
 
 static struct ec_completed *ec_node_sh_lex_complete(const struct ec_node *gen_node,
index be14348..265cc9b 100644 (file)
@@ -43,38 +43,27 @@ struct ec_node_space {
        struct ec_node gen;
 };
 
-static struct ec_parsed *ec_node_space_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_space_parse(const struct ec_node *gen_node,
+               struct ec_parsed *state,
+               const struct ec_strvec *strvec)
 {
-       struct ec_parsed *parsed = NULL;
-       struct ec_strvec *match_strvec;
        const char *str;
        size_t len = 0;
 
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
+       (void)state;
+       (void)gen_node;
 
        if (ec_strvec_len(strvec) == 0)
-               return parsed;
+               return EC_PARSED_NOMATCH;
 
        str = ec_strvec_val(strvec, 0);
        while (isspace(str[len]))
                len++;
        if (len == 0 || len != strlen(str))
-               return parsed;
+               return EC_PARSED_NOMATCH;
 
-       match_strvec = ec_strvec_ndup(strvec, 0, 1);
-       if (match_strvec == NULL)
-               goto fail;
-
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
-
- fail:
-       ec_parsed_free(parsed);
-       return NULL;
+       return 1;
 }
 
 static struct ec_node_type ec_node_space_type = {
index fe8c7bb..9f2497c 100644 (file)
@@ -45,36 +45,24 @@ struct ec_node_str {
        unsigned len;
 };
 
-static struct ec_parsed *ec_node_str_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_str_parse(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_strvec *match_strvec;
-       struct ec_parsed *parsed = NULL;
        const char *str;
 
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
+       (void)state;
 
        if (ec_strvec_len(strvec) == 0)
-               return parsed;
+               return EC_PARSED_NOMATCH;
 
        str = ec_strvec_val(strvec, 0);
        if (strcmp(str, node->string) != 0)
-               return parsed;
-
-       match_strvec = ec_strvec_ndup(strvec, 0, 1);
-       if (match_strvec == NULL)
-               goto fail;
+               return EC_PARSED_NOMATCH;
 
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
-
-       return parsed;
-
- fail:
-       ec_parsed_free(parsed);
-       return NULL;
+       return 1;
 }
 
 static struct ec_completed *ec_node_str_complete(const struct ec_node *gen_node,
index 48319e6..f1c09f8 100644 (file)
@@ -51,46 +51,42 @@ struct ec_node_subset {
 };
 
 struct parse_result {
-       struct ec_parsed **parsed_table; /* list of parsed node */
-       size_t parsed_table_len;         /* number of parsed node */
-       size_t len;                      /* consumed strings */
+       size_t parsed_len;          /* number of parsed node */
+       size_t len;                 /* consumed strings */
 };
 
-static int __ec_node_subset_parse(struct ec_node **table, size_t table_len,
-                               const struct ec_strvec *strvec,
-                               struct parse_result *out)
+/* recursively find the longest list of nodes that matches: the state is
+ * updated accordingly. */
+static int
+__ec_node_subset_parse(struct parse_result *out, struct ec_node **table,
+               size_t table_len, struct ec_parsed *state,
+               const struct ec_strvec *strvec)
 {
        struct ec_node **child_table;
-       struct ec_parsed *child_parsed = NULL;
        struct ec_strvec *childvec = NULL;
        size_t i, j, len = 0;
        struct parse_result best_result, result;
+       struct ec_parsed *best_parsed = NULL;
        int ret;
 
        if (table_len == 0)
                return 0;
 
        memset(&best_result, 0, sizeof(best_result));
-       best_result.parsed_table =
-               ec_calloc(table_len, sizeof(*best_result.parsed_table[0]));
-       if (best_result.parsed_table == NULL)
-               goto fail;
 
        child_table = ec_calloc(table_len - 1, sizeof(*child_table));
-       if (child_table == NULL)
+       if (child_table == NULL) {
+               ret = -ENOMEM;
                goto fail;
+       }
 
        for (i = 0; i < table_len; i++) {
                /* try to parse elt i */
-               child_parsed = ec_node_parse_strvec(table[i], strvec);
-               if (child_parsed == NULL)
-                       goto fail;
-
-               if (!ec_parsed_matches(child_parsed)) {
-                       ec_parsed_free(child_parsed);
-                       child_parsed = NULL;
+               ret = ec_node_parse_child(table[i], state, strvec);
+               if (ret == EC_PARSED_NOMATCH)
                        continue;
-               }
+               else if (ret < 0)
+                       goto fail;
 
                /* build a new table without elt i */
                for (j = 0; j < table_len; j++) {
@@ -100,113 +96,85 @@ static int __ec_node_subset_parse(struct ec_node **table, size_t table_len,
                                child_table[j - 1] = table[j];
                }
 
-               /* build a new strvec */
-               len = ec_parsed_len(child_parsed);
+               /* build a new strvec (ret is the len of matched strvec) */
+               len = ret;
                childvec = ec_strvec_ndup(strvec, len,
                                        ec_strvec_len(strvec) - len);
-               if (childvec == NULL)
+               if (childvec == NULL) {
+                       ret = -ENOMEM;
                        goto fail;
+               }
 
                memset(&result, 0, sizeof(result));
-
-               ret = __ec_node_subset_parse(child_table, table_len - 1,
-                                       childvec, &result);
+               ret = __ec_node_subset_parse(&result, child_table,
+                                       table_len - 1, state, childvec);
                ec_strvec_free(childvec);
                childvec = NULL;
                if (ret < 0)
                        goto fail;
 
                /* if result is not the best, ignore */
-               if (result.parsed_table_len + 1 <=
-                               best_result.parsed_table_len) {
-                       ec_parsed_free(child_parsed);
-                       child_parsed = NULL;
-                       for (j = 0; j < result.parsed_table_len; j++)
-                               ec_parsed_free(result.parsed_table[j]);
-                       ec_free(result.parsed_table);
+               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);
                        continue;
                }
 
                /* replace the previous best result */
-               for (j = 0; j < best_result.parsed_table_len; j++)
-                       ec_parsed_free(best_result.parsed_table[j]);
-               best_result.parsed_table[0] = child_parsed;
-               child_parsed = NULL;
-               for (j = 0; j < result.parsed_table_len; j++)
-                       best_result.parsed_table[j+1] = result.parsed_table[j];
-               best_result.parsed_table_len = result.parsed_table_len + 1;
+               ec_parsed_free(best_parsed);
+               best_parsed = ec_parsed_get_last_child(state);
+               ec_parsed_del_child(state, best_parsed);
+
+               best_result.parsed_len = result.parsed_len + 1;
                best_result.len = len + result.len;
-               ec_free(result.parsed_table);
+
+               memset(&result, 0, sizeof(result));
        }
 
        *out = best_result;
        ec_free(child_table);
+       if (best_parsed != NULL)
+               ec_parsed_add_child(state, best_parsed);
 
        return 0;
 
  fail:
-       ec_parsed_free(child_parsed);
+       ec_parsed_free(best_parsed);
        ec_strvec_free(childvec);
-       for (j = 0; j < best_result.parsed_table_len; j++)
-               ec_parsed_free(best_result.parsed_table[j]);
-       ec_free(best_result.parsed_table);
        ec_free(child_table);
-       return -1;
+       return ret;
 }
 
-static struct ec_parsed *ec_node_subset_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_subset_parse(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;
        struct ec_parsed *parsed = NULL;
        struct parse_result result;
-       struct ec_strvec *match_strvec;
-       size_t i;
        int ret;
 
        memset(&result, 0, sizeof(result));
 
-       parsed = ec_parsed();
-       if (parsed == NULL)
-               goto fail;
-
-       ret = __ec_node_subset_parse(node->table, node->len, strvec, &result);
+       ret = __ec_node_subset_parse(&result, node->table,
+                               node->len, state, strvec);
        if (ret < 0)
                goto fail;
 
        /* if no child node matches, return a matching empty strvec */
-       if (result.parsed_table_len == 0) {
-               ec_free(result.parsed_table);
-               match_strvec = ec_strvec();
-               if (match_strvec == NULL)
-                       goto fail;
-               ec_parsed_set_match(parsed, gen_node, match_strvec);
-               return parsed;
-       }
-
-       for (i = 0; i < result.parsed_table_len; i++) {
-               ec_parsed_add_child(parsed, result.parsed_table[i]);
-               result.parsed_table[i] = NULL;
-       }
-       ec_free(result.parsed_table);
-       result.parsed_table = NULL;
-
-       match_strvec = ec_strvec_ndup(strvec, 0, result.len);
-       if (match_strvec == NULL)
-               goto fail;
-
-       ec_parsed_set_match(parsed, gen_node, match_strvec);
+       if (result.parsed_len == 0)
+               return 0;
 
-       return parsed;
+       return result.len;
 
  fail:
-       for (i = 0; i < result.parsed_table_len; i++)
-               ec_parsed_free(result.parsed_table[i]);
-       ec_free(result.parsed_table);
        ec_parsed_free(parsed);
-
-       return NULL;
+       return ret;
 }
 
 static struct ec_completed *
index 603f02d..b496fcc 100644 (file)
@@ -48,16 +48,19 @@ struct ec_node_weakref {
        struct ec_node *child;
 };
 
-static struct ec_parsed *ec_node_weakref_parse(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static int
+ec_node_weakref_parse(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_parse_strvec(node->child, strvec);
+       return ec_node_parse_child(node->child, state, strvec);
 }
 
-static struct ec_completed *ec_node_weakref_complete(const struct ec_node *gen_node,
-       const struct ec_strvec *strvec)
+static struct ec_completed *
+ec_node_weakref_complete(const struct ec_node *gen_node,
+                       const struct ec_strvec *strvec)
 {
        struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
 
index 93d5325..38f42b8 100644 (file)
 #include <ecoli_node.h>
 #include <ecoli_parsed.h>
 
+int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
+                       const struct ec_strvec *strvec)
+{
+       struct ec_strvec *match_strvec;
+       struct ec_parsed *child;
+       int ret;
+
+       assert(state != NULL);
+
+       /* 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)
+                               return ret;
+               }
+       }
+       node->flags |= EC_NODE_F_BUILT;
+
+       if (node->type->parse == NULL)
+               return -ENOTSUP;
+
+       child = ec_parsed();
+       if (child == NULL)
+               return -ENOMEM;
+
+       ec_parsed_add_child(state, child);
+       ret = node->type->parse(node, child, strvec);
+       if (ret == EC_PARSED_NOMATCH) {
+               ec_parsed_del_child(state, child);
+               assert(TAILQ_EMPTY(&child->children));
+               ec_parsed_free(child);
+               return ret;
+       } else if (ret < 0) {
+               return ret;
+       }
+
+       match_strvec = ec_strvec_ndup(strvec, 0, ret);
+       if (match_strvec == NULL)
+               return -ENOMEM;
+
+       child->node = node;
+       child->strvec = match_strvec;
+
+       return ret;
+}
+
+struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
+                               const struct ec_strvec *strvec)
+{
+       struct ec_parsed *parsed = ec_parsed();
+       struct ec_parsed *child_parsed;
+       int ret;
+
+       if (parsed == NULL)
+               return NULL;
+
+       ret = ec_node_parse_child(node, parsed, strvec);
+       if (ret < 0 && ret != EC_PARSED_NOMATCH) {
+               ec_parsed_free(parsed);
+               parsed = NULL;
+       } else if (ret != EC_PARSED_NOMATCH) {
+               /* remove dummy root node */
+               child_parsed = ec_parsed_get_last_child(parsed);
+               ec_parsed_del_child(parsed, child_parsed);
+               ec_parsed_free(parsed);
+               parsed = child_parsed;
+       }
+
+       return parsed;
+}
+
 struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str)
 {
        struct ec_strvec *strvec = NULL;
-       struct ec_parsed *parsed;
+       struct ec_parsed *parsed = NULL;
 
        errno = ENOMEM;
        strvec = ec_strvec();
@@ -60,38 +132,10 @@ struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str)
 
  fail:
        ec_strvec_free(strvec);
+       ec_parsed_free(parsed);
        return NULL;
 }
 
-struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
-       const struct ec_strvec *strvec)
-{
-       struct ec_parsed *parsed;
-       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->parse == NULL) {
-               errno = ENOTSUP;
-               return NULL;
-       }
-
-       parsed = node->type->parse(node, strvec);
-
-       return parsed;
-}
-
-
 struct ec_parsed *ec_parsed(void)
 {
        struct ec_parsed *parsed = NULL;
@@ -108,13 +152,6 @@ struct ec_parsed *ec_parsed(void)
        return NULL;
 }
 
-void ec_parsed_set_match(struct ec_parsed *parsed,
-       const struct ec_node *node, struct ec_strvec *strvec)
-{
-       parsed->node = node;
-       parsed->strvec = strvec;
-}
-
 void ec_parsed_free_children(struct ec_parsed *parsed)
 {
        struct ec_parsed *child;
@@ -145,7 +182,7 @@ static void __ec_parsed_dump(FILE *out,
        struct ec_parsed *child;
        const struct ec_strvec *vec;
        size_t i;
-       const char *id = "None", *typename = "None";
+       const char *id = "none", *typename = "none";
 
        if (parsed->node != NULL) {
                if (parsed->node->id != NULL)
@@ -167,7 +204,11 @@ static void __ec_parsed_dump(FILE *out,
                fprintf(out, "%s<%s>",
                        i == 0 ? "" : ",",
                        ec_strvec_val(vec, i));
-       fprintf(out, "]\n");
+       // 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);
@@ -193,12 +234,31 @@ void ec_parsed_add_child(struct ec_parsed *parsed,
        struct ec_parsed *child)
 {
        TAILQ_INSERT_TAIL(&parsed->children, child, next);
+       child->parent = parsed;
 }
 
 void ec_parsed_del_child(struct ec_parsed *parsed,
        struct ec_parsed *child)
 {
        TAILQ_REMOVE(&parsed->children, child, next);
+       child->parent = NULL;
+}
+
+struct ec_parsed *
+ec_parsed_get_last_child(struct ec_parsed *parsed)
+{
+       return TAILQ_LAST(&parsed->children, ec_parsed_list);
+}
+
+struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
+{
+       if (parsed == NULL)
+               return NULL;
+
+       while (parsed->parent != NULL)
+               parsed = parsed->parent;
+
+       return parsed;
 }
 
 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
@@ -245,7 +305,7 @@ size_t ec_parsed_matches(const struct ec_parsed *parsed)
        if (parsed == NULL)
                return 0;
 
-       if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children))
+       if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed?
                return 0;
 
        return 1;
index 83ace08..dbef739 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <sys/queue.h>
 #include <sys/types.h>
+#include <limits.h>
 #include <stdio.h>
 
 struct ec_node;
@@ -42,6 +43,7 @@ TAILQ_HEAD(ec_parsed_list, ec_parsed);
 struct ec_parsed {
        TAILQ_ENTRY(ec_parsed) next;
        struct ec_parsed_list children;
+       struct ec_parsed *parent;
        const struct ec_node *node;
        struct ec_strvec *strvec;
 };
@@ -50,11 +52,7 @@ struct ec_parsed *ec_parsed(void);
 void ec_parsed_free(struct ec_parsed *parsed);
 void ec_parsed_free_children(struct ec_parsed *parsed);
 
-const struct ec_strvec *ec_parsed_strvec(
-       const struct ec_parsed *parsed);
-
-void ec_parsed_set_match(struct ec_parsed *parsed,
-       const struct ec_node *node, struct ec_strvec *strvec);
+const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed);
 
 /* XXX we could use a cache to store possible completions or match: the
  * cache would be per-node, and would be reset for each call to parse()
@@ -64,16 +62,26 @@ void ec_parsed_set_match(struct ec_parsed *parsed,
 */
 struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str);
 
-/* mostly internal to nodes */
-/* XXX it should not reset cache
- * ... not sure... it is used by tests */
 struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
-       const struct ec_strvec *strvec);
+                               const struct ec_strvec *strvec);
+
+#define EC_PARSED_NOMATCH INT_MIN
+/* internal: used by nodes */
+/* return:
+ * EC_PARSED_NOMATCH (negative) if it does not match
+ * any other negative value (-errno) for other errors
+ * the number of matched strings in strvec
+ */
+int ec_node_parse_child(struct ec_node *node,
+                       struct ec_parsed *state,
+                       const struct ec_strvec *strvec);
 
 void ec_parsed_add_child(struct ec_parsed *parsed,
-       struct ec_parsed *child);
+                       struct ec_parsed *child);
 void ec_parsed_del_child(struct ec_parsed *parsed,
-       struct ec_parsed *child);
+                       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_dump(FILE *out, const struct ec_parsed *parsed);
 
 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
index 6b002b8..6bd0fa3 100644 (file)
@@ -74,8 +74,7 @@ int ec_test_check_parse(struct ec_node *tk, int expected, ...)
        }
 
        p = ec_node_parse_strvec(tk, vec);
-       /* XXX only for debug */
-       ec_parsed_dump(stdout, p);
+       ec_parsed_dump(stdout, p); /* XXX only for debug */
        if (p == NULL) {
                ec_log(EC_LOG_ERR, "parsed is NULL\n");
        }
index cde202a..1d64402 100644 (file)
@@ -146,7 +146,7 @@ static int show_help(int ignore, int invoking_key)
        /* complete at current cursor position */
        line[rl_point] = '\0';
        c = ec_node_complete(commands, line);
-       ec_completed_dump(stdout, c);
+       //ec_completed_dump(stdout, c);
        free(line);
        if (c == NULL)
                return 1;
@@ -192,6 +192,7 @@ static int create_commands(void)
        if (cmdlist == NULL)
                goto fail;
 
+
        cmd = EC_NODE_SEQ(NULL,
                ec_node_str(NULL, "hello"),
                EC_NODE_OR("name",
@@ -212,6 +213,7 @@ static int create_commands(void)
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
 
+
        cmd = EC_NODE_CMD(NULL, "good morning bob|bobby|michael [count]",
                        ec_node_int("count", 0, 10, 10));
        if (cmd == NULL)
@@ -221,6 +223,17 @@ static int create_commands(void)
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
 
+
+       cmd = EC_NODE_CMD(NULL,
+                       "buy potatoes,carrots,pumpkins");
+       if (cmd == NULL)
+               goto fail;
+       ec_keyval_set(ec_node_attrs(cmd), "help",
+               "buy some vegetables", NULL);
+       if (ec_node_or_add(cmdlist, cmd) < 0)
+               goto fail;
+
+
        cmd = EC_NODE_SEQ(NULL,
                ec_node_str(NULL, "bye")
        );
@@ -228,6 +241,7 @@ static int create_commands(void)
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
 
+
        commands = ec_node_sh_lex(NULL, cmdlist);
        if (commands == NULL)
                goto fail;
index 0633d0f..40e0e62 100644 (file)
@@ -30,6 +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
 
 dependencies
 ============