From 3fb134fdebe01585605b22f876114ad70fea1f8c Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Mon, 17 Jul 2017 21:49:06 +0200 Subject: [PATCH] change parse api --- lib/ecoli_completed.c | 13 ++++ lib/ecoli_node.h | 23 ++++--- lib/ecoli_node_cmd.c | 7 +- lib/ecoli_node_empty.c | 28 ++------ lib/ecoli_node_expr.c | 7 +- lib/ecoli_node_int.c | 27 ++------ lib/ecoli_node_many.c | 55 ++++++--------- lib/ecoli_node_option.c | 45 ++++--------- lib/ecoli_node_or.c | 42 +++--------- lib/ecoli_node_re.c | 30 +++------ lib/ecoli_node_re_lex.c | 65 ++++++++---------- lib/ecoli_node_seq.c | 47 +++++-------- lib/ecoli_node_sh_lex.c | 63 ++++++++---------- lib/ecoli_node_space.c | 29 +++----- lib/ecoli_node_str.c | 28 +++----- lib/ecoli_node_subset.c | 132 ++++++++++++++---------------------- lib/ecoli_node_weakref.c | 13 ++-- lib/ecoli_parsed.c | 140 ++++++++++++++++++++++++++++----------- lib/ecoli_parsed.h | 30 ++++++--- lib/ecoli_test.c | 3 +- lib/main-readline.c | 16 ++++- lib/todo.txt | 1 + 22 files changed, 388 insertions(+), 456 deletions(-) diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index 8ef14d5..8a34c74 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -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 */ diff --git a/lib/ecoli_node.h b/lib/ecoli_node.h index 27a52c8..9115ebc 100644 --- a/lib/ecoli_node.h +++ b/lib/ecoli_node.h @@ -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. */ diff --git a/lib/ecoli_node_cmd.c b/lib/ecoli_node_cmd.c index 9a6c4eb..8cf76ab 100644 --- a/lib/ecoli_node_cmd.c +++ b/lib/ecoli_node_cmd.c @@ -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, diff --git a/lib/ecoli_node_empty.c b/lib/ecoli_node_empty.c index e52956e..6a6ed61 100644 --- a/lib/ecoli_node_empty.c +++ b/lib/ecoli_node_empty.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -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 = { diff --git a/lib/ecoli_node_expr.c b/lib/ecoli_node_expr.c index c158834..5aa8a2e 100644 --- a/lib/ecoli_node_expr.c +++ b/lib/ecoli_node_expr.c @@ -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, diff --git a/lib/ecoli_node_int.c b/lib/ecoli_node_int.c index bf73a13..2ba1b28 100644 --- a/lib/ecoli_node_int.c +++ b/lib/ecoli_node_int.c @@ -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 = { diff --git a/lib/ecoli_node_many.c b/lib/ecoli_node_many.c index b5dff92..f0843b1 100644 --- a/lib/ecoli_node_many.c +++ b/lib/ecoli_node_many.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -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 diff --git a/lib/ecoli_node_option.c b/lib/ecoli_node_option.c index 305734f..76561ee 100644 --- a/lib/ecoli_node_option.c +++ b/lib/ecoli_node_option.c @@ -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; diff --git a/lib/ecoli_node_or.c b/lib/ecoli_node_or.c index a4df91f..5563a78 100644 --- a/lib/ecoli_node_or.c +++ b/lib/ecoli_node_or.c @@ -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, diff --git a/lib/ecoli_node_re.c b/lib/ecoli_node_re.c index 3d2a064..63e2d3e 100644 --- a/lib/ecoli_node_re.c +++ b/lib/ecoli_node_re.c @@ -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) diff --git a/lib/ecoli_node_re_lex.c b/lib/ecoli_node_re_lex.c index e9e3ace..c4d5104 100644 --- a/lib/ecoli_node_re_lex.c +++ b/lib/ecoli_node_re_lex.c @@ -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) diff --git a/lib/ecoli_node_seq.c b/lib/ecoli_node_seq.c index 76258d3..a434363 100644 --- a/lib/ecoli_node_seq.c +++ b/lib/ecoli_node_seq.c @@ -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 * diff --git a/lib/ecoli_node_sh_lex.c b/lib/ecoli_node_sh_lex.c index b92af1f..7b61c52 100644 --- a/lib/ecoli_node_sh_lex.c +++ b/lib/ecoli_node_sh_lex.c @@ -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, diff --git a/lib/ecoli_node_space.c b/lib/ecoli_node_space.c index be14348..265cc9b 100644 --- a/lib/ecoli_node_space.c +++ b/lib/ecoli_node_space.c @@ -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 = { diff --git a/lib/ecoli_node_str.c b/lib/ecoli_node_str.c index fe8c7bb..9f2497c 100644 --- a/lib/ecoli_node_str.c +++ b/lib/ecoli_node_str.c @@ -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, diff --git a/lib/ecoli_node_subset.c b/lib/ecoli_node_subset.c index 48319e6..f1c09f8 100644 --- a/lib/ecoli_node_subset.c +++ b/lib/ecoli_node_subset.c @@ -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 * diff --git a/lib/ecoli_node_weakref.c b/lib/ecoli_node_weakref.c index 603f02d..b496fcc 100644 --- a/lib/ecoli_node_weakref.c +++ b/lib/ecoli_node_weakref.c @@ -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; diff --git a/lib/ecoli_parsed.c b/lib/ecoli_parsed.c index 93d5325..38f42b8 100644 --- a/lib/ecoli_parsed.c +++ b/lib/ecoli_parsed.c @@ -38,10 +38,82 @@ #include #include +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; diff --git a/lib/ecoli_parsed.h b/lib/ecoli_parsed.h index 83ace08..dbef739 100644 --- a/lib/ecoli_parsed.h +++ b/lib/ecoli_parsed.h @@ -30,6 +30,7 @@ #include #include +#include #include 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, diff --git a/lib/ecoli_test.c b/lib/ecoli_test.c index 6b002b8..6bd0fa3 100644 --- a/lib/ecoli_test.c +++ b/lib/ecoli_test.c @@ -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"); } diff --git a/lib/main-readline.c b/lib/main-readline.c index cde202a..1d64402 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -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; diff --git a/lib/todo.txt b/lib/todo.txt index 0633d0f..40e0e62 100644 --- a/lib/todo.txt +++ b/lib/todo.txt @@ -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 ============ -- 2.39.5