From bf091fc25fc602ceb9ec389f341c52bd0bf7d2af Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Thu, 20 Jul 2017 23:07:51 +0200 Subject: [PATCH] pass state to completed api --- lib/ecoli_completed.c | 141 ++++++++++++++++++++++++--------------- lib/ecoli_completed.h | 17 +++-- lib/ecoli_node.h | 1 + lib/ecoli_node_cmd.c | 29 +++++--- lib/ecoli_node_expr.c | 5 +- lib/ecoli_node_many.c | 120 +++++++++++++++++++++++++-------- lib/ecoli_node_once.c | 8 +-- lib/ecoli_node_option.c | 3 +- lib/ecoli_node_or.c | 10 +-- lib/ecoli_node_seq.c | 39 ++++++----- lib/ecoli_node_sh_lex.c | 8 ++- lib/ecoli_node_str.c | 14 ++-- lib/ecoli_node_subset.c | 44 ++++++------ lib/ecoli_node_weakref.c | 3 +- lib/ecoli_parsed.c | 35 +++++++--- lib/ecoli_parsed.h | 16 ++++- lib/main-readline.c | 20 ++++++ lib/todo.txt | 3 +- 18 files changed, 340 insertions(+), 176 deletions(-) diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index 8a34c74..18e92ed 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -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); diff --git a/lib/ecoli_completed.h b/lib/ecoli_completed.h index d9fcdc3..993db7f 100644 --- a/lib/ecoli_completed.h +++ b/lib/ecoli_completed.h @@ -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( diff --git a/lib/ecoli_node.h b/lib/ecoli_node.h index 9115ebc..e027f1d 100644 --- a/lib/ecoli_node.h +++ b/lib/ecoli_node.h @@ -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 *); diff --git a/lib/ecoli_node_cmd.c b/lib/ecoli_node_cmd.c index 8cf76ab..2082bdd 100644 --- a/lib/ecoli_node_cmd.c +++ b/lib/ecoli_node_cmd.c @@ -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) ); diff --git a/lib/ecoli_node_expr.c b/lib/ecoli_node_expr.c index 5aa8a2e..78b6755 100644 --- a/lib/ecoli_node_expr.c +++ b/lib/ecoli_node_expr.c @@ -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) diff --git a/lib/ecoli_node_many.c b/lib/ecoli_node_many.c index c07ae5e..87534a3 100644 --- a/lib/ecoli_node_many.c +++ b/lib/ecoli_node_many.c @@ -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, }; diff --git a/lib/ecoli_node_once.c b/lib/ecoli_node_once.c index 3142504..deb9baa 100644 --- a/lib/ecoli_node_once.c +++ b/lib/ecoli_node_once.c @@ -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; diff --git a/lib/ecoli_node_option.c b/lib/ecoli_node_option.c index 76561ee..0c72f98 100644 --- a/lib/ecoli_node_option.c +++ b/lib/ecoli_node_option.c @@ -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) diff --git a/lib/ecoli_node_or.c b/lib/ecoli_node_or.c index 5563a78..8925cc7 100644 --- a/lib/ecoli_node_or.c +++ b/lib/ecoli_node_or.c @@ -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; diff --git a/lib/ecoli_node_seq.c b/lib/ecoli_node_seq.c index a434363..8b7b2ee 100644 --- a/lib/ecoli_node_seq.c +++ b/lib/ecoli_node_seq.c @@ -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) diff --git a/lib/ecoli_node_sh_lex.c b/lib/ecoli_node_sh_lex.c index 7b61c52..ec15fc7 100644 --- a/lib/ecoli_node_sh_lex.c +++ b/lib/ecoli_node_sh_lex.c @@ -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; diff --git a/lib/ecoli_node_str.c b/lib/ecoli_node_str.c index 9f2497c..011a86c 100644 --- a/lib/ecoli_node_str.c +++ b/lib/ecoli_node_str.c @@ -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; } diff --git a/lib/ecoli_node_subset.c b/lib/ecoli_node_subset.c index f1c09f8..6b5fee0 100644 --- a/lib/ecoli_node_subset.c +++ b/lib/ecoli_node_subset.c @@ -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) diff --git a/lib/ecoli_node_weakref.c b/lib/ecoli_node_weakref.c index 063ae4d..9ad52fb 100644 --- a/lib/ecoli_node_weakref.c +++ b/lib/ecoli_node_weakref.c @@ -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 = { diff --git a/lib/ecoli_parsed.c b/lib/ecoli_parsed.c index 38f42b8..140edea 100644 --- a/lib/ecoli_parsed.c +++ b/lib/ecoli_parsed.c @@ -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) diff --git a/lib/ecoli_parsed.h b/lib/ecoli_parsed.h index dbef739..1ebea9e 100644 --- a/lib/ecoli_parsed.h +++ b/lib/ecoli_parsed.h @@ -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); diff --git a/lib/main-readline.c b/lib/main-readline.c index 1d64402..9d898ff 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -45,6 +45,8 @@ #include #include #include +#include +#include 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") ); diff --git a/lib/todo.txt b/lib/todo.txt index 40e0e62..c34e104 100644 --- a/lib/todo.txt +++ b/lib/todo.txt @@ -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 ======== -- 2.20.1