X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fecoli_node_seq.c;h=d6338e9098571dee242dace6ece82ec5871b735b;hb=c87286ff9f1d70e3722640d6f0b5846fdc493d38;hp=4a975ad4eed840009c64ac64a92a6d8d3a1504b7;hpb=c1eb3099a1a7f4c9b9f8c6238336ee5b69147fd6;p=protos%2Flibecoli.git diff --git a/lib/ecoli_node_seq.c b/lib/ecoli_node_seq.c index 4a975ad..d6338e9 100644 --- a/lib/ecoli_node_seq.c +++ b/lib/ecoli_node_seq.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -37,120 +38,158 @@ #include #include #include +#include +#include #include #include +#include +#include #include struct ec_node_seq { struct ec_node gen; struct ec_node **table; - unsigned int len; + size_t 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 *ec_node_seq_complete(const struct ec_node *gen_node, - const struct ec_strvec *strvec) +static int +__ec_node_seq_complete(struct ec_node **table, size_t table_len, + struct ec_completed *completed, + struct ec_parsed *parsed, + const struct ec_strvec *strvec) { - struct ec_node_seq *node = (struct ec_node_seq *)gen_node; - struct ec_completed *completed, *child_completed; struct ec_strvec *childvec = NULL; - struct ec_parsed *parsed; - size_t len = 0; unsigned int i; + int ret; + + if (table_len == 0) + return 0; + + /* + * Example of completion for a sequence node = [n1,n2] and an + * input = [a,b,c,d]: + * + * result = complete(n1, [a,b,c,d]) + + * complete(n2, [b,c,d]) if n1 matches [a] + + * complete(n2, [c,d]) if n1 matches [a,b] + + * complete(n2, [d]) if n1 matches [a,b,c] + + * complete(n2, []) if n1 matches [a,b,c,d] + */ + + /* first, try to complete with the first node of the table */ + ret = ec_node_complete_child(table[0], completed, parsed, strvec); + if (ret < 0) + goto fail; - completed = ec_completed(); - if (completed == NULL) - return NULL; - - if (node->len == 0) - return completed; - - for (i = 0; i < node->len && len < ec_strvec_len(strvec); i++) { - childvec = ec_strvec_ndup(strvec, len, - ec_strvec_len(strvec) - len); + /* 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; - child_completed = ec_node_complete_strvec(node->table[i], - childvec); - if (child_completed == NULL) + ret = ec_node_parse_child(table[0], parsed, 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(parsed); + 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(parsed); goto fail; + } + ret = __ec_node_seq_complete(&table[1], + table_len - 1, + completed, parsed, childvec); + ec_parsed_del_last_child(parsed); ec_strvec_free(childvec); childvec = NULL; - if (!ec_parsed_matches(parsed)) { - ec_parsed_free(parsed); - break; - } - - len += ec_strvec_len(parsed->strvec); - ec_parsed_free(parsed); + if (ret < 0) + goto fail; } - return completed; + return 0; fail: ec_strvec_free(childvec); - ec_completed_free(completed); - return NULL; + return -1; +} + +static int +ec_node_seq_complete(const struct ec_node *gen_node, + struct ec_completed *completed, + struct ec_parsed *parsed, + 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, completed, + parsed, strvec); +} + +static size_t ec_node_seq_get_max_parse_len(const struct ec_node *gen_node) +{ + struct ec_node_seq *node = (struct ec_node_seq *)gen_node; + size_t i, len, ret = 0; + + for (i = 0; i < node->len; i++) { + len = ec_node_get_max_parse_len(node->table[i]); + if (len <= SIZE_MAX - ret) + ret += len; + else + ret = SIZE_MAX; + } + + return ret; } static void ec_node_seq_free_priv(struct ec_node *gen_node) @@ -167,6 +206,7 @@ static struct ec_node_type ec_node_seq_type = { .name = "seq", .parse = ec_node_seq_parse, .complete = ec_node_seq_complete, + .get_max_parse_len = ec_node_seq_get_max_parse_len, .size = sizeof(struct ec_node_seq), .free_priv = ec_node_seq_free_priv, }; @@ -242,6 +282,7 @@ fail: return NULL; } +/* LCOV_EXCL_START */ static int ec_node_seq_testcase(void) { struct ec_node *node; @@ -314,6 +355,7 @@ static int ec_node_seq_testcase(void) return ret; } +/* LCOV_EXCL_STOP */ static struct ec_test ec_node_seq_test = { .name = "node_seq",