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.
This commit is contained in:
Laria 2021-12-15 21:28:44 +01:00
parent af33887131
commit c288c333ca
5 changed files with 449 additions and 96 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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, &params)) {
if (!fragments_to_params(p, &fragments, &params)) {
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);
}
}

View file

@ -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,
};
}