#include <ecoli_log.h>
#include <ecoli_strvec.h>
#include <ecoli_node.h>
+#include <ecoli_parsed.h>
+#include <ecoli_completed.h>
#include <ecoli_node_subset.h>
#include <ecoli_node_str.h>
#include <ecoli_node_or.h>
};
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++) {
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) {
memset(&result, 0, sizeof(result));
+ ec_parsed_del_last_child(state);
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_new();
- 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_new();
- 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 *
+static int
__ec_node_subset_complete(struct ec_node **table, size_t table_len,
- const struct ec_strvec *strvec)
+ struct ec_completed *completed,
+ struct ec_parsed *parsed,
+ const struct ec_strvec *strvec)
{
- struct ec_completed *completed = NULL;
- struct ec_completed *child_completed = NULL;
struct ec_strvec *childvec = NULL;
- struct ec_parsed *parsed = NULL;
struct ec_node *save;
size_t i, len;
+ int ret;
/*
* example with table = [a, b, c]
* + __subset_complete([a, b], childvec) if c matches
*/
- completed = ec_completed_new();
- if (completed == NULL)
- goto fail;
-
/* first, try to complete with each node of the table */
for (i = 0; i < table_len; i++) {
if (table[i] == NULL)
continue;
- child_completed = ec_node_complete_strvec(table[i],
- strvec);
-
- if (child_completed == NULL)
+ ret = ec_node_complete_child(table[i],
+ completed, parsed, strvec);
+ if (ret < 0)
goto fail;
-
- ec_completed_merge(completed, child_completed);
- child_completed = NULL;
}
/* then, if a node matches, advance in strvec and try to complete with
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], parsed, 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(parsed);
goto fail;
+ }
save = table[i];
table[i] = NULL;
- child_completed = __ec_node_subset_complete(table,
- table_len, childvec);
+ ret = __ec_node_subset_complete(table, table_len,
+ completed, parsed, childvec);
table[i] = save;
ec_strvec_free(childvec);
childvec = NULL;
+ ec_parsed_del_last_child(parsed);
- if (child_completed == NULL)
+ if (ret < 0)
goto fail;
-
- ec_completed_merge(completed, child_completed);
- child_completed = NULL;
-
- ec_parsed_free(parsed);
- parsed = NULL;
}
- return completed;
-fail:
- ec_parsed_free(parsed);
- ec_completed_free(child_completed);
- ec_completed_free(completed);
+ return 0;
- return NULL;
+fail:
+ return -1;
}
-static struct ec_completed *ec_node_subset_complete(const struct ec_node *gen_node,
- const struct ec_strvec *strvec)
+static int
+ec_node_subset_complete(const struct ec_node *gen_node,
+ struct ec_completed *completed,
+ struct ec_parsed *parsed,
+ 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, completed,
+ parsed, strvec);
}
static void ec_node_subset_free_priv(struct ec_node *gen_node)
va_start(ap, id);
- gen_node = __ec_node_new(&ec_node_subset_type, id);
+ gen_node = __ec_node(&ec_node_subset_type, id);
node = (struct ec_node_subset *)gen_node;
if (node == NULL)
fail = 1;;
return NULL;
}
+/* LCOV_EXCL_START */
static int ec_node_subset_testcase(void)
{
struct ec_node *node;
return ret;
}
+/* LCOV_EXCL_STOP */
static struct ec_test ec_node_subset_test = {
.name = "node_subset",