expr: Make body objects refcounted

We'll soon need this, once we implement function definitions
This commit is contained in:
Laria 2022-01-22 17:16:28 +01:00
parent 0ab36ec37e
commit db0fb2aee4
4 changed files with 103 additions and 50 deletions

View file

@ -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 *);

View file

@ -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;
}
}

View file

@ -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(&params);
fragment_list_deinit(&fragments);
DEINIT_LIST(subfuncs, subfuncs_len, apfl_expr_subfunc_deinit);

View file

@ -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,
});