From db0fb2aee484a4e5a88ba684b18a1971fb70215b Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Sat, 22 Jan 2022 17:16:28 +0100 Subject: [PATCH] expr: Make body objects refcounted We'll soon need this, once we implement function definitions --- src/apfl.h | 9 ++++--- src/expr.c | 41 ++++++++++++++++++++---------- src/parser.c | 38 ++++++++++++++++++++++----- src/parser_test.c | 65 +++++++++++++++++++++++++++++------------------ 4 files changed, 103 insertions(+), 50 deletions(-) diff --git a/src/apfl.h b/src/apfl.h index e4fc01b..76ca206 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -231,6 +231,7 @@ struct apfl_expr_call { struct apfl_expr_body { struct apfl_expr *items; size_t len; + unsigned refcount; // TODO: Probably better to not expose refcount }; enum apfl_expr_const_type { @@ -292,7 +293,7 @@ struct apfl_expr_params_item { struct apfl_expr_subfunc { struct apfl_expr_params params; - struct apfl_expr_body body; + struct apfl_expr_body *body; }; struct apfl_expr_complex_func { @@ -382,7 +383,7 @@ struct apfl_expr { struct apfl_expr_list list; struct apfl_expr_dict dict; struct apfl_expr_call call; - struct apfl_expr_body simple_func; + struct apfl_expr_body *simple_func; struct apfl_expr_complex_func complex_func; struct apfl_expr_assignment assignment; struct apfl_expr_dot dot; @@ -407,7 +408,7 @@ void apfl_expr_list_item_deinit(struct apfl_expr_list_item *); void apfl_expr_dict_pair_deinit(struct apfl_expr_dict_pair *); void apfl_expr_dict_deinit(struct apfl_expr_dict *); void apfl_expr_call_deinit(struct apfl_expr_call *); -void apfl_expr_body_deinit(struct apfl_expr_body *); +void apfl_expr_body_unref(struct apfl_expr_body *); void apfl_expr_const_deinit(struct apfl_expr_const *); void apfl_expr_param_predicate_deinit(struct apfl_expr_param_predicate *); void apfl_expr_param_list_deinit(struct apfl_expr_param_list *); @@ -437,7 +438,7 @@ struct apfl_expr_list_item apfl_expr_list_item_move(struct apfl_e struct apfl_expr_dict_pair apfl_expr_dict_pair_move(struct apfl_expr_dict_pair *); struct apfl_expr_dict apfl_expr_dict_move(struct apfl_expr_dict *); struct apfl_expr_call apfl_expr_call_move(struct apfl_expr_call *); -struct apfl_expr_body apfl_expr_body_move(struct apfl_expr_body *); +struct apfl_expr_body * apfl_expr_body_move(struct apfl_expr_body **); struct apfl_expr_const apfl_expr_const_move(struct apfl_expr_const *); struct apfl_expr_param_predicate apfl_expr_param_predicate_move(struct apfl_expr_param_predicate *); struct apfl_expr_param_list apfl_expr_param_list_move(struct apfl_expr_param_list *); diff --git a/src/expr.c b/src/expr.c index c7c71d3..26ca4cd 100644 --- a/src/expr.c +++ b/src/expr.c @@ -21,7 +21,8 @@ apfl_expr_deinit(struct apfl_expr *expr) apfl_expr_call_deinit(&expr->call); break; case APFL_EXPR_SIMPLE_FUNC: - apfl_expr_body_deinit(&expr->simple_func); + apfl_expr_body_unref(expr->simple_func); + expr->simple_func = NULL; break; case APFL_EXPR_COMPLEX_FUNC: apfl_expr_complex_func_deinit(&expr->complex_func); @@ -81,9 +82,12 @@ apfl_expr_call_deinit(struct apfl_expr_call *call) } void -apfl_expr_body_deinit(struct apfl_expr_body *body) +apfl_expr_body_unref(struct apfl_expr_body *body) { - DEINIT_LIST(body->items, body->len, apfl_expr_deinit); + if (body != NULL && apfl_refcount_dec(&body->refcount)) { + DEINIT_LIST(body->items, body->len, apfl_expr_deinit); + free(body); + } } void @@ -159,7 +163,8 @@ void apfl_expr_subfunc_deinit(struct apfl_expr_subfunc *subfunc) { apfl_expr_params_deinit(&subfunc->params); - apfl_expr_body_deinit(&subfunc->body); + apfl_expr_body_unref(subfunc->body); + subfunc->body = NULL; } void @@ -357,11 +362,11 @@ apfl_expr_call_move(struct apfl_expr_call *in) return out; } -struct apfl_expr_body -apfl_expr_body_move(struct apfl_expr_body *in) +struct apfl_expr_body * +apfl_expr_body_move(struct apfl_expr_body **in) { - struct apfl_expr_body out; - MOVE_LIST(out, in, items, len); + struct apfl_expr_body *out = *in; + *in = NULL; return out; } @@ -744,7 +749,7 @@ print_expr(struct apfl_expr *expr, unsigned indent, FILE *f) break; case APFL_EXPR_SIMPLE_FUNC: apfl_print_indented(indent, f, "Simple function @ " POSFMT "\n", POSARGS(expr->position)); - print_body(&expr->simple_func, indent+1, f); + print_body(expr->simple_func, indent+1, f); break; case APFL_EXPR_COMPLEX_FUNC: apfl_print_indented(indent, f, "Complex function @ " POSFMT "\n", POSARGS(expr->position)); @@ -756,7 +761,7 @@ print_expr(struct apfl_expr *expr, unsigned indent, FILE *f) print_params_item(&sub->params.params[j], indent+3, f); } apfl_print_indented(indent+2, f, "Body\n"); - print_body(&sub->body, indent+3, f); + print_body(sub->body, indent+3, f); } break; case APFL_EXPR_ASSIGNMENT: @@ -817,14 +822,22 @@ expr_list_eq(struct apfl_expr_list a, struct apfl_expr_list b) } static bool -body_eq(struct apfl_expr_body a, struct apfl_expr_body b) +body_eq(struct apfl_expr_body *a, struct apfl_expr_body *b) { - if (a.len != b.len) { + if (a == b) { + return true; + } + + if (a == NULL || b == NULL) { return false; } - for (size_t i = 0; i < a.len; i++) { - if (!apfl_expr_eq(a.items[i], b.items[i])) { + if (a->len != b->len) { + return false; + } + + for (size_t i = 0; i < a->len; i++) { + if (!apfl_expr_eq(a->items[i], b->items[i])) { return false; } } diff --git a/src/parser.c b/src/parser.c index f817d9c..8b5665e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1702,6 +1702,21 @@ error: return PF_ERROR; } +static bool +init_body(apfl_parser_ptr p, struct apfl_expr_body **body) +{ + if ((*body = ALLOC(struct apfl_expr_body)) == NULL) { + p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); + return false; + } + **body = (struct apfl_expr_body) { + .items = NULL, + .len = 0, + .refcount = 1, + }; + return true; +} + static bool parse_braces( apfl_parser_ptr p, @@ -1718,9 +1733,15 @@ parse_braces( struct fragment_list fragments; apfl_resizable_init(APFL_RESIZABLE_ARGS(fragments, children)); - struct apfl_expr_body body = { + struct apfl_expr_body *body; + if (!init_body(p, &body)) { + return false; + } + + *body = (struct apfl_expr_body) { .items = NULL, .len = 0, + .refcount = 1, }; size_t body_cap = 0; @@ -1737,8 +1758,8 @@ parse_braces( case PF_OK: if (!apfl_resizable_append( sizeof(struct apfl_expr), - (void **)&body.items, - &body.len, + (void **)&body->items, + &body->len, &body_cap, &expr, 1 @@ -1779,7 +1800,8 @@ parse_braces( } params = (struct apfl_expr_params) { .params = NULL, .len = 0 }; - body = (struct apfl_expr_body) { .items = NULL, .len = 0 }; + + body = NULL; body_cap = 0; } @@ -1805,7 +1827,7 @@ parse_braces( return true; case APFL_TOK_MAPSTO: - if (body.len > 0 && !has_params) { + if (body->len > 0 && !has_params) { p->error = (struct apfl_error) { .type = APFL_ERR_STATEMENTS_BEFORE_PARAMETERS, .position = p->token.position, @@ -1831,7 +1853,9 @@ parse_braces( } params = (struct apfl_expr_params) { .params = NULL, .len = 0 }; - body = (struct apfl_expr_body) { .items = NULL, .len = 0 }; + if (!init_body(p, &body)) { + goto error; + } body_cap = 0; } @@ -1851,7 +1875,7 @@ parse_braces( } error: - apfl_expr_body_deinit(&body); + apfl_expr_body_unref(body); apfl_expr_params_deinit(¶ms); fragment_list_deinit(&fragments); DEINIT_LIST(subfuncs, subfuncs_len, apfl_expr_subfunc_deinit); diff --git a/src/parser_test.c b/src/parser_test.c index a678519..86deaa1 100644 --- a/src/parser_test.c +++ b/src/parser_test.c @@ -153,6 +153,21 @@ params_item(bool expand, struct apfl_expr_param param) }; } +struct test_pre_body { + struct apfl_expr *items; + size_t len; +}; + +static struct apfl_expr_body * +create_body(struct parser_test *pt, struct test_pre_body pre_body) +{ + struct apfl_expr_body *body = must_alloc(pt->t, sizeof(struct apfl_expr_body)); + body->items = pre_body.items; + body->len = pre_body.len; + body->refcount = 1; + return body; +} + // Fugly macros to make it a bit easier to create a heap allocated struct value #define BEGIN_NEW(pt, T) ((T *)new_helper(pt, sizeof(T), &((T) #define END_NEW ))) @@ -201,7 +216,7 @@ enum listbuilder_cmd { #define LIST_ADD }, {.has_item = true, .item = MKLISTBUILDER(list, struct apfl_expr_list, struct apfl_expr_list_item, items, len) -MKLISTBUILDER(body, struct apfl_expr_body, struct apfl_expr, items, len) +MKLISTBUILDER(body, struct test_pre_body, struct apfl_expr, items, len) MKLISTBUILDER(dict, struct apfl_expr_dict, struct apfl_expr_dict_pair, items, len) MKLISTBUILDER(complex_func, struct apfl_expr_complex_func, struct apfl_expr_subfunc, subfuncs, len) MKLISTBUILDER(params, struct apfl_expr_params, struct apfl_expr_params_item, params, len) @@ -339,8 +354,8 @@ TEST(empty_function, t) { expect_expr(pt, (struct apfl_expr) { .type = APFL_EXPR_SIMPLE_FUNC, .position = POS(1, 1), - .simple_func = LIST_BEGIN(pt, body) - LIST_END, + .simple_func = create_body(pt, LIST_BEGIN(pt, body) + LIST_END), }); expect_eof(pt); destroy_parser_test(pt); @@ -548,9 +563,9 @@ TEST(factorial, t) { .constant = num_const(0), }), LIST_END, - .body = LIST_BEGIN(pt, body) + .body = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD const_expr(2, 10, num_const(1)), - LIST_END + LIST_END) }, LIST_ADD (struct apfl_expr_subfunc) { .params = LIST_BEGIN(pt, params) @@ -559,7 +574,7 @@ TEST(factorial, t) { .var = new_string(pt, "n"), }), LIST_END, - .body = LIST_BEGIN(pt, body) + .body = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD (struct apfl_expr) { .type = APFL_EXPR_CALL, .position = POS(3, 10), @@ -591,7 +606,7 @@ TEST(factorial, t) { LIST_END, }, }, - LIST_END + LIST_END) }, LIST_END } END_NEW @@ -643,14 +658,14 @@ TEST(map, t) { LIST_END, }), LIST_END, - .body = LIST_BEGIN(pt, body) + .body = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD (struct apfl_expr) { .type = APFL_EXPR_LIST, .position = POS(2, 9), .list = LIST_BEGIN(pt, list) LIST_END, }, - LIST_END, + LIST_END), }, LIST_ADD (struct apfl_expr_subfunc) { .params = LIST_BEGIN(pt, params) @@ -672,7 +687,7 @@ TEST(map, t) { LIST_END, }), LIST_END, - .body = LIST_BEGIN(pt, body) + .body = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD (struct apfl_expr) { .type = APFL_EXPR_LIST, .position = POS(4, 5), @@ -700,7 +715,7 @@ TEST(map, t) { } END_NEW), LIST_END, }, - LIST_END + LIST_END) }, LIST_END, } END_NEW, @@ -977,12 +992,12 @@ TEST(simple_function, t) { expect_expr(pt, (struct apfl_expr) { .type = APFL_EXPR_SIMPLE_FUNC, .position = POS(1, 1), - .simple_func = LIST_BEGIN(pt, body) + .simple_func = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD (struct apfl_expr) { .type = APFL_EXPR_SIMPLE_FUNC, .position = POS(1, 2), - .simple_func = LIST_BEGIN(pt, body) - LIST_END, + .simple_func = create_body(pt, LIST_BEGIN(pt, body) + LIST_END), }, LIST_ADD (struct apfl_expr) { .type = APFL_EXPR_CALL, @@ -994,7 +1009,7 @@ TEST(simple_function, t) { LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) { .type = APFL_EXPR_SIMPLE_FUNC, .position = POS(3, 5), - .simple_func = LIST_BEGIN(pt, body) + .simple_func = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD (struct apfl_expr) { .type = APFL_EXPR_ASSIGNMENT, .position = POS(4, 9), @@ -1006,13 +1021,13 @@ TEST(simple_function, t) { }, LIST_ADD var(pt, 5, 5, "a"), LIST_ADD var(pt, 6, 5, "b"), - LIST_END, + LIST_END), } END_NEW), LIST_END, }, }, LIST_ADD var(pt, 7, 4, "c"), - LIST_END, + LIST_END), }); destroy_parser_test(pt); } @@ -1070,11 +1085,11 @@ TEST(complex_function, t) { }, }), LIST_END, - .body = LIST_BEGIN(pt, body) + .body = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD var(pt, 1, 21, "foo"), LIST_ADD var(pt, 1, 26, "bar"), LIST_ADD var(pt, 2, 5, "baz"), - LIST_END, + LIST_END), }, LIST_ADD { .params = LIST_BEGIN(pt, params) @@ -1088,8 +1103,8 @@ TEST(complex_function, t) { LIST_END, }), LIST_END, - .body = LIST_BEGIN(pt, body) - LIST_END, + .body = create_body(pt, LIST_BEGIN(pt, body) + LIST_END), }, LIST_ADD { .params = LIST_BEGIN(pt, params) @@ -1117,7 +1132,7 @@ TEST(complex_function, t) { LIST_END }), LIST_END, - .body = LIST_BEGIN(pt, body) + .body = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD var(pt, 4, 5, "a"), LIST_ADD var(pt, 5, 5, "b"), LIST_ADD { @@ -1137,16 +1152,16 @@ TEST(complex_function, t) { .var = new_string(pt, "x"), }), LIST_END, - .body = LIST_BEGIN(pt, body) + .body = create_body(pt, LIST_BEGIN(pt, body) LIST_ADD var(pt, 6, 14, "y"), - LIST_END + LIST_END), } LIST_END } END_NEW), LIST_END, }, } - LIST_END + LIST_END), }, LIST_END, });