diff --git a/src/parser.c b/src/parser.c index cc813c7..db08a03 100644 --- a/src/parser.c +++ b/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); }