From c288c333ca650943adfb19775a96db3de8ab1db2 Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Wed, 15 Dec 2021 21:28:44 +0100 Subject: [PATCH] Continue work on parser Seems that we can parse most things now :). Assignments don't work yet, thoug. Also we're currently leaking memory pretty badly. --- src/Makefile.am | 1 + src/apfl.h | 9 +- src/main.c | 22 ++- src/parser.c | 483 +++++++++++++++++++++++++++++++++++++++--------- src/tokenizer.c | 30 +++ 5 files changed, 449 insertions(+), 96 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ce4a37f..92ae728 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,6 +10,7 @@ libapfl_a_SOURCES += resizable.c libapfl_a_SOURCES += strings.c libapfl_a_SOURCES += token.c libapfl_a_SOURCES += tokenizer.c +libapfl_a_SOURCES += parser.c apfl_internal_headers = apfl_internal_headers += common.h diff --git a/src/apfl.h b/src/apfl.h index b2fd227..98fac6c 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -389,7 +389,6 @@ struct apfl_expr_at apfl_expr_at_move(struct apfl_expr_at *); // End move functions - enum apfl_parse_result { APFL_PARSE_OK, APFL_PARSE_EOF, @@ -427,6 +426,8 @@ struct apfl_parser_token_source { void *opaque; }; +struct apfl_parser_token_source apfl_tokenizer_as_token_source(apfl_tokenizer_ptr); + struct apfl_parser; typedef struct apfl_parser *apfl_parser_ptr; @@ -447,6 +448,12 @@ enum apfl_parse_result apfl_parser_next(apfl_parser_ptr); */ struct apfl_error apfl_parser_get_error(apfl_parser_ptr); +/* Get the current expression. + * Return value is undefined when the last call to apfl_parser_next did not + * return APFL_PARSE_OK. + */ +struct apfl_expr apfl_parser_get_expr(apfl_parser_ptr); + #ifdef __cplusplus } #endif diff --git a/src/main.c b/src/main.c index a12c0a9..1efa056 100644 --- a/src/main.c +++ b/src/main.c @@ -37,26 +37,33 @@ main(int argc, const char **argv) int rv = 0; apfl_tokenizer_ptr tokenizer = NULL; - if (!(tokenizer = apfl_tokenizer_new(repl_source_reader, NULL))) { + apfl_parser_ptr parser = NULL; + + if ((tokenizer = apfl_tokenizer_new(repl_source_reader, NULL)) == NULL) { fprintf(stderr, "Failed initializing tokenizer\n"); goto exit; } + if ((parser = apfl_parser_new(apfl_tokenizer_as_token_source(tokenizer))) == NULL) { + fprintf(stderr, "Failed initializing parser\n"); + goto exit; + } + while (true) { struct apfl_error err; - struct apfl_token token; + struct apfl_expr expr; - switch (apfl_tokenizer_next(tokenizer, false)) { + switch (apfl_parser_next(parser)) { case APFL_PARSE_OK: - token = apfl_tokenizer_get_token(tokenizer); - apfl_token_print(token, stdout); - apfl_token_deinit(&token); + expr = apfl_parser_get_expr(parser); + apfl_expr_print(expr, stdout); + apfl_expr_deinit(&expr); break; case APFL_PARSE_EOF: goto exit; case APFL_PARSE_ERROR: - err = apfl_tokenizer_get_error(tokenizer); + err = apfl_parser_get_error(parser); apfl_error_print(err, stderr); if (APFL_ERROR_IS_FATAL(err)) { @@ -69,6 +76,7 @@ main(int argc, const char **argv) exit: apfl_tokenizer_destroy(tokenizer); + apfl_parser_destroy(parser); return rv; } diff --git a/src/parser.c b/src/parser.c index d0686dc..cc813c7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -10,6 +10,8 @@ struct apfl_parser { struct apfl_parser_token_source token_source; + bool has_expr; + struct apfl_expr expr; struct apfl_error error; bool eof; @@ -27,6 +29,7 @@ enum parse_fragment_result { enum parse_fragment_flags { FFLAG_NO_EXPAND = 1, + FFLAG_NO_POSTFIXS = 2, }; enum fragment_type { @@ -126,6 +129,7 @@ fragment_deinit(struct fragment *fragment) break; case FRAG_NAME: apfl_string_deinit(&fragment->name); + break; case FRAG_DOT: DESTROY(fragment->dot.lhs, fragment_deinit); apfl_string_deinit(&fragment->dot.rhs); @@ -166,7 +170,7 @@ fragment_lhs_rhs_move(struct fragment_lhs_rhs *in) static struct fragment_list fragment_list_move(struct fragment_list *in) { - struct fragment_list out; + struct fragment_list out = *in; MOVEPTR(out.children, in->children); in->len = 0; in->cap = 0; @@ -201,7 +205,7 @@ fragment_move(struct fragment *in) out.expr = apfl_expr_move(&in->expr); break; case FRAG_LIST: - out.list = fragment_list_move(&in->fragment); + out.list = fragment_list_move(&in->list); break; } @@ -220,6 +224,7 @@ apfl_parser_new(struct apfl_parser_token_source token_source) p->eof = false; p->has_token = false; p->has_unread = false; + p->has_expr = false; return p; } @@ -343,8 +348,6 @@ read_token_after_cant_handle(apfl_parser_ptr p) // A function that returns PF_CANT_HANDLE always unreads a token, so we are // guaranteed to have at least one token. assert(read_token(p, true) == APFL_PARSE_OK); - - return &p->token; } static struct apfl_error @@ -386,8 +389,24 @@ parse_fragment_into_list(apfl_parser_ptr p, struct fragment_list *list, bool nee return PF_OK; } +static struct apfl_error +err_unexpected_eof_after(enum apfl_token_type token_type, struct apfl_position pos) +{ + return (struct apfl_error) { + .type = APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN, + .token_type = token_type, + .position = pos, + }; +} + +static bool fragments_to_call( + apfl_parser_ptr, + struct fragment_list *, + struct apfl_expr * +); + static enum parse_fragment_result -parse_parens_head(apfl_parser_ptr p, struct fragment_list *children, struct apfl_position position) +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? } @@ -407,7 +426,8 @@ parse_parens_tail(apfl_parser_ptr p, struct fragment_list *children, struct apfl case PF_OK: assert(false); // already handled case PF_EOF: - // \mystuff\TODO:unexpected eof + p->error = err_unexpected_eof_after(APFL_TOK_LPAREN, position); + return PF_ERROR; case PF_CANT_HANDLE: break; case PF_ERROR: @@ -418,16 +438,12 @@ parse_parens_tail(apfl_parser_ptr p, struct fragment_list *children, struct apfl read_token_after_cant_handle(p); if (p->token.type == APFL_TOK_RPAREN) { - result = PF_OK; + return PF_OK; // \mystuff\TODO:finalize list somehow? } else { - p->error = (struct apfl_error) { - // \mystuff\TODO:unexpected token error - }; - result = PF_ERROR; + p->error = ERR_UNEXPECTED_TOKEN(p->token); + return PF_ERROR; } - - return result; } static enum parse_fragment_result @@ -438,23 +454,26 @@ parse_parens(apfl_parser_ptr p, struct fragment *out, struct apfl_position posit enum parse_fragment_result result; - result = parse_parens_head(p, &children, position); + result = parse_parens_head(p, &children); if (result != PF_OK) { - goto fail; + goto error; } result = parse_parens_tail(p, &children, position); if (result != PF_OK) { - goto fail; + goto error; } out->type = FRAG_EXPR; - out->expr = TODO(); // \mystuff\TODO: out->position = position; + if (!fragments_to_call(p, &children, &out->expr)) { + goto error; + } + return PF_OK; -fail: +error: // \mystuff\TODO:cleanup return result; @@ -512,7 +531,13 @@ parse_empty_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_position p return PF_ERROR; } - out->type = FRAG_EMPTY_DICT; + out->type = FRAG_EXPR; + out->expr = (struct apfl_expr) { + .type = APFL_EXPR_DICT, + .dict.items = NULL, + .dict.len = 0, + .position = position, + }; out->position = position; return PF_OK; } @@ -521,11 +546,15 @@ parse_empty_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_position p static enum parse_fragment_result parse_empty_list_or_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_position position) { - assert(p->has_token); + read_token_after_cant_handle(p); switch (p->token.type) { case APFL_TOK_RBRACKET: - out->type = FRAG_EMPTY_LIST; + out->type = FRAG_LIST; + out->list = (struct fragment_list) { + .children = NULL, + .len = 0, + }; out->position = position; return PF_OK; case APFL_TOK_MAPSTO: @@ -536,20 +565,79 @@ parse_empty_list_or_dict(apfl_parser_ptr p, struct fragment *out, struct apfl_po } } -static struct apfl_error -err_unexpected_eof_after(enum apfl_token_type token_type, struct apfl_position pos) -{ - return (struct apfl_error) { - .type = APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN, - .token_type = token_type, - .position = pos, - }; -} +static bool fragment_to_list_item( + apfl_parser_ptr, + struct fragment, + struct apfl_expr_list_item * +); + +static struct apfl_expr *fragment_to_expr_allocated(apfl_parser_ptr, struct fragment); static bool fragment_to_expr(apfl_parser_ptr p, struct fragment fragment, struct apfl_expr *out) { - // \mystuff\TODO: + switch (fragment.type) { + case FRAG_EXPAND: + p->error = err_unexpected_token(APFL_TOK_EXPAND, fragment.position); + return false; + case FRAG_CONSTANT: + out->type = APFL_EXPR_CONSTANT; + out->constant = fragment.constant; + out->position = fragment.position; + return true; + case FRAG_NAME: + out->type = APFL_EXPR_VAR; + out->var = apfl_string_move(&fragment.name); + out->position = fragment.position; + return true; + case FRAG_DOT: + out->type = APFL_EXPR_DOT; + if ((out->dot.lhs = fragment_to_expr_allocated(p, fragment_move(fragment.dot.lhs))) == NULL) { + return false; + } + out->dot.rhs = apfl_string_move(&fragment.dot.rhs); + out->position = fragment.position; + return true; + case FRAG_AT: + out->type = APFL_EXPR_AT; + if ((out->at.lhs = fragment_to_expr_allocated(p, fragment_move(fragment.at.lhs))) == NULL) { + return false; + } + if ((out->at.rhs = fragment_to_expr_allocated(p, fragment_move(fragment.at.rhs))) == NULL) { + return false; + } + out->position = fragment.position; + return true; + case FRAG_PREDICATE: + p->error = err_unexpected_token(APFL_TOK_QUESTION_MARK, fragment.position); + return false; + case FRAG_EXPR: + *out = apfl_expr_move(&fragment.expr); + return true; + case FRAG_LIST: + out->type = APFL_EXPR_LIST; + out->position = fragment.position; + out->list.len = 0; + if (fragment.list.len == 0) { + out->list.items = NULL; + return true; + } + if ((out->list.items = ALLOC_LIST(struct apfl_expr_list_item, fragment.list.len)) == NULL) { + p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); + fragment_deinit(&fragment); + return false; + } + for (size_t i = 0; i < fragment.list.len; i++) { + if (!fragment_to_list_item(p, fragment_move(&fragment.list.children[i]), &out->list.items[i])) { + fragment_deinit(&fragment); + return false; + } + out->list.len++; + } + return true; + } + + assert(false); } static struct apfl_expr * @@ -558,14 +646,14 @@ fragment_to_expr_allocated(apfl_parser_ptr p, struct fragment fragment) struct apfl_expr *out = malloc(sizeof(struct apfl_expr)); if (out == NULL) { p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); - return false; + return NULL; } if (!fragment_to_expr(p, fragment, out)) { free(out); - return false; + return NULL; } - return true; + return out; } static enum parse_fragment_result @@ -673,7 +761,7 @@ after_mapsto: if (!apfl_resizable_append( sizeof(struct apfl_expr_dict_pair), - &dict.items, + (void **)&dict.items, &dict.len, &dict_cap, &pair, @@ -695,7 +783,7 @@ maybe_end: } out->type = FRAG_EXPR, - out->expr.type = (struct apfl_expr) { + out->expr = (struct apfl_expr) { .type = APFL_EXPR_DICT, .dict = dict, .position = start, @@ -814,13 +902,13 @@ error: return result; } -static enum parse_fragment_result +static bool parse_expand(apfl_parser_ptr p, struct fragment *fragment, struct apfl_position position) { struct fragment *inner = malloc(sizeof(struct fragment)); if (inner == NULL) { p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); - return PF_ERROR; + return false; } enum parse_fragment_result result = parse_fragment(p, inner, true, FFLAG_NO_EXPAND); @@ -828,7 +916,7 @@ parse_expand(apfl_parser_ptr p, struct fragment *fragment, struct apfl_position fragment->type = FRAG_EXPAND; fragment->expand = inner; fragment->position = position; - return PF_OK; + return true; } free(inner); @@ -838,32 +926,47 @@ parse_expand(apfl_parser_ptr p, struct fragment *fragment, struct apfl_position assert(false); // Already handled above break; case PF_CANT_HANDLE: - return unexpected_cant_handle(p); + p->error = ERR_UNEXPECTED_TOKEN(p->token); + return false; case PF_EOF: p->error = err_unexpected_eof_after(APFL_TOK_EXPAND, position); - return PF_ERROR; + return false; case PF_ERROR: - return PF_ERROR; + return false; } + + assert(false); } -static enum parse_fragment_result -parse_stringify(apfl_parser_ptr p, struct fragment *fragment, struct apfl_position position) +static bool +must_read_token_after(apfl_parser_ptr p, enum apfl_token_type want_type) { + enum apfl_token_type cur_type = p->token.type; + struct apfl_position cur_pos = p->token.position; + switch (read_token(p, true)) { case APFL_PARSE_OK: break; case APFL_PARSE_EOF: - p->error = err_unexpected_eof_after(APFL_TOK_STRINGIFY, position); - return PF_ERROR; - + p->error = err_unexpected_eof_after(cur_type, cur_pos); + return false; case APFL_PARSE_ERROR: - return PF_ERROR; + return false; } - if (p->token.type != APFL_TOK_NAME) { + if (p->token.type != want_type) { p->error = ERR_UNEXPECTED_TOKEN(p->token); - return PF_ERROR; + return false; + } + + return true; +} + +static bool +parse_stringify(apfl_parser_ptr p, struct fragment *fragment, struct apfl_position position) +{ + if (!must_read_token_after(p, APFL_TOK_NAME)) { + return false; } fragment->type = FRAG_CONSTANT; @@ -872,12 +975,12 @@ parse_stringify(apfl_parser_ptr p, struct fragment *fragment, struct apfl_positi .string = apfl_string_move(&p->token.text), }; fragment->position = position; - return PF_OK; + return true; } static bool fragment_to_param_recursive(apfl_parser_ptr, struct fragment *, struct apfl_expr_param *); -static bool fragments_to_params(apfl_parser_ptr, struct fragment_list, struct apfl_expr_params *); +static bool fragments_to_params(apfl_parser_ptr, struct fragment_list *, struct apfl_expr_params *); static bool predicate_fragment_to_param( @@ -945,8 +1048,10 @@ fragment_to_param_recursive( return false; case FRAG_LIST: out->type = APFL_EXPR_PARAM_LIST; - return fragments_to_params(p, fragment_list_move(&fragment->list), &out->list); + return fragments_to_params(p, &fragment->list, &out->list); } + + assert(false); } static bool @@ -974,22 +1079,28 @@ fragment_to_param( static bool fragments_to_params( apfl_parser_ptr p, - struct fragment_list fragments, + struct fragment_list *fragments, struct apfl_expr_params *out ) { bool result = true; - out->params = malloc(sizeof(struct apfl_expr_param) * fragments.len); + if (fragments->len == 0) { + out->len = 0; + out->params = NULL; + goto ok; + } + + out->params = ALLOC_LIST(struct apfl_expr_param, fragments->len); out->len = 0; if (out->params == NULL) { goto error; } bool seen_expand = false; - for (size_t i = 0; i < fragments.len; i++) { + for (size_t i = 0; i < fragments->len; i++) { if (!fragment_to_param( p, - &fragments.children[i], + &fragments->children[i], &out->params[i], &seen_expand )) { @@ -1005,7 +1116,7 @@ error: result = false; apfl_expr_params_deinit(out); ok: - fragment_list_deinit(&fragments); + fragment_list_deinit(fragments); return result; } @@ -1245,11 +1356,19 @@ fragments_to_call( out->call.arguments.len++; } + return true; + error: apfl_expr_deinit(out); 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, @@ -1304,7 +1423,9 @@ parse_body_or_toplevel_finalize( } } - return true; + fragment_list_deinit(fragments); + + return BODY_FINALIZE_OK; error: apfl_expr_deinit(out); @@ -1316,14 +1437,22 @@ parse_body_or_toplevel( apfl_parser_ptr p, bool handle_eof, struct fragment_list *fragments, - struct apfl_expr *out + 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; + bool first; + for (;;) { + first = true; for (;;) { - switch (parse_fragment_into_list(p, fragments, true, 0)) { + switch (parse_fragment_into_list(p, fragments, need || !first, 0)) { case PF_OK: break; case PF_CANT_HANDLE: @@ -1350,11 +1479,15 @@ parse_body_or_toplevel( case PF_ERROR: goto error; } + + first = false; } break_inner: read_token_after_cant_handle(p); + bool is_rbrace = false; + switch (p->token.type) { case APFL_TOK_ASSIGN: case APFL_TOK_LOCAL_ASSIGN: @@ -1377,6 +1510,18 @@ 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) { p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); @@ -1408,6 +1553,10 @@ break_inner: } break; + case APFL_TOK_RBRACE: + is_rbrace = true; + unread_token(p); + // fallthrough case APFL_TOK_LINEBREAK: case APFL_TOK_SEMICOLON: switch (parse_body_or_toplevel_finalize( @@ -1422,12 +1571,18 @@ break_inner: case BODY_FINALIZE_ERROR: goto error; case BODY_FINALIZE_EMPTY: + if (is_rbrace) { + return PF_CANT_HANDLE; + } + // If there was nothing to finalize, we have an empty expression // that doesn't need to end up in the AST. So let's just // continue with the outermost loop and try again. break; + default: + assert(false); } - + break; default: if (leftmost_assignment_expr != NULL) { p->error = ERR_UNEXPECTED_TOKEN(p->token); @@ -1441,6 +1596,7 @@ break_inner: error: // \mystuff\TODO:also on other non ok results??? DESTROY(leftmost_assignment_expr, apfl_expr_deinit); + return PF_ERROR; } static enum parse_fragment_result @@ -1449,18 +1605,12 @@ parse_braces( struct fragment *out, struct apfl_position start ) { - enum { - FUNTYPE_UNDECIDED, - FUNTYPE_SIMPLE, - FUNTYPE_COMPLEX, - } type = FUNTYPE_UNDECIDED; - struct apfl_expr_subfunc *subfuncs = NULL; size_t subfuncs_len = 0; size_t subfuncs_cap = 0; bool has_params = false; - struct apfl_expr_params params = {}; + struct apfl_expr_params params = { .params = NULL, .len = 0 }; struct fragment_list fragments; apfl_resizable_init(APFL_RESIZABLE_ARGS(fragments, children)); @@ -1478,7 +1628,8 @@ parse_braces( p, false, &fragments, - &expr + &expr, + true )) { case PF_OK: if (!apfl_resizable_append( @@ -1504,7 +1655,51 @@ parse_braces( switch (p->token.type) { case APFL_TOK_RBRACE: - // \mystuff\TODO: + // TODO: Rather fulgly duplication + if (has_params) { + // Finalize previous subfunc and append + if (!apfl_resizable_append( + sizeof(struct apfl_expr_subfunc), + (void **)&subfuncs, + &subfuncs_len, + &subfuncs_cap, + &(struct apfl_expr_subfunc) { + .params = params, + .body = body, + }, + 1 + )) { + p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); + goto error; + } + + params = (struct apfl_expr_params) { .params = NULL, .len = 0 }; + body = (struct apfl_expr_body) { .items = NULL, .len = 0 }; + body_cap = 0; + } + + out->type = FRAG_EXPR; + if (has_params) { + out->expr = (struct apfl_expr) { + .type = APFL_EXPR_COMPLEX_FUNC, + .complex_func.subfuncs = subfuncs, + .complex_func.len = subfuncs_len, + .position = start, + }; + subfuncs = NULL; + subfuncs_len = 0; + subfuncs_cap = 0; + } else { + out->expr = (struct apfl_expr) { + .type = APFL_EXPR_SIMPLE_FUNC, + .simple_func = apfl_expr_body_move(&body), + .position = start, + }; + body_cap = 0; + } + + return PF_OK; + break; case APFL_TOK_MAPSTO: if (body.len > 0 && !has_params) { @@ -1532,14 +1727,12 @@ parse_braces( goto error; } - params = (struct apfl_expr_params) {}; - body = (struct apfl_expr_body) {}; + params = (struct apfl_expr_params) { .params = NULL, .len = 0 }; + body = (struct apfl_expr_body) { .items = NULL, .len = 0 }; body_cap = 0; } - type = FUNTYPE_COMPLEX; - - if (!fragments_to_params(p, fragments, ¶ms)) { + if (!fragments_to_params(p, &fragments, ¶ms)) { goto error; } has_params = true; @@ -1562,6 +1755,9 @@ error: static enum parse_fragment_result parse_fragment(apfl_parser_ptr p, struct fragment *fragment, bool need, enum parse_fragment_flags flags) { + struct fragment *lhs = NULL; + struct fragment *rhs = NULL; + switch (read_token(p, need)) { case APFL_PARSE_OK: break; @@ -1571,7 +1767,7 @@ parse_fragment(apfl_parser_ptr p, struct fragment *fragment, bool need, enum par return PF_ERROR; } - enum parse_fragment_result result; + enum parse_fragment_result result = PF_OK; // \mystuff\TODO:i think we can get rid of this var? switch (p->token.type) { case APFL_TOK_LPAREN: @@ -1589,10 +1785,14 @@ parse_fragment(apfl_parser_ptr p, struct fragment *fragment, bool need, enum par return PF_CANT_HANDLE; } - result = parse_expand(p, fragment, p->token.position); + if (!parse_expand(p, fragment, p->token.position)) { + goto error; + } break; case APFL_TOK_STRINGIFY: - result = parse_stringify(p, fragment, p->token.position); + if (!parse_stringify(p, fragment, p->token.position)) { + goto error; + } break; case APFL_TOK_NUMBER: fragment->type = FRAG_CONSTANT; @@ -1642,39 +1842,128 @@ parse_fragment(apfl_parser_ptr p, struct fragment *fragment, bool need, enum par return PF_CANT_HANDLE; } - if (result == PF_OK) { + if (result != PF_OK) { + return result; + } + + for (; !(flags & FFLAG_NO_POSTFIXS); ) { switch (read_token(p, need)) { case APFL_PARSE_OK: break; case APFL_PARSE_EOF: return PF_OK; case APFL_PARSE_ERROR: - return PF_ERROR; // \mystuff\TODO:destroy fragment in case of errors + fragment_deinit(fragment); + return PF_ERROR; } + enum apfl_token_type token_type = p->token.type; + struct apfl_position token_pos = p->token.position; + switch (p->token.type) { case APFL_TOK_DOT: - result = parse_dot(p, fragment, p->token.position); + if (!must_read_token_after(p, APFL_TOK_NAME)) { + return PF_ERROR; + } + + if ((lhs = ALLOC(struct fragment)) == NULL) { + p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); + return PF_ERROR; + } + *lhs = *fragment; + fragment->type = FRAG_DOT; + fragment->position = token_pos; + MOVEPTR(fragment->dot.lhs, lhs); + fragment->dot.rhs = apfl_string_move(&p->token.text); + break; case APFL_TOK_AT: - result = parse_at(p, fragment, p->token.position); - break; case APFL_TOK_QUESTION_MARK: - result = parse_predicate(p, fragment, p->token.position); + if ( + ((lhs = ALLOC(struct fragment)) == NULL) + || ((rhs = ALLOC(struct fragment)) == NULL) + ) { + p->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); + return PF_ERROR; + } + + switch (parse_fragment(p, rhs, true, FFLAG_NO_POSTFIXS | FFLAG_NO_EXPAND)) { + case PF_OK: + break; + case PF_ERROR: + goto error; + case PF_EOF: + p->error = err_unexpected_eof_after(token_type, token_pos); + goto error; + case PF_CANT_HANDLE: + read_token_after_cant_handle(p); + p->error = ERR_UNEXPECTED_TOKEN(p->token); + goto error; + } + + + *lhs = *fragment; + if (token_type == APFL_TOK_AT) { + fragment->type = FRAG_AT; + fragment->position = token_pos; + fragment->at.lhs = lhs; + fragment->at.rhs = rhs; + } else { + assert(token_type == APFL_TOK_QUESTION_MARK); + + fragment->type = FRAG_PREDICATE; + fragment->position = token_pos; + fragment->at.lhs = lhs; + fragment->at.rhs = rhs; + } + break; default: unread_token(p); - return result; + return PF_OK; } } - return result; + return PF_OK; + +error: + DESTROY(lhs, fragment_deinit); + DESTROY(rhs, fragment_deinit); + fragment_deinit(fragment); + return PF_ERROR; } enum apfl_parse_result apfl_parser_next(apfl_parser_ptr p) { - // \mystuff\TODO: + if (p->has_expr) { + apfl_expr_deinit(&p->expr); + } + + struct fragment_list fragments; // TODO: Clean me up! + apfl_resizable_init(APFL_RESIZABLE_ARGS(fragments, children)); + + switch (parse_body_or_toplevel( + p, + true, + &fragments, + &p->expr, + false + )) { + case PF_OK: + p->has_expr = true; + return APFL_PARSE_OK; + case PF_ERROR: + return APFL_PARSE_ERROR; + case PF_EOF: + return APFL_PARSE_EOF; + case PF_CANT_HANDLE: + read_token_after_cant_handle(p); + p->error = ERR_UNEXPECTED_TOKEN(p->token); + return APFL_PARSE_ERROR; + } + + assert(false); } struct apfl_error @@ -1682,3 +1971,21 @@ apfl_parser_get_error(apfl_parser_ptr p) { return p->error; } + +struct apfl_expr +apfl_parser_get_expr(apfl_parser_ptr p) +{ + p->has_expr = false; + return p->expr; +} + +void +apfl_parser_destroy(apfl_parser_ptr p) +{ + if (p->has_expr) { + apfl_expr_deinit(&p->expr); + } + if (p->has_token) { + apfl_token_deinit(&p->token); + } +} diff --git a/src/tokenizer.c b/src/tokenizer.c index 99b36f8..707fd1d 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -907,3 +907,33 @@ number( return APFL_PARSE_OK; } } + +static enum apfl_parse_result +token_source_wrap_next(void *opaque, bool need) +{ + return apfl_tokenizer_next(opaque, need); +} + +static struct apfl_token +token_source_wrap_get_token(void *opaque) +{ + return apfl_tokenizer_get_token(opaque); +} + +static struct apfl_error +token_source_wrap_get_error(void *opaque) +{ + return apfl_tokenizer_get_error(opaque); +} + + +struct apfl_parser_token_source +apfl_tokenizer_as_token_source(apfl_tokenizer_ptr p) +{ + return (struct apfl_parser_token_source) { + .next = token_source_wrap_next, + .get_token = token_source_wrap_get_token, + .get_error = token_source_wrap_get_error, + .opaque = p, + }; +}