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:
parent
af33887131
commit
c288c333ca
5 changed files with 449 additions and 96 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
22
src/main.c
22
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;
|
||||
}
|
||||
|
|
|
|||
483
src/parser.c
483
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue