parser: Fix parsing assignments

This commit is contained in:
Laria 2021-12-15 23:35:10 +01:00
parent 86e1c1339d
commit d853ba40ad

View file

@ -1282,21 +1282,22 @@ error:
return false;
}
static bool
fragment_to_partial_assignment(
apfl_parser_ptr p,
bool local,
struct fragment fragment,
struct apfl_expr_assignment *out
) {
out->local = local;
out->rhs = NULL;
struct partial_assignment {
struct apfl_expr_assignable lhs;
bool local;
struct apfl_position position;
};
bool rv = fragment_to_assignable(p, false, fragment, &out->lhs);
fragment_deinit(&fragment);
return rv;
static void
partial_assignment_deinit(struct partial_assignment *pa)
{
apfl_expr_assignable_deinit(&pa->lhs);
}
struct partial_assignment_list {
APFL_RESIZABLE_TRAIT(struct partial_assignment, items)
};
enum parse_body_or_toplevel_finalize_result {
BODY_FINALIZE_ERROR,
BODY_FINALIZE_OK,
@ -1363,25 +1364,18 @@ error:
return false;
}
struct partial_assignment {
struct apfl_expr_assignable lhs;
bool local;
struct apfl_position position;
};
static enum parse_body_or_toplevel_finalize_result
parse_body_or_toplevel_finalize(
apfl_parser_ptr p,
struct fragment_list *fragments,
struct apfl_expr **leftmost_assignment_expr,
struct apfl_expr *rightmost_assignment_expr,
struct partial_assignment_list partial_assignments,
struct apfl_expr *out
) {
if (fragments->len == 0) {
if (rightmost_assignment_expr != NULL) {
if (partial_assignments.len > 0) {
p->error = (struct apfl_error) {
.type = APFL_ERR_EMPTY_ASSIGNMENT,
.position = rightmost_assignment_expr->position,
.position = partial_assignments.items[partial_assignments.len-1].position,
};
goto error;
}
@ -1389,28 +1383,18 @@ parse_body_or_toplevel_finalize(
return BODY_FINALIZE_EMPTY;
}
// Nasty pointer juggling: If there are no assignments, we want to put the
// expression generated from the fragments to go directly to the output.
// Otherwise we want to store it in the right-hand-side of the rightmost
// assignment expression and the leftmost assignment expression becomes the
// output.
struct apfl_expr *dest = NULL;
if (rightmost_assignment_expr == NULL) {
dest = out;
} else {
assert(*leftmost_assignment_expr != NULL);
*out = **leftmost_assignment_expr;
free(*leftmost_assignment_expr);
*leftmost_assignment_expr = NULL;
assert(rightmost_assignment_expr->type == APFL_EXPR_ASSIGNMENT);
rightmost_assignment_expr->assignment.rhs = malloc(sizeof(struct apfl_expr));
if (rightmost_assignment_expr->assignment.rhs == NULL) {
struct apfl_expr *dest = out;
for (size_t i = 0; i < partial_assignments.len; i++) {
struct partial_assignment *cur = &partial_assignments.items[i];
dest->type = APFL_EXPR_ASSIGNMENT;
dest->position = cur->position;
dest->assignment.local = cur->local;
dest->assignment.lhs = apfl_expr_assignable_move(&cur->lhs);
if ((dest->assignment.rhs = ALLOC(struct apfl_expr)) == NULL) {
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
goto error;
}
dest = rightmost_assignment_expr->assignment.rhs;
dest = dest->assignment.rhs;
}
if (fragments->len == 1) {
@ -1424,14 +1408,24 @@ parse_body_or_toplevel_finalize(
}
fragment_list_deinit(fragments);
DEINIT_LIST(partial_assignments.items, partial_assignments.len, partial_assignment_deinit);
return BODY_FINALIZE_OK;
error:
DEINIT_LIST(partial_assignments.items, partial_assignments.len, partial_assignment_deinit);
apfl_expr_deinit(out);
return BODY_FINALIZE_ERROR;
}
static struct partial_assignment_list
partial_assignment_list_move(struct partial_assignment_list *in)
{
struct partial_assignment_list out = *in;
apfl_resizable_init(APFL_RESIZABLE_ARGS(*in, items));
return out;
}
static enum parse_fragment_result
parse_body_or_toplevel(
apfl_parser_ptr p,
@ -1440,17 +1434,13 @@ parse_body_or_toplevel(
struct apfl_expr *out,
bool need
) {
// struct partial_assignment *partial_assignments = NULL;
// size_t partial_assignment_len = 0;
// size_t partial_assignment_cap = 0;
struct apfl_expr *leftmost_assignment_expr = NULL;
struct apfl_expr *rightmost_assignment_expr = NULL;
struct partial_assignment_list partial_assignments;
apfl_resizable_init(APFL_RESIZABLE_ARGS(partial_assignments, items));
bool first;
first = true;
for (;;) {
first = true;
for (;;) {
switch (parse_fragment_into_list(p, fragments, need || !first, 0)) {
case PF_OK:
@ -1462,8 +1452,7 @@ parse_body_or_toplevel(
switch (parse_body_or_toplevel_finalize(
p,
fragments,
&leftmost_assignment_expr,
rightmost_assignment_expr,
partial_assignment_list_move(&partial_assignments),
out
)) {
case BODY_FINALIZE_OK:
@ -1510,47 +1499,27 @@ break_inner:
goto error;
}
// \mystuff\TODO:
// if (!apfl_resizable_grow_cap(
// sizeof(struct partial_assignment),
// (void **)partial_assignments,
// &partial_assignment_len,
// &partial_assignment_cap,
// 1
// )) {
// p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
// goto error;
// }
struct apfl_expr *cur_assignment_expr = ALLOC(struct apfl_expr);
if (cur_assignment_expr == NULL) {
if (!apfl_resizable_grow_cap(
sizeof(struct partial_assignment),
APFL_RESIZABLE_ARGS(partial_assignments, items),
1
)) {
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
goto error;
}
cur_assignment_expr->type = APFL_EXPR_ASSIGNMENT;
cur_assignment_expr->position = position;
struct partial_assignment *cur_partial = &partial_assignments.items[partial_assignments.len];
cur_partial->local = local;
cur_partial->position = position;
struct fragment fragment = fragment_move(&fragments->children[0]);
fragment_list_deinit(fragments); // Reset fragment list
if (!fragment_to_partial_assignment(
p,
local,
fragment,
&cur_assignment_expr->assignment
)) {
free(cur_assignment_expr);
if (!fragment_to_assignable(p, false, fragment, &cur_partial->lhs)) {
goto error;
}
if (rightmost_assignment_expr == NULL) {
assert(leftmost_assignment_expr == NULL);
leftmost_assignment_expr = cur_assignment_expr;
rightmost_assignment_expr = cur_assignment_expr;
} else {
rightmost_assignment_expr->assignment.rhs = cur_assignment_expr;
rightmost_assignment_expr = cur_assignment_expr;
}
partial_assignments.len++;
break;
case APFL_TOK_RBRACE:
@ -1562,8 +1531,7 @@ break_inner:
switch (parse_body_or_toplevel_finalize(
p,
fragments,
&leftmost_assignment_expr,
rightmost_assignment_expr,
partial_assignment_list_move(&partial_assignments),
out
)) {
case BODY_FINALIZE_OK:
@ -1584,7 +1552,7 @@ break_inner:
}
break;
default:
if (leftmost_assignment_expr != NULL) {
if (partial_assignments.len > 0) {
p->error = ERR_UNEXPECTED_TOKEN(p->token);
goto error;
}
@ -1595,7 +1563,7 @@ break_inner:
}
error: // \mystuff\TODO:also on other non ok results???
DESTROY(leftmost_assignment_expr, apfl_expr_deinit);
DEINIT_LIST(partial_assignments.items, partial_assignments.len, partial_assignment_deinit);
return PF_ERROR;
}
@ -1698,9 +1666,9 @@ parse_braces(
body_cap = 0;
}
return PF_OK;
DEINIT_LIST(fragments.children, fragments.len, fragment_deinit);
break;
return PF_OK;
case APFL_TOK_MAPSTO:
if (body.len > 0 && !has_params) {
p->error = (struct apfl_error) {
@ -1982,10 +1950,14 @@ apfl_parser_get_expr(apfl_parser_ptr p)
void
apfl_parser_destroy(apfl_parser_ptr p)
{
if (p == NULL) {
return;
}
if (p->has_expr) {
apfl_expr_deinit(&p->expr);
}
if (p->has_token) {
apfl_token_deinit(&p->token);
}
free(p);
}