expr: Make body objects refcounted
We'll soon need this, once we implement function definitions
This commit is contained in:
parent
0ab36ec37e
commit
db0fb2aee4
4 changed files with 103 additions and 50 deletions
|
|
@ -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 *);
|
||||
|
|
|
|||
41
src/expr.c
41
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
38
src/parser.c
38
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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue