From 86d3143560d546c7f7df78f67dc633a574d68397 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Thu, 26 Jan 2017 19:35:28 +0100 Subject: [PATCH] save --- lib/Makefile | 2 +- lib/ecoli_tk_expr.c | 62 +++++++-------- lib/ecoli_tk_re_lex.c | 1 + lib/{ecoli_tk_shlex.c => ecoli_tk_sh_lex.c} | 46 ++++++------ lib/{ecoli_tk_shlex.h => ecoli_tk_sh_lex.h} | 2 +- lib/{ecoli_tk_bypass.c => ecoli_tk_weakref.c} | 74 +++++++----------- lib/{ecoli_tk_bypass.h => ecoli_tk_weakref.h} | 75 ++++++++++++------- lib/main-readline.c | 4 +- 8 files changed, 125 insertions(+), 141 deletions(-) rename lib/{ecoli_tk_shlex.c => ecoli_tk_sh_lex.c} (91%) rename lib/{ecoli_tk_shlex.h => ecoli_tk_sh_lex.h} (96%) rename lib/{ecoli_tk_bypass.c => ecoli_tk_weakref.c} (62%) rename lib/{ecoli_tk_bypass.h => ecoli_tk_weakref.h} (60%) diff --git a/lib/Makefile b/lib/Makefile index db3763c..ca072a5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -37,7 +37,7 @@ srcs := ecoli_tk.c ecoli_malloc.c ecoli_log.c ecoli_strvec.c srcs += ecoli_keyval.c ecoli_test.c srcs += ecoli_tk_str.c ecoli_tk_seq.c ecoli_tk_space.c ecoli_tk_or.c srcs += ecoli_tk_empty.c ecoli_tk_int.c ecoli_tk_option.c ecoli_tk_many.c -srcs += ecoli_tk_shlex.c ecoli_tk_expr.c ecoli_tk_bypass.c ecoli_tk_re_lex.c +srcs += ecoli_tk_sh_lex.c ecoli_tk_expr.c ecoli_tk_weakref.c ecoli_tk_re_lex.c shlib-y-$(O)libecoli.so := $(srcs) ldflags-$(O)test = -rdynamic diff --git a/lib/ecoli_tk_expr.c b/lib/ecoli_tk_expr.c index 4b54b9f..fe28b20 100644 --- a/lib/ecoli_tk_expr.c +++ b/lib/ecoli_tk_expr.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include struct ec_tk_expr { struct ec_tk gen; @@ -84,7 +84,6 @@ static struct ec_completed_tk *ec_tk_expr_complete(const struct ec_tk *gen_tk, static void ec_tk_expr_free_priv(struct ec_tk *gen_tk) { struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk; - struct ec_tk *final; unsigned int i; ec_log(EC_LOG_DEBUG, "free %p %p %p\n", tk, tk->child, tk->val_tk); @@ -106,12 +105,7 @@ static void ec_tk_expr_free_priv(struct ec_tk *gen_tk) ec_free(tk->open_ops); ec_free(tk->close_ops); - /* break the graph loop, and free the nodes */ - if (tk->child != NULL) { - final = ec_tk_bypass_pop(tk->child); - ec_tk_free(tk->child); - ec_tk_free(final); - } + ec_tk_free(tk->child); } static int ec_tk_expr_build(struct ec_tk *gen_tk) @@ -119,7 +113,7 @@ static int ec_tk_expr_build(struct ec_tk *gen_tk) struct ec_tk_expr *tk = (struct ec_tk_expr *)gen_tk; struct ec_tk *term = NULL, *expr = NULL, *next = NULL, *pre_op = NULL, *post_op = NULL, - *post = NULL, *final = NULL; + *post = NULL, *weak = NULL; unsigned int i; int ret; @@ -132,9 +126,9 @@ static int ec_tk_expr_build(struct ec_tk *gen_tk) /* create the object, we will initialize it later: this is * needed because we have a circular dependency */ ret = -ENOMEM; - expr = ec_tk_bypass_empty("expr"); - if (expr == NULL) - goto fail; + weak = ec_tk_weakref_empty("weak"); + if (weak == NULL) + return -1; /* prefix unary operators */ pre_op = ec_tk_or("pre-op"); @@ -162,12 +156,12 @@ static int ec_tk_expr_build(struct ec_tk *gen_tk) if (ec_tk_or_add(term, EC_TK_SEQ(NULL, ec_tk_clone(pre_op), - ec_tk_clone(expr))) < 0) + ec_tk_clone(weak))) < 0) goto fail; for (i = 0; i < tk->paren_len; i++) { if (ec_tk_or_add(term, EC_TK_SEQ(NULL, ec_tk_clone(tk->open_ops[i]), - ec_tk_clone(expr), + ec_tk_clone(weak), ec_tk_clone(tk->close_ops[i]))) < 0) goto fail; } @@ -189,11 +183,11 @@ static int ec_tk_expr_build(struct ec_tk *gen_tk) goto fail; } - final = EC_TK_SEQ("final", + expr = EC_TK_SEQ("expr", ec_tk_clone(term), ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0) ); - if (final == NULL) + if (expr == NULL) goto fail; /* free the initial references */ @@ -206,11 +200,11 @@ static int ec_tk_expr_build(struct ec_tk *gen_tk) ec_tk_free(post); post = NULL; - if (ec_tk_bypass_set(expr, ec_tk_clone(final)) < 0) + /* no need to clone here, the node is not consumed */ + if (ec_tk_weakref_set(weak, expr) < 0) goto fail; - - ec_tk_free(final); - final = NULL; + ec_tk_free(weak); + weak = NULL; tk->child = expr; @@ -222,7 +216,7 @@ fail: ec_tk_free(pre_op); ec_tk_free(post_op); ec_tk_free(post); - ec_tk_free(final); + ec_tk_free(weak); return ret; } @@ -420,7 +414,7 @@ fail: static int ec_tk_expr_testcase_manual(void) { struct ec_tk *term = NULL, *factor = NULL, *expr = NULL, *val = NULL, - *pre_op = NULL, *post_op = NULL, *post = NULL, *final = NULL; + *pre_op = NULL, *post_op = NULL, *post = NULL, *weak = NULL; int ret = 0; // XXX check all APIs: pointers are "moved", they are freed by @@ -429,10 +423,8 @@ static int ec_tk_expr_testcase_manual(void) /* Example that generates an expression "manually". We keep it * here for reference. */ - /* create the object, we will initialize it later: this is - * needed because we have a circular dependency */ - expr = ec_tk_bypass_empty("expr"); - if (expr == NULL) + weak = ec_tk_weakref_empty("weak"); + if (weak == NULL) return -1; /* reverse bits */ @@ -450,12 +442,12 @@ static int ec_tk_expr_testcase_manual(void) val, EC_TK_SEQ(NULL, ec_tk_str(NULL, "("), - ec_tk_clone(expr), + ec_tk_clone(weak), ec_tk_str(NULL, ")") ), EC_TK_SEQ(NULL, ec_tk_clone(pre_op), - ec_tk_clone(expr) + ec_tk_clone(weak) ) ); val = NULL; @@ -482,7 +474,7 @@ static int ec_tk_expr_testcase_manual(void) ) ); - final = EC_TK_SEQ("final", + expr = EC_TK_SEQ("expr", ec_tk_clone(post), ec_tk_many(NULL, ec_tk_clone(post_op), 0, 0) ); @@ -499,11 +491,11 @@ static int ec_tk_expr_testcase_manual(void) ec_tk_free(post); post = NULL; - if (ec_tk_bypass_set(expr, ec_tk_clone(final)) < 0) + /* no need to clone here, the node is not consumed */ + if (ec_tk_weakref_set(weak, expr) < 0) goto fail; - - ec_tk_free(final); - final = NULL; + ec_tk_free(weak); + weak = NULL; ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1"); ret |= EC_TEST_CHECK_TK_PARSE(expr, 1, "1", "*"); @@ -514,9 +506,7 @@ static int ec_tk_expr_testcase_manual(void) expr, 10, "~", "(", "1", "*", "(", "1", "+", "1", ")", ")"); ret |= EC_TEST_CHECK_TK_PARSE(expr, 4, "1", "+", "~", "1"); - final = ec_tk_bypass_pop(expr); ec_tk_free(expr); - ec_tk_free(final); return ret; @@ -528,7 +518,7 @@ fail: ec_tk_free(pre_op); ec_tk_free(post_op); ec_tk_free(post); - ec_tk_free(final); + ec_tk_free(weak); return 0; } diff --git a/lib/ecoli_tk_re_lex.c b/lib/ecoli_tk_re_lex.c index 5dd273d..8d31543 100644 --- a/lib/ecoli_tk_re_lex.c +++ b/lib/ecoli_tk_re_lex.c @@ -247,6 +247,7 @@ static int ec_tk_re_lex_testcase(void) ret |= ec_tk_re_lex_add(tk, "^[ ]+", 0); if (ret != 0) { ec_log(EC_LOG_ERR, "cannot add regexp to token\n"); + ec_tk_free(tk); return -1; } diff --git a/lib/ecoli_tk_shlex.c b/lib/ecoli_tk_sh_lex.c similarity index 91% rename from lib/ecoli_tk_shlex.c rename to lib/ecoli_tk_sh_lex.c index a7bb6ff..ab66e60 100644 --- a/lib/ecoli_tk_shlex.c +++ b/lib/ecoli_tk_sh_lex.c @@ -41,9 +41,9 @@ #include #include #include -#include +#include -struct ec_tk_shlex { +struct ec_tk_sh_lex { struct ec_tk gen; struct ec_tk *child; }; @@ -233,10 +233,10 @@ static struct ec_strvec *tokenize(const char *str, int completion, return NULL; } -static struct ec_parsed_tk *ec_tk_shlex_parse(const struct ec_tk *gen_tk, +static struct ec_parsed_tk *ec_tk_sh_lex_parse(const struct ec_tk *gen_tk, const struct ec_strvec *strvec) { - struct ec_tk_shlex *tk = (struct ec_tk_shlex *)gen_tk; + struct ec_tk_sh_lex *tk = (struct ec_tk_sh_lex *)gen_tk; struct ec_strvec *new_vec = NULL, *match_strvec; struct ec_parsed_tk *parsed_tk = NULL, *child_parsed_tk; const char *str; @@ -282,10 +282,10 @@ static struct ec_parsed_tk *ec_tk_shlex_parse(const struct ec_tk *gen_tk, return NULL; } -static struct ec_completed_tk *ec_tk_shlex_complete(const struct ec_tk *gen_tk, +static struct ec_completed_tk *ec_tk_sh_lex_complete(const struct ec_tk *gen_tk, const struct ec_strvec *strvec) { - struct ec_tk_shlex *tk = (struct ec_tk_shlex *)gen_tk; + struct ec_tk_sh_lex *tk = (struct ec_tk_sh_lex *)gen_tk; struct ec_completed_tk *completed_tk, *child_completed_tk = NULL; struct ec_strvec *new_vec = NULL; const char *str; @@ -364,28 +364,28 @@ static struct ec_completed_tk *ec_tk_shlex_complete(const struct ec_tk *gen_tk, return NULL; } -static void ec_tk_shlex_free_priv(struct ec_tk *gen_tk) +static void ec_tk_sh_lex_free_priv(struct ec_tk *gen_tk) { - struct ec_tk_shlex *tk = (struct ec_tk_shlex *)gen_tk; + struct ec_tk_sh_lex *tk = (struct ec_tk_sh_lex *)gen_tk; ec_tk_free(tk->child); } -static struct ec_tk_ops ec_tk_shlex_ops = { - .typename = "shlex", - .parse = ec_tk_shlex_parse, - .complete = ec_tk_shlex_complete, - .free_priv = ec_tk_shlex_free_priv, +static struct ec_tk_ops ec_tk_sh_lex_ops = { + .typename = "sh_lex", + .parse = ec_tk_sh_lex_parse, + .complete = ec_tk_sh_lex_complete, + .free_priv = ec_tk_sh_lex_free_priv, }; -struct ec_tk *ec_tk_shlex_new(const char *id, struct ec_tk *child) +struct ec_tk *ec_tk_sh_lex_new(const char *id, struct ec_tk *child) { - struct ec_tk_shlex *tk = NULL; + struct ec_tk_sh_lex *tk = NULL; if (child == NULL) return NULL; - tk = (struct ec_tk_shlex *)ec_tk_new(id, &ec_tk_shlex_ops, + tk = (struct ec_tk_sh_lex *)ec_tk_new(id, &ec_tk_sh_lex_ops, sizeof(*tk)); if (tk == NULL) { ec_tk_free(child); @@ -397,12 +397,12 @@ struct ec_tk *ec_tk_shlex_new(const char *id, struct ec_tk *child) return &tk->gen; } -static int ec_tk_shlex_testcase(void) +static int ec_tk_sh_lex_testcase(void) { struct ec_tk *tk; int ret = 0; - tk = ec_tk_shlex_new(NULL, + tk = ec_tk_sh_lex_new(NULL, EC_TK_SEQ(NULL, ec_tk_str(NULL, "foo"), ec_tk_option_new(NULL, @@ -422,7 +422,7 @@ static int ec_tk_shlex_testcase(void) ec_tk_free(tk); /* test completion */ - tk = ec_tk_shlex_new(NULL, + tk = ec_tk_sh_lex_new(NULL, EC_TK_SEQ(NULL, ec_tk_str(NULL, "foo"), ec_tk_option_new(NULL, @@ -489,9 +489,9 @@ static int ec_tk_shlex_testcase(void) return ret; } -static struct ec_test ec_tk_shlex_test = { - .name = "tk_shlex", - .test = ec_tk_shlex_testcase, +static struct ec_test ec_tk_sh_lex_test = { + .name = "tk_sh_lex", + .test = ec_tk_sh_lex_testcase, }; -EC_REGISTER_TEST(ec_tk_shlex_test); +EC_REGISTER_TEST(ec_tk_sh_lex_test); diff --git a/lib/ecoli_tk_shlex.h b/lib/ecoli_tk_sh_lex.h similarity index 96% rename from lib/ecoli_tk_shlex.h rename to lib/ecoli_tk_sh_lex.h index 5aa2246..7031d1c 100644 --- a/lib/ecoli_tk_shlex.h +++ b/lib/ecoli_tk_sh_lex.h @@ -30,6 +30,6 @@ #include -struct ec_tk *ec_tk_shlex_new(const char *id, struct ec_tk *child); +struct ec_tk *ec_tk_sh_lex_new(const char *id, struct ec_tk *child); #endif diff --git a/lib/ecoli_tk_bypass.c b/lib/ecoli_tk_weakref.c similarity index 62% rename from lib/ecoli_tk_bypass.c rename to lib/ecoli_tk_weakref.c index e71a14c..5aee97c 100644 --- a/lib/ecoli_tk_bypass.c +++ b/lib/ecoli_tk_weakref.c @@ -39,49 +39,41 @@ #include #include #include -#include +#include -struct ec_tk_bypass { +struct ec_tk_weakref { struct ec_tk gen; struct ec_tk *child; }; -static struct ec_parsed_tk *ec_tk_bypass_parse(const struct ec_tk *gen_tk, +static struct ec_parsed_tk *ec_tk_weakref_parse(const struct ec_tk *gen_tk, const struct ec_strvec *strvec) { - struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk; + struct ec_tk_weakref *tk = (struct ec_tk_weakref *)gen_tk; return ec_tk_parse_tokens(tk->child, strvec); } -static struct ec_completed_tk *ec_tk_bypass_complete(const struct ec_tk *gen_tk, +static struct ec_completed_tk *ec_tk_weakref_complete(const struct ec_tk *gen_tk, const struct ec_strvec *strvec) { - struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk; + struct ec_tk_weakref *tk = (struct ec_tk_weakref *)gen_tk; return ec_tk_complete_tokens(tk->child, strvec); } -static void ec_tk_bypass_free_priv(struct ec_tk *gen_tk) -{ - struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk; - - ec_tk_free(tk->child); -} - -static struct ec_tk_ops ec_tk_bypass_ops = { - .typename = "bypass", - .parse = ec_tk_bypass_parse, - .complete = ec_tk_bypass_complete, - .free_priv = ec_tk_bypass_free_priv, +static struct ec_tk_ops ec_tk_weakref_ops = { + .typename = "weakref", + .parse = ec_tk_weakref_parse, + .complete = ec_tk_weakref_complete, }; -struct ec_tk *ec_tk_bypass_empty(const char *id) +struct ec_tk *ec_tk_weakref_empty(const char *id) { - struct ec_tk_bypass *tk = NULL; + struct ec_tk_weakref *tk = NULL; - tk = (struct ec_tk_bypass *)ec_tk_new(id, - &ec_tk_bypass_ops, sizeof(*tk)); + tk = (struct ec_tk_weakref *)ec_tk_new(id, + &ec_tk_weakref_ops, sizeof(*tk)); if (tk == NULL) return NULL; @@ -90,9 +82,9 @@ struct ec_tk *ec_tk_bypass_empty(const char *id) return &tk->gen; } -int ec_tk_bypass_set(struct ec_tk *gen_tk, struct ec_tk *child) +int ec_tk_weakref_set(struct ec_tk *gen_tk, struct ec_tk *child) { - struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk; + struct ec_tk_weakref *tk = (struct ec_tk_weakref *)gen_tk; // XXX check tk type @@ -111,46 +103,30 @@ int ec_tk_bypass_set(struct ec_tk *gen_tk, struct ec_tk *child) return 0; } -struct ec_tk *ec_tk_bypass_pop(struct ec_tk *gen_tk) -{ - struct ec_tk_bypass *tk = (struct ec_tk_bypass *)gen_tk; - struct ec_tk *child; - - child = tk->child; - tk->child = NULL; - - gen_tk->flags &= ~EC_TK_F_BUILT; - TAILQ_REMOVE(&gen_tk->children, child, next); // XXX really needed? - - return child; -} - -struct ec_tk *ec_tk_bypass(const char *id, struct ec_tk *child) +struct ec_tk *ec_tk_weakref(const char *id, struct ec_tk *child) { struct ec_tk *gen_tk = NULL; if (child == NULL) return NULL; - gen_tk = ec_tk_bypass_empty(id); - if (gen_tk == NULL) { - ec_tk_free(child); + gen_tk = ec_tk_weakref_empty(id); + if (gen_tk == NULL) return NULL; - } - ec_tk_bypass_set(gen_tk, child); + ec_tk_weakref_set(gen_tk, child); return gen_tk; } -static int ec_tk_bypass_testcase(void) +static int ec_tk_weakref_testcase(void) { return 0; } -static struct ec_test ec_tk_bypass_test = { - .name = "tk_bypass", - .test = ec_tk_bypass_testcase, +static struct ec_test ec_tk_weakref_test = { + .name = "tk_weakref", + .test = ec_tk_weakref_testcase, }; -EC_REGISTER_TEST(ec_tk_bypass_test); +EC_REGISTER_TEST(ec_tk_weakref_test); diff --git a/lib/ecoli_tk_bypass.h b/lib/ecoli_tk_weakref.h similarity index 60% rename from lib/ecoli_tk_bypass.h rename to lib/ecoli_tk_weakref.h index 92f84d9..c911400 100644 --- a/lib/ecoli_tk_bypass.h +++ b/lib/ecoli_tk_weakref.h @@ -30,45 +30,62 @@ #include -/// XXX rename in loop ? -// XXX + provide the helper to free ? - -/* a tk that just behaves like its child +/* a tk that just behaves like its child and that does not free + * its child when freed. + * * useful to create cyclic graphs of tokens: * creating a loop (with clones) result in something that is not * freeable, due to reference counters - * bypass node can solve the issue: before freeing the graph, - * the loop can be cut, falling back to a valid tree that can - * be freed. * * Example: - * seq = seq() - * i = int() - * seq_add(seq, i) - * seq_add(seq, clone(seq)) - * FAIL, cannot be freed + * val = int(0, 10) + * op = str("!") + * expr = or() + * seq = seq(clone(op), clone(expr)) + * expr.add(clone(seq)) + * expr.add(clone(val)) + * free(val) + * free(op) + * free(seq) + * + * FAIL: expr cannot be freed due to cyclic refs + * The references are like this: + * + * val + * ^ + * | + * $user ---> expr ---> seq ---> op + * <--- * - * seq = seq() - * bypass = bypass(clone(seq)) - * i = int() - * seq_add(seq, i) - * seq_add(seq, bypass) + * It is solved with: + * val = int(0, 10) + * op = str("!") + * expr = or() + * weak = weak(expr) + * seq = seq(clone(op), clone(weak)) + * expr.add(clone(seq)) + * expr.add(clone(val)) + * free(val) + * free(op) + * free(weak) + * free(seq) * - * TO FREE: - * seq2 = bypass_del(bypass) // breaks the loop (seq2 == seq) - * free(bypass) - * free(seq2) - * free(seq) + * + * val + * ^ + * | + * $user ---> expr ---------------> seq ---> op + * <- - - weak <--- + * + * The node expr can be freed. */ -struct ec_tk *ec_tk_bypass(const char *id, struct ec_tk *child); - -struct ec_tk *ec_tk_bypass_empty(const char *id); +/* on error, child is *not* freed */ +struct ec_tk *ec_tk_weakref(const char *id, struct ec_tk *child); -/* child is consumed */ -/* all token given in the list will be freed when freeing this one */ -int ec_tk_bypass_set(struct ec_tk *tk, struct ec_tk *child); +struct ec_tk *ec_tk_weakref_empty(const char *id); -struct ec_tk *ec_tk_bypass_pop(struct ec_tk *gen_tk); +/* on error, child is *not* freed */ +int ec_tk_weakref_set(struct ec_tk *tk, struct ec_tk *child); #endif diff --git a/lib/main-readline.c b/lib/main-readline.c index 9489b70..7a0d5b8 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include static struct ec_tk *commands; @@ -201,7 +201,7 @@ static int create_commands(void) if (ec_tk_or_add(cmdlist, cmd) < 0) goto fail; - commands = ec_tk_shlex_new(NULL, cmdlist); + commands = ec_tk_sh_lex_new(NULL, cmdlist); if (commands == NULL) goto fail; -- 2.39.5