diff --git a/lang/ast/block.c b/lang/ast/block.c index 35e9097..58c45a7 100644 --- a/lang/ast/block.c +++ b/lang/ast/block.c @@ -8,6 +8,34 @@ #include #include +void block_add_terminator(struct block_parser_state *state, unsigned short tok) +{ + if (state->s_nr_terminators < BLOCK_TERMINATOR_MAX) { + state->s_terminators[state->s_nr_terminators++] = tok; + } +} + +void block_copy_terminators( + const struct block_parser_state *src, struct block_parser_state *dest) +{ + dest->s_nr_terminators = src->s_nr_terminators; + + for (unsigned int i = 0; i < src->s_nr_terminators; i++) { + dest->s_terminators[i] = src->s_terminators[i]; + } +} + +bool block_terminates_at_token(struct block_parser_state *state, unsigned short tok) +{ + for (unsigned int i = 0; i < BLOCK_TERMINATOR_MAX; i++) { + if (state->s_terminators[i] == tok) { + return true; + } + } + + return false; +} + static struct token_parse_result parse_end( struct ivy_parser *ctx, struct ivy_token *tok) { @@ -18,7 +46,7 @@ static struct token_parse_result parse_end( = (struct ivy_ast_block_node *)(state->s_base.s_node); int flags = 0; - if (state->s_terminator == IVY_KW_END) { + if (block_terminates_at_token(state, IVY_KW_END)) { flags = PARSE_REPEAT_TOKEN; } @@ -39,6 +67,23 @@ static struct token_parse_result parse_else( return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } +static struct token_parse_result parse_keyword( + struct ivy_parser *ctx, struct ivy_token *tok) +{ + struct block_parser_state *state + = parser_get_state(ctx, struct block_parser_state); + + struct ivy_ast_block_node *node + = (struct ivy_ast_block_node *)(state->s_base.s_node); + + if (block_terminates_at_token(state, tok->t_keyword)) { + parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); + return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); + } + + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); +} + static struct token_parse_result parse_symbol( struct ivy_parser *ctx, struct ivy_token *tok) { @@ -48,7 +93,7 @@ static struct token_parse_result parse_symbol( struct ivy_ast_block_node *node = (struct ivy_ast_block_node *)(state->s_base.s_node); - if (state->s_terminator == tok->t_symbol) { + if (block_terminates_at_token(state, tok->t_symbol)) { parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } @@ -69,6 +114,10 @@ static struct token_parse_result parse_expr_begin( = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR, 0); + memcpy(expr->s_terminators, state->s_terminators, + sizeof expr->s_terminators); + expr->s_nr_terminators = state->s_nr_terminators; + return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } @@ -103,6 +152,7 @@ struct ast_node_type block_node_ops = { .n_keyword_parsers = { KW_PARSER(END, parse_end), KW_PARSER(ELSE, parse_else), + KW_PARSER_FALLBACK(parse_keyword), }, .n_symbol_parsers = { SYM_PARSER_FALLBACK(parse_symbol), diff --git a/lang/ast/block.h b/lang/ast/block.h index 5952e25..cf1bbe0 100644 --- a/lang/ast/block.h +++ b/lang/ast/block.h @@ -3,10 +3,24 @@ #include "ctx.h" +#define BLOCK_TERMINATOR_MAX 8 + struct block_parser_state { struct parser_state s_base; bool s_single_expr; - unsigned int s_terminator; + + /* the block will be terminated when any token in this list + * is encountered. the token that terminated the block will + * not be consumed. */ + unsigned short s_terminators[BLOCK_TERMINATOR_MAX]; + unsigned short s_nr_terminators; }; -#endif \ No newline at end of file +extern void block_add_terminator( + struct block_parser_state *state, unsigned short tok); +extern void block_copy_terminators( + const struct block_parser_state *src, struct block_parser_state *dest); +extern bool block_terminates_at_token( + struct block_parser_state *state, unsigned short tok); + +#endif diff --git a/lang/ast/cond.c b/lang/ast/cond.c index f83c3c1..7b70e16 100644 --- a/lang/ast/cond.c +++ b/lang/ast/cond.c @@ -1,6 +1,6 @@ #include "block.h" -#include "iterate.h" #include "expr/expr.h" +#include "iterate.h" struct cond_group_parser_state { struct parser_state s_base; @@ -20,9 +20,7 @@ static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_ state->s_prev_node = (struct ivy_ast_node *)arg; } -struct token_parse_result parse_if( - struct ivy_parser* ctx, - struct ivy_token* tok) +struct token_parse_result parse_if(struct ivy_parser *ctx, struct ivy_token *tok) { struct cond_group_parser_state *state = parser_get_state(ctx, struct cond_group_parser_state); @@ -31,7 +29,8 @@ struct token_parse_result parse_if( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - state->s_cur_branch = (struct ivy_ast_cond_node *)ast_node_create(IVY_AST_COND); + state->s_cur_branch + = (struct ivy_ast_cond_node *)ast_node_create(IVY_AST_COND); if (!state->s_cur_branch) { return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); } @@ -60,12 +59,12 @@ static enum ivy_status flush_current_branch(struct cond_group_parser_state *stat if (!state->s_cur_branch) { return IVY_ERR_INTERNAL_FAILURE; } - + b_queue_push_back(&state->s_branches, &state->s_cur_branch->n_base.n_entry); - + state->s_cur_branch = (struct ivy_ast_cond_node *)ast_node_create(IVY_AST_COND); - + if (!state->s_cur_branch) { return IVY_ERR_NO_MEMORY; } @@ -73,7 +72,8 @@ static enum ivy_status flush_current_branch(struct cond_group_parser_state *stat return IVY_OK; } -static struct token_parse_result parse_then(struct ivy_parser *ctx, struct ivy_token *tok) +static struct token_parse_result parse_then( + struct ivy_parser *ctx, struct ivy_token *tok) { struct cond_group_parser_state *state = parser_get_state(ctx, struct cond_group_parser_state); @@ -103,13 +103,14 @@ static struct token_parse_result parse_then(struct ivy_parser *ctx, struct ivy_t = (struct block_parser_state *)parser_push_state( ctx, IVY_AST_BLOCK, 0); /* set the sub-expression depth to be non-zero so the expression parser doesn't consume the expression separator. */ - block->s_terminator = IVY_KW_END; + block_add_terminator(block, IVY_KW_END); state->s_prev_token = IVY_KW_THEN; return PARSE_RESULT(IVY_OK, 0); } -static struct token_parse_result parse_else(struct ivy_parser *ctx, struct ivy_token *tok) +static struct token_parse_result parse_else( + struct ivy_parser *ctx, struct ivy_token *tok) { enum ivy_status status; struct cond_group_parser_state *state @@ -155,7 +156,7 @@ static struct token_parse_result parse_else(struct ivy_parser *ctx, struct ivy_t if (status != IVY_OK) { return PARSE_RESULT(status, 0); } - + /* next component will be an expression. */ struct expr_parser_state *expr = (struct expr_parser_state *)parser_push_state( @@ -168,22 +169,26 @@ static struct token_parse_result parse_else(struct ivy_parser *ctx, struct ivy_t return PARSE_RESULT(IVY_OK, 0); } -static struct token_parse_result parse_expr_begin(struct ivy_parser* ctx, struct ivy_token* tok) +static struct token_parse_result parse_expr_begin( + struct ivy_parser *ctx, struct ivy_token *tok) { struct cond_group_parser_state *state = parser_get_state(ctx, struct cond_group_parser_state); - if (state->s_prev_token != IVY_KW_ELSE && state->s_prev_token != IVY_KW_THEN) { + if (state->s_prev_token != IVY_KW_ELSE + && state->s_prev_token != IVY_KW_THEN) { /* expression can only follow else and then keywords. */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - struct block_parser_state *block = (struct block_parser_state *)parser_push_state(ctx, IVY_AST_BLOCK, 0); - block->s_terminator = IVY_KW_END; + struct block_parser_state *block + = (struct block_parser_state *)parser_push_state( + ctx, IVY_AST_BLOCK, 0); + block_add_terminator(block, IVY_KW_END); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } -static enum ivy_status finalise_cond_group(struct cond_group_parser_state* state) +static enum ivy_status finalise_cond_group(struct cond_group_parser_state *state) { struct ivy_ast_cond_group_node *group = (struct ivy_ast_cond_group_node *)state->s_base.s_node; @@ -205,7 +210,7 @@ static enum ivy_status finalise_cond_group(struct cond_group_parser_state* state state->s_cur_branch->n_body = state->s_prev_node; } else if (state->s_prev_token == IVY_KW_IF) { /* this is the if expression, s_prev_node is the if condition. */ - state->s_cur_branch->n_cond = state->s_prev_node; + state->s_cur_branch->n_cond = state->s_prev_node; } state->s_prev_node = NULL; @@ -256,7 +261,8 @@ static struct token_parse_result parse_punct_terminator( return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } -static struct token_parse_result parse_end(struct ivy_parser *ctx, struct ivy_token *tok) +static struct token_parse_result parse_end( + struct ivy_parser *ctx, struct ivy_token *tok) { struct cond_group_parser_state *state = parser_get_state(ctx, struct cond_group_parser_state); @@ -284,7 +290,7 @@ static enum ivy_status add_child( if (state->s_prev_node) { return IVY_ERR_BAD_SYNTAX; } - + state->s_prev_node = child; return IVY_OK; } @@ -297,7 +303,8 @@ static void cond_group_collect_children( b_queue_iterator it = {0}; b_queue_foreach (&it, &group->n_branches) { - struct ivy_ast_node *branch = b_unbox(struct ivy_ast_node, it.entry, n_entry); + struct ivy_ast_node *branch + = b_unbox(struct ivy_ast_node, it.entry, n_entry); ast_node_iterator_enqueue_node(iterator, node, branch); } } diff --git a/lang/ast/for.c b/lang/ast/for.c index f13fe76..d1b4cd9 100644 --- a/lang/ast/for.c +++ b/lang/ast/for.c @@ -101,7 +101,7 @@ static struct token_parse_result parse_do( = (struct block_parser_state *)parser_push_state( ctx, IVY_AST_BLOCK, 0); - block->s_terminator = IVY_KW_END; + block_add_terminator(block, IVY_KW_END); state->s_prev_token = IVY_KW_DO; return PARSE_RESULT(IVY_OK, 0); } @@ -120,7 +120,7 @@ static struct token_parse_result parse_expr_begin( struct block_parser_state *block = (struct block_parser_state *)parser_push_state( ctx, IVY_AST_BLOCK, 0); - block->s_terminator = IVY_KW_END; + block_add_terminator(block, IVY_KW_END); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } diff --git a/lang/ast/lambda.c b/lang/ast/lambda.c index 1361820..979974e 100644 --- a/lang/ast/lambda.c +++ b/lang/ast/lambda.c @@ -29,7 +29,7 @@ static struct token_parse_result parse_expr_begin( struct block_parser_state *block = (struct block_parser_state *)parser_push_state( ctx, IVY_AST_BLOCK, 0); - block->s_terminator = IVY_SYM_RIGHT_BRACKET; + block_add_terminator(block, IVY_SYM_RIGHT_BRACKET); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } diff --git a/lang/ast/msgh.c b/lang/ast/msgh.c index 822b506..380c5e2 100644 --- a/lang/ast/msgh.c +++ b/lang/ast/msgh.c @@ -40,7 +40,7 @@ static struct token_parse_result parse_linefeed( struct block_parser_state *block_state = (struct block_parser_state *)parser_push_state( ctx, IVY_AST_BLOCK, 0); - block_state->s_terminator = IVY_SYM_BANG; + block_add_terminator(block_state, IVY_SYM_BANG); return PARSE_RESULT(IVY_OK, 0); } diff --git a/lang/ast/while.c b/lang/ast/while.c index 490b3d1..686353e 100644 --- a/lang/ast/while.c +++ b/lang/ast/while.c @@ -70,7 +70,7 @@ static struct token_parse_result parse_do( = (struct block_parser_state *)parser_push_state( ctx, IVY_AST_BLOCK, 0); /* set the sub-expression depth to be non-zero so the expression parser doesn't consume the expression separator. */ - block->s_terminator = IVY_KW_END; + block_add_terminator(block, IVY_KW_END); state->s_prev_token = IVY_KW_DO; return PARSE_RESULT(IVY_OK, 0); @@ -90,7 +90,7 @@ static struct token_parse_result parse_expr_begin( struct block_parser_state *block = (struct block_parser_state *)parser_push_state( ctx, IVY_AST_BLOCK, 0); - block->s_terminator = IVY_KW_END; + block_add_terminator(block, IVY_KW_END); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); }