parser: Fix parsing assignments
This commit is contained in:
parent
86e1c1339d
commit
d853ba40ad
1 changed files with 59 additions and 87 deletions
146
src/parser.c
146
src/parser.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue