Continue work on parser

- Simplify return types: Many functions that returned
  `enum parse_fragment_result` only ever returned PF_OK or PF_ERROR.
  Changing these functions to return bool simplifies things a lot. This
  also helped in identifying some places where I didn't handle all
  parse_fragment_result values properly.
- More cleaning up
- Allow linebreaks inside parenthesis
This commit is contained in:
Laria 2021-12-16 22:07:18 +01:00
parent d853ba40ad
commit e79945a398

View file

@ -362,14 +362,6 @@ err_unexpected_token(enum apfl_token_type token_type, struct apfl_position pos)
#define ERR_UNEXPECTED_TOKEN(t) (err_unexpected_token((t).type, (t).position))
// Must only be called after an PF_CANT_HANDLE!
static enum parse_fragment_result
unexpected_cant_handle(apfl_parser_ptr p)
{
p->error = ERR_UNEXPECTED_TOKEN(p->token);
return PF_ERROR;
}
static enum parse_fragment_result
parse_fragment_into_list(apfl_parser_ptr p, struct fragment_list *list, bool need, enum parse_fragment_flags flags)
{
@ -405,62 +397,67 @@ static bool fragments_to_call(
struct apfl_expr *
);
static enum parse_fragment_result
parse_parens_head(apfl_parser_ptr p, struct fragment_list *children)
{
return parse_fragment_into_list(p, children, true, FFLAG_NO_EXPAND); // \mystuff\TODO:more flags?
}
static enum parse_fragment_result
parse_parens_tail(apfl_parser_ptr p, struct fragment_list *children, struct apfl_position position)
{
enum parse_fragment_result result;
for (;;) {
result = parse_fragment_into_list(p, children, true, 0); // \mystuff\TODO:more flags?
if (result != PF_OK) {
break;
}
}
switch (result) {
static bool
parse_parens_head(
apfl_parser_ptr p,
struct fragment_list *children,
struct apfl_position position
) {
switch (parse_fragment_into_list(p, children, true, FFLAG_NO_EXPAND)) {
case PF_OK:
assert(false); // already handled
return true;
case PF_EOF:
p->error = err_unexpected_eof_after(APFL_TOK_LPAREN, position);
return PF_ERROR;
return false;
case PF_CANT_HANDLE:
break;
read_token_after_cant_handle(p);
p->error = ERR_UNEXPECTED_TOKEN(p->token);
return false;
case PF_ERROR:
return PF_ERROR;
return false;
}
assert(result == PF_CANT_HANDLE);
read_token_after_cant_handle(p);
assert(false);
}
if (p->token.type == APFL_TOK_RPAREN) {
return PF_OK;
// \mystuff\TODO:finalize list somehow?
} else {
p->error = ERR_UNEXPECTED_TOKEN(p->token);
return PF_ERROR;
static bool
parse_parens_tail(apfl_parser_ptr p, struct fragment_list *children, struct apfl_position position)
{
for (;;) {
switch (parse_fragment_into_list(p, children, true, 0)) {
case PF_OK:
break;
case PF_EOF:
p->error = err_unexpected_eof_after(APFL_TOK_LPAREN, position);
return false;
case PF_CANT_HANDLE:
read_token_after_cant_handle(p);
if (p->token.type == APFL_TOK_RPAREN) {
return true;
} else if (p->token.type == APFL_TOK_LINEBREAK) {
// Ignore linebreaks inside (...)
break;
} else {
p->error = ERR_UNEXPECTED_TOKEN(p->token);
return false;
}
case PF_ERROR:
return false;
}
}
}
static enum parse_fragment_result
static bool
parse_parens(apfl_parser_ptr p, struct fragment *out, struct apfl_position position)
{
struct fragment_list children;
apfl_resizable_init(APFL_RESIZABLE_ARGS(children, children));
enum parse_fragment_result result;
result = parse_parens_head(p, &children);
if (result != PF_OK) {
if (!parse_parens_head(p, &children, position)) {
goto error;
}
result = parse_parens_tail(p, &children, position);
if (result != PF_OK) {
if (!parse_parens_tail(p, &children, position)) {
goto error;
}
@ -471,15 +468,15 @@ parse_parens(apfl_parser_ptr p, struct fragment *out, struct apfl_position posit
goto error;
}
return PF_OK;
return true;
error:
// \mystuff\TODO:cleanup
fragment_list_deinit(&children);
return result;
return false;
}
static enum parse_fragment_result
static bool
skip_inner_bracket_separators(apfl_parser_ptr p)
{
for (;;) {
@ -494,25 +491,23 @@ skip_inner_bracket_separators(apfl_parser_ptr p)
}
unread_token(p);
return PF_OK;
return true;
case APFL_PARSE_EOF:
return PF_OK;
return true;
case APFL_PARSE_ERROR:
return PF_ERROR;
return false;
}
}
}
static enum parse_fragment_result
static bool
parse_empty_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_position position)
{
// We already got `[ ->`, we now read another (non separator) token and return success, if it's an `]`.
// Else it's a syntax error
enum parse_fragment_result result;
result = skip_inner_bracket_separators(p);
if (result != PF_OK) {
return result;
if (!skip_inner_bracket_separators(p)) {
return false;
}
switch (read_token(p, true)) {
@ -520,15 +515,14 @@ parse_empty_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_position p
break;
case APFL_PARSE_EOF:
p->error = apfl_error_simple(APFL_ERR_UNEXPECTED_EOF);
return PF_ERROR;
return false;
case APFL_PARSE_ERROR:
return PF_ERROR;
return false;
}
if (p->token.type != APFL_TOK_RBRACKET) {
p->error = ERR_UNEXPECTED_TOKEN(p->token);
return PF_ERROR;
return false;
}
out->type = FRAG_EXPR;
@ -539,11 +533,11 @@ parse_empty_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_position p
.position = position,
};
out->position = position;
return PF_OK;
return true;
}
// Must only be called after PF_CANT_HANDLE
static enum parse_fragment_result
static bool
parse_empty_list_or_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_position position)
{
read_token_after_cant_handle(p);
@ -556,12 +550,12 @@ parse_empty_list_or_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_po
.len = 0,
};
out->position = position;
return PF_OK;
return true;
case APFL_TOK_MAPSTO:
return parse_empty_dict(p, out, position);
default:
p->error = ERR_UNEXPECTED_TOKEN(p->token);
return PF_ERROR;
return false;
}
}
@ -656,7 +650,7 @@ fragment_to_expr_allocated(apfl_parser_ptr p, struct fragment fragment)
return out;
}
static enum parse_fragment_result
static bool
parse_dict(
apfl_parser_ptr p,
struct fragment *out,
@ -669,8 +663,6 @@ parse_dict(
bool cleanup_key = true;
bool cleanup_value = false;
enum parse_fragment_result result;
struct apfl_expr_dict dict = {
.items = NULL,
.len = 0,
@ -680,18 +672,16 @@ parse_dict(
goto after_mapsto;
for (;;) {
result = skip_inner_bracket_separators(p);
if (result != PF_OK) {
if (!skip_inner_bracket_separators(p)) {
goto error;
}
switch ((result = parse_fragment(p, &key, true, FFLAG_NO_EXPAND))) {
switch (parse_fragment(p, &key, true, FFLAG_NO_EXPAND)) {
case PF_OK:
cleanup_key = true;
break;
case PF_EOF:
p->error = err_unexpected_eof_after(APFL_TOK_LBRACKET, start);
result = PF_ERROR;
goto error;
case PF_CANT_HANDLE:
goto maybe_end;
@ -699,8 +689,7 @@ parse_dict(
goto error;
}
result = skip_inner_bracket_separators(p);
if (result != PF_OK) {
if (!skip_inner_bracket_separators(p)) {
goto error;
}
@ -709,10 +698,8 @@ parse_dict(
break;
case APFL_PARSE_EOF:
p->error = err_unexpected_eof_after(APFL_TOK_LBRACKET, start);
result = PF_ERROR;
goto error;
case APFL_PARSE_ERROR:
result = PF_ERROR;
goto error;
}
@ -724,22 +711,21 @@ parse_dict(
mapsto_pos = p->token.position;
after_mapsto:
result = skip_inner_bracket_separators(p);
if (result != PF_OK) {
if (!skip_inner_bracket_separators(p)) {
goto error;
}
struct fragment value;
switch ((result = parse_fragment(p, &value, true, FFLAG_NO_EXPAND))) {
switch (parse_fragment(p, &value, true, FFLAG_NO_EXPAND)) {
case PF_OK:
cleanup_value = true;
break;
case PF_EOF:
p->error = err_unexpected_eof_after(APFL_TOK_MAPSTO, mapsto_pos);
result = PF_ERROR;
goto error;
case PF_CANT_HANDLE:
result = unexpected_cant_handle(p);
read_token_after_cant_handle(p);
p->error = ERR_UNEXPECTED_TOKEN(p->token);
goto error;
case PF_ERROR:
goto error;
@ -747,10 +733,9 @@ after_mapsto:
struct apfl_expr_dict_pair pair;
if (
(pair.k = fragment_to_expr_allocated(p, key)) == NULL
|| (pair.v = fragment_to_expr_allocated(p, value)) == NULL
(pair.k = fragment_to_expr_allocated(p, fragment_move(&key))) == NULL
|| (pair.v = fragment_to_expr_allocated(p, fragment_move(&value))) == NULL
) {
result = PF_ERROR;
goto error;
}
@ -769,7 +754,7 @@ after_mapsto:
)) {
// \mystuff\TODO:destroy pair!
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
return PF_ERROR;
return false;
}
}
@ -789,7 +774,7 @@ maybe_end:
.position = start,
};
out->position = start;
return PF_OK;
return true;
error:
if (cleanup_key) {
@ -799,10 +784,10 @@ error:
fragment_deinit(&value);
}
free(dict.items); // \mystuff\TODO:also destroy all items!
return result;
return false;
}
static enum parse_fragment_result
static bool
parse_list(
apfl_parser_ptr p,
struct fragment *out,
@ -815,7 +800,7 @@ parse_list(
if (!append_fragment(&list, first)) {
fragment_deinit(&first);
p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED);
return PF_ERROR;
return false;
}
for (;;) {
@ -843,20 +828,18 @@ maybe_end:
out->list = list;
out->position = start;
return PF_OK;
return true;
error:
// \mystuff\TODO:clean up list
return PF_ERROR;
return false;
}
static enum parse_fragment_result
static bool
parse_brackets(apfl_parser_ptr p, struct fragment *out, struct apfl_position start)
{
enum parse_fragment_result result;
result = skip_inner_bracket_separators(p);
if (result != PF_OK) {
return result;
if (!skip_inner_bracket_separators(p)) {
return false;
}
struct fragment first;
@ -867,13 +850,12 @@ parse_brackets(apfl_parser_ptr p, struct fragment *out, struct apfl_position sta
return parse_empty_list_or_dict(p, out, start);
case PF_EOF:
p->error = err_unexpected_eof_after(APFL_TOK_LBRACKET, start);
return PF_ERROR;
return false;
case PF_ERROR:
return PF_ERROR;
return false;
}
result = skip_inner_bracket_separators(p);
if (result != PF_OK) {
if (!skip_inner_bracket_separators(p)) {
goto error;
}
@ -882,10 +864,8 @@ parse_brackets(apfl_parser_ptr p, struct fragment *out, struct apfl_position sta
break;
case APFL_PARSE_EOF:
p->error = err_unexpected_eof_after(APFL_TOK_LBRACKET, start);
result = PF_ERROR;
goto error;
case APFL_PARSE_ERROR:
result = PF_ERROR;
goto error;
}
@ -899,7 +879,7 @@ parse_brackets(apfl_parser_ptr p, struct fragment *out, struct apfl_position sta
error:
fragment_deinit(&first);
return result;
return false;
}
static bool
@ -1567,7 +1547,7 @@ error: // \mystuff\TODO:also on other non ok results???
return PF_ERROR;
}
static enum parse_fragment_result
static bool
parse_braces(
apfl_parser_ptr p,
struct fragment *out,
@ -1668,7 +1648,7 @@ parse_braces(
DEINIT_LIST(fragments.children, fragments.len, fragment_deinit);
return PF_OK;
return true;
case APFL_TOK_MAPSTO:
if (body.len > 0 && !has_params) {
p->error = (struct apfl_error) {
@ -1717,7 +1697,7 @@ parse_braces(
error:
// \mystuff\TODO:cleanup
return PF_ERROR;
return false;
}
static enum parse_fragment_result
@ -1739,13 +1719,19 @@ parse_fragment(apfl_parser_ptr p, struct fragment *fragment, bool need, enum par
switch (p->token.type) {
case APFL_TOK_LPAREN:
result = parse_parens(p, fragment, p->token.position);
if (!parse_parens(p, fragment, p->token.position)) {
goto error;
}
break;
case APFL_TOK_LBRACKET:
result = parse_brackets(p, fragment, p->token.position);
if (!parse_brackets(p, fragment, p->token.position)) {
goto error;
}
break;
case APFL_TOK_LBRACE:
result = parse_braces(p, fragment, p->token.position);
if (!parse_braces(p, fragment, p->token.position)) {
goto error;
}
break;
case APFL_TOK_EXPAND:
if (flags & FFLAG_NO_EXPAND) {