diff --git a/lang/ast/atom.c b/lang/ast/atom.c index f558c1c..dd9b944 100644 --- a/lang/ast/atom.c +++ b/lang/ast/atom.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "node.h" #include @@ -14,6 +13,5 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) struct ast_node_type atom_node_ops = { .n_to_string = to_string, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_atom_node), }; diff --git a/lang/ast/block.c b/lang/ast/block.c index 5c0d935..65355bb 100644 --- a/lang/ast/block.c +++ b/lang/ast/block.c @@ -1,149 +1,24 @@ #include "block.h" -#include "ctx.h" -#include "expr/expr.h" #include "iterate.h" #include "node.h" #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) -{ - 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); - - int flags = 0; - if (block_terminates_at_token(state, IVY_KW_END)) { - flags = PARSE_REPEAT_TOKEN; - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, flags); -} - -static struct token_parse_result parse_else( - 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); - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - 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) -{ - 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_symbol)) { - 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_global( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - parser_push_state(ctx, IVY_AST_GLOBAL, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_expr_begin( - 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); - - struct expr_parser_state *expr - = (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); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct ivy_ast_block_node *block - = (struct ivy_ast_block_node *)parent->s_node; - - fx_queue_push_back(&block->n_expr, &child->n_entry); - - return IVY_OK; -} - static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { struct ivy_ast_block_node *block = (struct ivy_ast_block_node *)node; - fx_queue_entry *entry = fx_queue_first(&block->n_expr); + fx_queue_entry *entry = fx_queue_first(&block->n_arg); + while (entry) { + struct ivy_ast_node *expr + = fx_unbox(struct ivy_ast_node, entry, n_entry); + ast_node_iterator_enqueue_node(iterator, node, expr); + entry = fx_queue_next(entry); + } + + entry = fx_queue_first(&block->n_expr); while (entry) { struct ivy_ast_node *expr = fx_unbox(struct ivy_ast_node, entry, n_entry); @@ -153,21 +28,6 @@ static void collect_children( } struct ast_node_type block_node_ops = { - .n_add_child = add_child, .n_collect_children = collect_children, - .n_state_size = sizeof(struct block_parser_state), .n_node_size = sizeof(struct ivy_ast_block_node), - .n_keyword_parsers = { - KW_PARSER(GLOBAL, parse_global), - KW_PARSER(END, parse_end), - KW_PARSER(ELSE, parse_else), - KW_PARSER(ELIF, parse_else), /* same behaviour as ELSE */ - KW_PARSER_FALLBACK(parse_keyword), - }, - .n_symbol_parsers = { - SYM_PARSER_FALLBACK(parse_symbol), - }, - .n_expr_parser = { - .expr_begin = parse_expr_begin, - }, }; diff --git a/lang/ast/block.h b/lang/ast/block.h index cf1bbe0..9d4a7b7 100644 --- a/lang/ast/block.h +++ b/lang/ast/block.h @@ -1,26 +1,4 @@ #ifndef _AST_BLOCK_H_ #define _AST_BLOCK_H_ -#include "ctx.h" - -#define BLOCK_TERMINATOR_MAX 8 - -struct block_parser_state { - struct parser_state s_base; - bool s_single_expr; - - /* 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; -}; - -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/cascade.c b/lang/ast/cascade.c index 4bfd963..220ddc9 100644 --- a/lang/ast/cascade.c +++ b/lang/ast/cascade.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "iterate.h" #include "node.h" @@ -22,6 +21,5 @@ static void collect_children( struct ast_node_type cascade_node_ops = { .n_collect_children = collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_cascade_node), }; diff --git a/lang/ast/class.c b/lang/ast/class.c index 9de9cc8..eca61d9 100644 --- a/lang/ast/class.c +++ b/lang/ast/class.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "iterate.h" #include "node.h" @@ -6,142 +5,6 @@ #include #include -struct class_parser_state { - struct parser_state s_base; - enum { - AREA_IDENT, - AREA_BODY, - } s_current_area; - int s_prev_token; -}; - -static struct token_parse_result parse_hyphen_right_angle( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct class_parser_state *state - = parser_get_state(ctx, struct class_parser_state); - - if (state->s_current_area != AREA_BODY) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_push_state(ctx, IVY_AST_PROPERTY, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_plus( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct class_parser_state *state - = parser_get_state(ctx, struct class_parser_state); - - if (state->s_current_area != AREA_BODY) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_push_state(ctx, IVY_AST_MSGH, 0); - struct parser_state *msgh_state = parser_get_state_generic(ctx); - struct ivy_ast_msgh_node *msgh - = (struct ivy_ast_msgh_node *)msgh_state->s_node; - - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static struct token_parse_result parse_hyphen( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct class_parser_state *state - = parser_get_state(ctx, struct class_parser_state); - - if (state->s_current_area != AREA_BODY) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_push_state(ctx, IVY_AST_MSGH, 0); - struct parser_state *msgh_state = parser_get_state_generic(ctx); - struct ivy_ast_msgh_node *msgh - = (struct ivy_ast_msgh_node *)msgh_state->s_node; - - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static struct token_parse_result parse_ident( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct class_parser_state *state - = parser_get_state(ctx, struct class_parser_state); - - struct ivy_ast_class_node *node - = (struct ivy_ast_class_node *)(state->s_base.s_node); - - if (state->s_current_area != AREA_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token == IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - node->n_ident = tok; - state->s_prev_token = IVY_TOK_IDENT; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_end( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct class_parser_state *state - = parser_get_state(ctx, struct class_parser_state); - - struct ivy_ast_class_node *node - = (struct ivy_ast_class_node *)(state->s_base.s_node); - - if (state->s_current_area == AREA_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_linefeed( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct class_parser_state *state - = parser_get_state(ctx, struct class_parser_state); - - if (state->s_current_area != AREA_IDENT) { - return PARSE_RESULT(IVY_OK, 0); - } - - if (state->s_prev_token != IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev_token = IVY_TOK_LINEFEED; - state->s_current_area = AREA_BODY; - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *state, struct ivy_ast_node *child) -{ - struct ivy_ast_class_node *c = (struct ivy_ast_class_node *)state->s_node; - - switch (child->n_type) { - case IVY_AST_MSGH: - fx_queue_push_back(&c->n_msg_handlers, &child->n_entry); - break; - case IVY_AST_PROPERTY: - fx_queue_push_back(&c->n_properties, &child->n_entry); - break; - default: - return IVY_ERR_NOT_SUPPORTED; - } - - return IVY_OK; -} - static void to_string(struct ivy_ast_node *node, fx_string *str) { struct ivy_ast_class_node *c = (struct ivy_ast_class_node *)node; @@ -151,13 +14,6 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) c->n_ident->t_str); } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct class_parser_state *state = (struct class_parser_state *)sp; - state->s_prev_token = IVY_KW_CLASS; - state->s_current_area = AREA_IDENT; -} - static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { @@ -180,22 +36,7 @@ static void collect_children( } struct ast_node_type class_node_ops = { - .n_add_child = add_child, .n_to_string = to_string, - .n_init_state = init_state, .n_collect_children = collect_children, - .n_state_size = sizeof(struct class_parser_state), .n_node_size = sizeof(struct ivy_ast_class_node), - .n_symbol_parsers = { - SYM_PARSER(HYPHEN_RIGHT_ANGLE, parse_hyphen_right_angle), - SYM_PARSER(HYPHEN, parse_hyphen), - SYM_PARSER(PLUS, parse_plus), - }, - .n_token_parsers = { - TOK_PARSER(IDENT, parse_ident), - TOK_PARSER(LINEFEED, parse_linefeed), - }, - .n_keyword_parsers = { - KW_PARSER(END, parse_end), - }, }; diff --git a/lang/ast/cond.c b/lang/ast/cond.c index f500d3a..afe5a1c 100644 --- a/lang/ast/cond.c +++ b/lang/ast/cond.c @@ -1,337 +1,5 @@ -#include "block.h" -#include "expr/expr.h" #include "iterate.h" - -struct cond_group_parser_state { - struct parser_state s_base; - bool s_inline; - unsigned int s_prev_token; - - struct ivy_ast_cond_node *s_cur_branch; - fx_queue s_branches; - - struct ivy_ast_node *s_prev_node; -}; - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct cond_group_parser_state *state - = (struct cond_group_parser_state *)sp; - state->s_prev_node = (struct ivy_ast_node *)arg; -} - -static enum ivy_status flush_current_branch(struct cond_group_parser_state *state) -{ - if (!state->s_cur_branch) { - return IVY_ERR_INTERNAL_FAILURE; - } - - fx_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; - } - - return IVY_OK; -} - -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); - - if (state->s_cur_branch) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - 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); - } - - if (state->s_prev_node) { - /* this is an inline if-else */ - state->s_inline = true; - state->s_cur_branch->n_body = state->s_prev_node; - state->s_prev_node = NULL; - } else { - state->s_inline = false; - } - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - state->s_prev_token = IVY_KW_IF; - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result parse_elif(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_cur_branch) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_inline) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token != IVY_KW_THEN) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cur_branch->n_body = state->s_prev_node; - state->s_prev_node = NULL; - - enum ivy_status status = flush_current_branch(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - state->s_prev_token = IVY_KW_ELIF; - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -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); - - if (!state->s_cur_branch) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_inline) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token != IVY_KW_IF && state->s_prev_token != IVY_KW_ELIF) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - /* previous component was the if-condition. */ - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cur_branch->n_cond = state->s_prev_node; - state->s_prev_node = NULL; - - /* next component will be a block. */ - struct block_parser_state *block - = (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_add_terminator(block, IVY_KW_ELIF); - block_add_terminator(block, IVY_KW_ELSE); - 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) -{ - enum ivy_status status; - struct cond_group_parser_state *state - = parser_get_state(ctx, struct cond_group_parser_state); - - if (!state->s_cur_branch) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_inline) { - /* previous component was either an expression or a block, and is the if branch body. */ - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token != IVY_KW_THEN) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cur_branch->n_body = state->s_prev_node; - state->s_prev_node = NULL; - - status = flush_current_branch(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - /* next component should be a block. */ - } else { - /* previous component was the if-condition. */ - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token != IVY_KW_IF) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cur_branch->n_cond = state->s_prev_node; - state->s_prev_node = NULL; - - status = flush_current_branch(state); - 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( - ctx, IVY_AST_EXPR, 0); - /* set the sub-expression depth to be non-zero so the expression - * parser doesn't consume the expression separator. */ - expr->s_subexpr_depth = 1; - } - - state->s_prev_token = IVY_KW_ELSE; - return PARSE_RESULT(IVY_OK, 0); -} - -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) { - /* 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_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) -{ - struct ivy_ast_cond_group_node *group - = (struct ivy_ast_cond_group_node *)state->s_base.s_node; - - if (state->s_inline) { - /* we have just reached the end of either the 'if' or the 'else' expression. */ - if (!state->s_cur_branch) { - /* not currently parsing a conditional branch. */ - return IVY_ERR_BAD_SYNTAX; - } - - if (!state->s_prev_node) { - /* else expression is empty. */ - return IVY_ERR_BAD_SYNTAX; - } - - if (state->s_prev_token == IVY_KW_ELSE) { - /* this is the else expression, s_prev_node is the else body. */ - 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_prev_node = NULL; - flush_current_branch(state); - - group->n_branches = state->s_branches; - state->s_branches = FX_QUEUE_INIT; - return IVY_OK; - } else { - /* we have just reached the 'end' keyword. */ - if (!state->s_cur_branch) { - /* not currently parsing a conditional branch. */ - return IVY_ERR_BAD_SYNTAX; - } - - if (!state->s_prev_node) { - /* else expression is empty. */ - return IVY_ERR_BAD_SYNTAX; - } - - state->s_cur_branch->n_body = state->s_prev_node; - state->s_prev_node = NULL; - flush_current_branch(state); - - group->n_branches = state->s_branches; - state->s_branches = FX_QUEUE_INIT; - return IVY_OK; - } -} - -static struct token_parse_result parse_punct_terminator( - 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_inline) { - /* only inline conditional can be ended with punctuation. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = finalise_cond_group(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -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); - - enum ivy_status status = finalise_cond_group(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - int flags = 0; - if (state->s_inline) { - flags = PARSE_REPEAT_TOKEN; - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, flags); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct cond_group_parser_state *state - = (struct cond_group_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} +#include "node.h" static void cond_group_collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) @@ -363,31 +31,11 @@ static void cond_collect_children( } struct ast_node_type cond_group_node_ops = { - .n_init_state = init_state, - .n_add_child = add_child, .n_collect_children = cond_group_collect_children, - .n_state_size = sizeof(struct cond_group_parser_state), .n_node_size = sizeof(struct ivy_ast_cond_group_node), - .n_keyword_parsers = { - KW_PARSER(IF, parse_if), - KW_PARSER(THEN, parse_then), - KW_PARSER(ELIF, parse_elif), - KW_PARSER(ELSE, parse_else), - KW_PARSER(END, parse_end), - }, - .n_symbol_parsers = { - SYM_PARSER(DOT, parse_punct_terminator), - SYM_PARSER(COMMA, parse_punct_terminator), - SYM_PARSER(RIGHT_PAREN, parse_punct_terminator), - SYM_PARSER(BANG, parse_punct_terminator), - }, - .n_expr_parser = { - .expr_begin = parse_expr_begin, - }, }; struct ast_node_type cond_node_ops = { .n_collect_children = cond_collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_cond_node), }; diff --git a/lang/ast/const.c b/lang/ast/const.c index 500c8e0..868867a 100644 --- a/lang/ast/const.c +++ b/lang/ast/const.c @@ -1,17 +1,13 @@ -#include "ctx.h" #include "node.h" struct ast_node_type c_true_node_ops = { - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_node), }; struct ast_node_type c_false_node_ops = { - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_node), }; struct ast_node_type c_null_node_ops = { - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_node), }; diff --git a/lang/ast/ctx.c b/lang/ast/ctx.c deleted file mode 100644 index 8df5dd2..0000000 --- a/lang/ast/ctx.c +++ /dev/null @@ -1,356 +0,0 @@ -#include "ctx.h" - -#include "../debug.h" -#include "node.h" - -#include -#include -#include -#include -#include -#include -#include - -#ifdef IVY_LANG_DEBUG -static void print_state_stack(struct ivy_parser *parser) -{ - fx_queue_iterator it = {0}; - fx_queue_foreach (&it, &parser->p_state) { - struct parser_state *state - = fx_unbox(struct parser_state, it.entry, s_entry); - debug_printf( - " %s\n", - ivy_ast_node_type_to_string(state->s_node->n_type)); - } -} -#endif - -enum ivy_status ivy_parser_create(struct ivy_parser **parser) -{ - struct ivy_parser *out = malloc(sizeof *out); - if (!out) { - return IVY_ERR_NO_MEMORY; - } - - memset(out, 0x0, sizeof *out); - - parser_push_state(out, IVY_AST_UNIT, 0); - - *parser = out; - return IVY_OK; -} - -void ivy_parser_destroy(struct ivy_parser *parser, struct ivy_ast_node **result) -{ - struct ivy_ast_node *root = NULL; - - fx_queue_entry *entry = fx_queue_first(&parser->p_state); - ; - while (entry) { - struct parser_state *state - = fx_unbox(struct parser_state, entry, s_entry); - fx_queue_entry *next = fx_queue_next(entry); - fx_queue_delete(&parser->p_state, entry); - - if (root) { - ivy_ast_node_destroy(root); - } - - root = state->s_node; - free(state); - entry = next; - } - - if (result) { - *result = root; - } else if (root) { - ivy_ast_node_destroy(root); - } - - free(parser); -} - -enum ivy_status ivy_parser_set_diag_ctx( - struct ivy_parser *parser, struct ivy_diag_ctx *ctx) -{ - parser->p_diag_ctx = ctx; - return IVY_OK; -} - -enum ivy_status ivy_parser_get_status(struct ivy_parser *parser) -{ - return parser->p_status; -} - -enum ivy_status ivy_parser_push_token( - struct ivy_parser *parser, struct ivy_token *tok) -{ - if (!tok) { - return ivy_parser_push_eof(parser); - } - - while (true) { - struct parser_state *state = parser_get_state_generic(parser); - if (!state) { - parser->p_status = IVY_ERR_INTERNAL_FAILURE; - break; - } - - token_parse_function func = get_token_parser(state->s_node, tok); - if (func) { - struct token_parse_result result = func(parser, tok); - parser->p_status = result.r_status; - -#ifdef IVY_LANG_DEBUG - debug_printf("states (after token)\n"); - print_state_stack(parser); -#endif - if (result.r_flags & PARSE_REPEAT_TOKEN) { - continue; - } - - break; - } - - if (tok->t_type == IVY_TOK_LINEFEED) { - ivy_token_destroy(tok); - parser->p_status = IVY_OK; - break; - } - - parser->p_status = IVY_ERR_BAD_SYNTAX; - break; - } - - return parser->p_status; -} - -enum ivy_status ivy_parser_push_eof(struct ivy_parser *parser) -{ - while (true) { - struct parser_state *state = parser_get_state_generic(parser); - if (!state) { - parser->p_status = IVY_ERR_INTERNAL_FAILURE; - break; - } - - token_parse_function func = NULL; - struct ivy_token tok = {0}; - - switch (state->s_node->n_type) { - case IVY_AST_EXPR: - case IVY_AST_COND_GROUP: - case IVY_AST_FOR_LOOP: - case IVY_AST_WHILE_LOOP: - tok.t_type = IVY_TOK_SYMBOL; - tok.t_symbol = IVY_SYM_DOT; - func = get_token_parser(state->s_node, &tok); - break; - default: - break; - } - - if (!func) { - break; - } - - struct token_parse_result result = func(parser, &tok); - parser->p_status = result.r_status; - - if (result.r_flags & PARSE_REPEAT_TOKEN) { - continue; - } - -#ifdef IVY_LANG_DEBUG - debug_printf("states (after token)\n"); - print_state_stack(parser); -#endif - break; - } - - return parser->p_status; -} - -struct parser_state *parser_get_state_generic(struct ivy_parser *parser) -{ - fx_queue_entry *entry = fx_queue_last(&parser->p_state); - if (!entry) { - return NULL; - } - - struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry); - return state; -} - -struct parser_state *parser_get_parent_state_generic( - struct ivy_parser *parser, enum ivy_ast_node_type type) -{ - fx_queue_entry *entry = fx_queue_last(&parser->p_state); - if (!entry) { - return NULL; - } - - entry = fx_queue_prev(entry); - if (!entry) { - return NULL; - } - - struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry); - - if (state->s_node->n_type != type) { - return NULL; - } - - return state; -} - -struct parser_state *parser_push_state( - struct ivy_parser *parser, enum ivy_ast_node_type type, uintptr_t arg) -{ - const struct ast_node_type *node_type = get_ast_node_type(type); - if (!node_type) { - return NULL; - } - - struct parser_state *state = malloc(node_type->n_state_size); - if (!state) { - return NULL; - } - - memset(state, 0x0, node_type->n_state_size); - - fx_queue_entry *current_state_entry = fx_queue_last(&parser->p_state); - if (current_state_entry) { - struct parser_state *current_state = fx_unbox( - struct parser_state, current_state_entry, s_entry); - state->s_parent = current_state->s_node; - } - - state->s_node = ast_node_create(type); - fx_queue_push_back(&parser->p_state, &state->s_entry); - - if (node_type->n_init_state) { - node_type->n_init_state(parser, state, arg); - } - -#ifdef IVY_LANG_DEBUG - debug_printf("states (after push)\n"); - print_state_stack(parser); -#endif - return state; -} - -void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags) -{ - if (parser->p_state.q_first == parser->p_state.q_last) { - return; - } - - fx_queue_entry *entry = fx_queue_last(&parser->p_state); - struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry); - fx_queue_pop_back(&parser->p_state); - - if (state && state->s_node && (flags & STATE_ADD_NODE_TO_PARENT)) { - parser_add_child(parser, state->s_node); - } - - free(state); - -#ifdef IVY_LANG_DEBUG - debug_printf("states (after pop)\n"); - print_state_stack(parser); -#endif -} - -void parser_replace_current_node( - struct ivy_parser *parser, struct ivy_ast_node *new_node) -{ - struct parser_state *state = parser_get_state_generic(parser); - if (!state) { - return; - } - - ivy_ast_node_destroy(state->s_node); - state->s_node = new_node; -} - -enum ivy_status parser_add_child( - struct ivy_parser *parser, struct ivy_ast_node *new_node) -{ - struct parser_state *state = parser_get_state_generic(parser); - if (!state) { - return IVY_ERR_NOT_SUPPORTED; - } - - const struct ast_node_type *node_type - = get_ast_node_type(state->s_node->n_type); - if (!node_type || !node_type->n_add_child) { - return IVY_ERR_NOT_SUPPORTED; - } - - return node_type->n_add_child(state, new_node); -} - -bool ivy_parser_is_node_complete(struct ivy_parser *parser) -{ - return (parser->p_state.q_first == parser->p_state.q_last); -} - -struct ivy_ast_node *ivy_parser_root_node(struct ivy_parser *parser) -{ - fx_queue_entry *entry = fx_queue_first(&parser->p_state); - struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry); - return state ? state->s_node : NULL; -} - -struct ivy_ast_node *ivy_parser_dequeue_node(struct ivy_parser *parser) -{ - fx_queue_entry *entry = fx_queue_first(&parser->p_state); - struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry); - - if (!state) { - return NULL; - } - - if (state->s_node->n_type != IVY_AST_UNIT) { - return NULL; - } - - struct ivy_ast_unit_node *unit = (struct ivy_ast_unit_node *)state->s_node; - - entry = fx_queue_pop_front(&unit->n_children); - - if (!entry) { - return NULL; - } - - return fx_unbox(struct ivy_ast_node, entry, n_entry); -} - -struct ivy_diag *parser_push_diag( - struct ivy_parser *parser, unsigned long diag_class, unsigned long msg, - struct ivy_token *tok) -{ - struct ivy_diag *diag - = ivy_diag_ctx_create_diag(parser->p_diag_ctx, diag_class); - - if (msg != 0) { - ivy_diag_push_msg(diag, msg); - } - - if (tok) { - ivy_diag_set_location(diag, tok->t_start.c_row, tok->t_start.c_col); - const struct ivy_diag_highlight hl[] = { - IVY_DIAG_HL( - ERROR, tok->t_start.c_row, tok->t_start.c_col, - tok->t_end.c_row, tok->t_end.c_col), - }; - const size_t nr_hl = sizeof hl / sizeof hl[0]; - - ivy_diag_push_snippet( - diag, tok->t_start.c_row, tok->t_end.c_row, NULL, 0, hl, - nr_hl); - }; - - return diag; -} diff --git a/lang/ast/ctx.h b/lang/ast/ctx.h deleted file mode 100644 index f81bf40..0000000 --- a/lang/ast/ctx.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _AST_CTX_H_ -#define _AST_CTX_H_ - -#include -#include -#include -#include -#include - -#define parser_get_state(parser, state_type) \ - ((state_type *)parser_get_state_generic(parser)) - -#define parser_get_parent_state(parser, type_id, state_type) \ - ((state_type *)parser_get_parent_state_generic(parser, type_id)) - -struct parser_state { - fx_queue_entry s_entry; - struct ivy_ast_node *s_parent; - struct ivy_ast_node *s_node; -}; - -struct ivy_parser { - enum ivy_status p_status; - struct ivy_diag_ctx *p_diag_ctx; - fx_queue p_state; - fx_queue p_token_queue; - fx_queue p_node_queue; -}; - -enum pop_state_flags { - STATE_ADD_NODE_TO_PARENT = 0x01u, -}; - -extern struct parser_state *parser_push_state( - struct ivy_parser *parser, enum ivy_ast_node_type node_type, uintptr_t arg); -extern void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags); -extern struct parser_state *parser_get_state_generic(struct ivy_parser *parser); -extern struct parser_state *parser_get_parent_state_generic( - struct ivy_parser *parser, enum ivy_ast_node_type type); - -extern void parser_replace_current_node( - struct ivy_parser *parser, struct ivy_ast_node *new_node); -extern enum ivy_status parser_add_child( - struct ivy_parser *parser, struct ivy_ast_node *new_node); - -extern struct ivy_diag *parser_push_diag( - struct ivy_parser *parser, unsigned long diag_class, unsigned long msg, - struct ivy_token *tok); - -#endif diff --git a/lang/ast/discard.c b/lang/ast/discard.c index 1b954ce..e082ae1 100644 --- a/lang/ast/discard.c +++ b/lang/ast/discard.c @@ -1,9 +1,7 @@ -#include "ctx.h" #include "node.h" #include struct ast_node_type discard_node_ops = { - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_discard_node), }; diff --git a/lang/ast/do.c b/lang/ast/do.c new file mode 100644 index 0000000..a92de3e --- /dev/null +++ b/lang/ast/do.c @@ -0,0 +1,16 @@ +#include "iterate.h" +#include "node.h" + +#include + +static void collect_children( + struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) +{ + struct ivy_ast_do_node *do_node = (struct ivy_ast_do_node *)node; + ast_node_iterator_enqueue_node(iterator, node, do_node->n_block); +} + +struct ast_node_type do_node_ops = { + .n_collect_children = collect_children, + .n_node_size = sizeof(struct ivy_ast_op_node), +}; diff --git a/lang/ast/double.c b/lang/ast/double.c index e663aa9..fb52f4c 100644 --- a/lang/ast/double.c +++ b/lang/ast/double.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "node.h" #include @@ -14,6 +13,5 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) struct ast_node_type double_node_ops = { .n_to_string = to_string, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_double_node), }; diff --git a/lang/ast/expr/arith.c b/lang/ast/expr/arith.c deleted file mode 100644 index fa347ea..0000000 --- a/lang/ast/expr/arith.c +++ /dev/null @@ -1,1557 +0,0 @@ -#include "../block.h" -#include "../debug.h" -#include "../node.h" -#include "expr.h" - -#include -#include -#include -#include -#include - -static void print_operand(struct ivy_ast_node *node) -{ - switch (node->n_type) { - case IVY_AST_IDENT: { - struct ivy_ast_ident_node *ident - = (struct ivy_ast_ident_node *)node; - debug_printf("%s", ident->n_content->t_str); - break; - } - case IVY_AST_INT: { - struct ivy_ast_int_node *v = (struct ivy_ast_int_node *)node; - debug_printf("%llu", v->n_value->t_int); - break; - } - case IVY_AST_DOUBLE: { - struct ivy_ast_double_node *v = (struct ivy_ast_double_node *)node; - debug_printf("%.2lf", v->n_value->t_double); - break; - } - case IVY_AST_OP: { - struct ivy_ast_op_node *v = (struct ivy_ast_op_node *)node; - debug_printf("%s", ivy_operator_id_to_string(v->n_op->op_id)); - break; - } - case IVY_AST_MSG: { - struct ivy_ast_msg_node *v = (struct ivy_ast_msg_node *)node; - if (v->n_sel->n_msg_name) { - debug_printf("%s()", v->n_sel->n_msg_name->t_str); - } else { - debug_printf(""); - } - break; - } - case IVY_AST_STRING: { - struct ivy_ast_string_node *v = (struct ivy_ast_string_node *)node; - debug_printf("\"%s\"", v->n_value->t_str); - break; - } - default: - debug_printf(""); - break; - } -} - -enum ivy_status arith_push_operand( - struct expr_parser_state *state, struct ivy_token *tok) -{ - switch (tok->t_type) { - case IVY_TOK_IDENT: { - struct ivy_ast_ident_node *v - = (struct ivy_ast_ident_node *)ast_node_create( - IVY_AST_IDENT); - v->n_content = tok; - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); - fx_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); - break; - } - case IVY_TOK_INT: { - struct ivy_ast_int_node *v - = (struct ivy_ast_int_node *)ast_node_create(IVY_AST_INT); - v->n_value = tok; - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); - fx_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); - break; - } - case IVY_TOK_DOUBLE: { - struct ivy_ast_double_node *v - = (struct ivy_ast_double_node *)ast_node_create( - IVY_AST_DOUBLE); - v->n_value = tok; - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); - fx_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); - break; - } - case IVY_TOK_ATOM: { - struct ivy_ast_atom_node *v - = (struct ivy_ast_atom_node *)ast_node_create(IVY_AST_ATOM); - v->n_content = tok; - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); - fx_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); - break; - } - case IVY_TOK_STRING: { - struct ivy_ast_string_node *v - = (struct ivy_ast_string_node *)ast_node_create( - IVY_AST_STRING); - v->n_value = tok; - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); - fx_queue_push_back(&state->s_output_queue, &v->n_base.n_entry); - break; - } - case IVY_TOK_SYMBOL: { - if (tok->t_symbol != IVY_SYM_UNDERSCORE) { - return IVY_ERR_BAD_SYNTAX; - } - - struct ivy_ast_node *v = ast_node_create(IVY_AST_DISCARD); - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); - fx_queue_push_back(&state->s_output_queue, &v->n_entry); - break; - } - case IVY_TOK_KEYWORD: { - struct ivy_ast_node *v = NULL; - switch (tok->t_keyword) { - case IVY_KW_BREAK: - v = ast_node_create(IVY_AST_LOOP_BREAK); - break; - case IVY_KW_CONTINUE: - v = ast_node_create(IVY_AST_LOOP_REPEAT); - break; - case IVY_KW_TRUE: - v = ast_node_create(IVY_AST_C_TRUE); - break; - case IVY_KW_FALSE: - v = ast_node_create(IVY_AST_C_FALSE); - break; - case IVY_KW_NULL: - v = ast_node_create(IVY_AST_C_NULL); - break; - default: - return IVY_ERR_BAD_SYNTAX; - } - - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)v, tok); - fx_queue_push_back(&state->s_output_queue, &v->n_entry); - break; - } - default: - return IVY_ERR_BAD_SYNTAX; - } - - return IVY_OK; -} - -static const struct ivy_operator *get_operator_from_token(struct ivy_token *tok) -{ - switch (tok->t_type) { - case IVY_TOK_SYMBOL: - return ivy_operator_get_by_token(tok->t_symbol); - case IVY_TOK_KEYWORD: - return ivy_operator_get_by_token(tok->t_keyword); - default: - return ivy_operator_get_by_token(tok->t_type); - } -} - -static const struct ivy_operator *get_operator_from_node(struct ivy_ast_node *n) -{ - switch (n->n_type) { - case IVY_AST_OP: { - struct ivy_ast_op_node *op = (struct ivy_ast_op_node *)n; - return op->n_op; - } - case IVY_AST_MSG: - return ivy_operator_get_by_id(IVY_OP_MSG); - default: - return NULL; - } -} - -static struct ivy_ast_selector_node *unary_selector_from_token(struct ivy_token *tok) -{ - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)ast_node_create(IVY_AST_SELECTOR); - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)sel, tok); - sel->n_msg_name = tok; - return sel; -} - -static struct ivy_ast_node *create_operator_node_from_token(struct ivy_token *tok) -{ - const struct ivy_operator *op = get_operator_from_token(tok); - if (!op) { - return NULL; - } - - if (op->op_id == IVY_OP_MSG) { - struct ivy_ast_msg_node *new_msg_node - = (struct ivy_ast_msg_node *)ast_node_create(IVY_AST_MSG); - new_msg_node->n_sel = unary_selector_from_token(tok); - ivy_ast_node_set_bounds_from_token( - (struct ivy_ast_node *)new_msg_node, tok); - return (struct ivy_ast_node *)new_msg_node; - } - - struct ivy_ast_op_node *new_op_node - = (struct ivy_ast_op_node *)ast_node_create(IVY_AST_OP); - new_op_node->n_op = op; - ivy_ast_node_set_bounds_from_token((struct ivy_ast_node *)new_op_node, tok); - return (struct ivy_ast_node *)new_op_node; -} - -#ifdef IVY_LANG_DEBUG -static void print_expr_queues(struct expr_parser_state *state) -{ - fx_queue_iterator it = {0}; - - debug_printf("operators:"); - fx_queue_foreach (&it, &state->s_operator_stack) { - struct ivy_ast_node *n - = fx_unbox(struct ivy_ast_node, it.entry, n_entry); - debug_printf(" "); - print_operand(n); - } - - debug_printf("\noperands:"); - fx_queue_foreach (&it, &state->s_output_queue) { - struct ivy_ast_node *n - = fx_unbox(struct ivy_ast_node, it.entry, n_entry); - debug_printf(" "); - print_operand(n); - } - - debug_printf("\n"); -} -#endif - -void arith_push_operator(struct expr_parser_state *state, struct ivy_ast_node *node) -{ - const struct ivy_operator *op = get_operator_from_node(node); - if (!op) { - return; - } - - while (true) { - fx_queue_entry *top = fx_queue_last(&state->s_operator_stack); - if (!top) { - break; - } - - struct ivy_ast_node *top_node - = fx_unbox(struct ivy_ast_node, top, n_entry); - const struct ivy_operator *top_op = NULL; - - switch (top_node->n_type) { - case IVY_AST_OP: { - struct ivy_ast_op_node *op_node - = (struct ivy_ast_op_node *)top_node; - top_op = op_node->n_op; - break; - } - case IVY_AST_MSG: { - struct ivy_ast_msg_node *msg_node - = (struct ivy_ast_msg_node *)top_node; - top_op = ivy_operator_get_by_id(IVY_OP_MSG); - break; - } - default: - return; - } - - if (top_op->op_precedence < op->op_precedence - || (top_op->op_precedence == op->op_precedence - && op->op_associativity != IVY_ASSOCIATIVITY_LEFT)) { - break; - } - - fx_queue_delete(&state->s_operator_stack, top); - fx_queue_push_back(&state->s_output_queue, top); - } - - fx_queue_push_back(&state->s_operator_stack, &node->n_entry); -#ifdef IVY_LANG_DEBUG - print_expr_queues(state); -#endif -} - -static bool op_node_is_complete(struct ivy_ast_op_node *node) -{ - if (!node->n_op) { - return false; - } - - switch (node->n_op->op_arity) { - case IVY_OP_UNARY: - return node->n_right != NULL; - case IVY_OP_BINARY: - return (node->n_left != NULL && node->n_right != NULL); - default: - return false; - } -} - -enum ivy_status expr_finalise_arith( - struct expr_parser_state *state, struct ivy_ast_node **expr_tree, - enum ivy_operator_precedence minimum_precedence) -{ - fx_queue_entry *entry = NULL; - - /* first, take all the operators still left on the operator stack and - * add them to the output queue. - * - * since each set of parentheses has its own expression context, - * we don't have to handle parentheses here */ - while (true) { - entry = fx_queue_pop_back(&state->s_operator_stack); - if (!entry) { - break; - } - - struct ivy_ast_node *node - = fx_unbox(struct ivy_ast_node, entry, n_entry); - if (!node) { - /* this should never happen */ - return IVY_ERR_INTERNAL_FAILURE; - } - - const struct ivy_operator *op = NULL; - - switch (node->n_type) { - case IVY_AST_OP: { - struct ivy_ast_op_node *n = (struct ivy_ast_op_node *)node; - op = n->n_op; - break; - } - case IVY_AST_MSG: - /* all unary message operators have the same pre-defined - * precedence */ - op = ivy_operator_get_by_id(IVY_OP_MSG); - break; - default: - return IVY_ERR_INTERNAL_FAILURE; - } - - /* if we aren't processing operators below a certain precedence - * then leave them on the stack and stop here. */ - if (op->op_precedence < minimum_precedence) { - fx_queue_push_back(&state->s_operator_stack, entry); - break; - } - - fx_queue_push_back(&state->s_output_queue, entry); - } - -#if 0 - debug_printf("** after linearisation:\n"); - print_expr_queues(state); -#endif - - /* next, step through the output queue and build a tree of ast nodes - * representing the expression. the queue is in RPM, where operators - * always follow their operands, so a queue of operands is needed - * for the conversion. */ - - fx_queue q = FX_QUEUE_INIT; - fx_queue_entry *tmp = NULL; - entry = fx_queue_first(&state->s_output_queue); - int i = 0; - - while (entry) { - struct ivy_ast_node *item - = fx_unbox(struct ivy_ast_node, entry, n_entry); - fx_queue_entry *next = fx_queue_next(entry); - fx_queue_delete(&state->s_output_queue, entry); - - /* if the node is an operand, just push it to a temporary queue - * and come back to it later. */ - if (item->n_type != IVY_AST_OP && item->n_type != IVY_AST_MSG) { - /* operand */ - fx_queue_push_back(&q, &item->n_entry); - goto next; - } - - const struct ivy_operator *op = NULL; - - if (item->n_type == IVY_AST_MSG) { - struct ivy_ast_msg_node *msg - = (struct ivy_ast_msg_node *)item; - /* if the message has no recipient, it is a unary message, - * and the recipient is located on the operand stack. - * - * if the message DOES have a recipient, it is a - * self-contained keyword message, and can be pushed to - * the operand queue as-is. */ - if (!msg->n_recipient) { - tmp = fx_queue_pop_back(&q); - msg->n_recipient = fx_unbox( - struct ivy_ast_node, tmp, n_entry); - } - fx_queue_push_back(&q, &msg->n_base.n_entry); - goto next; - } - - struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)item; - /* if an operator node is already complete (i.e. it already has - * all the operands it needs, it can be pushed to the operand - * queue as-is */ - if (op_node_is_complete(op_node)) { - fx_queue_push_back(&q, &item->n_entry); - goto next; - } - - /* otherwise, pop the relevant operands from the operand - * queue... */ - op = op_node->n_op; - tmp = fx_queue_pop_back(&q); - op_node->n_right = fx_unbox(struct ivy_ast_node, tmp, n_entry); - - if (op_node->n_right) { - op_node->n_right->n_parent = (struct ivy_ast_node *)op_node; - - ivy_ast_node_extend_bounds_recursive( - (struct ivy_ast_node *)op_node, - (struct ivy_ast_node *)tmp); - } - - if (op->op_arity == IVY_OP_BINARY) { - tmp = fx_queue_pop_back(&q); - op_node->n_left - = fx_unbox(struct ivy_ast_node, tmp, n_entry); - - if (op_node->n_left) { - op_node->n_left->n_parent - = (struct ivy_ast_node *)op_node; - - ivy_ast_node_extend_bounds_recursive( - (struct ivy_ast_node *)op_node, - (struct ivy_ast_node *)tmp); - } - } - - /* ...and push the newly-completed operator node to the operand - * queue */ - fx_queue_push_back(&q, &op_node->n_base.n_entry); - next: - entry = next; - } - -#if 0 - debug_printf("** after hierarchisation:\n"); - print_expr_queues(state); -#endif - - /* if we are not processing operators below a certain precedence, - * i.e. when determining the recipient of a keyword-message), these - * operators will still be on the parser state's operator stack, but - * their operands have just been moved to the temporary operand stack - * used above. move them back to the parser state's output queue here - * so they can be used later. */ - entry = fx_queue_first(&state->s_operator_stack); - while (entry) { - fx_queue_entry *entry2 = fx_queue_pop_front(&q); - if (!entry2) { - return IVY_ERR_INTERNAL_FAILURE; - } - - fx_queue_push_back(&state->s_output_queue, entry2); - entry = fx_queue_next(entry); - } - -#if 0 - debug_printf("** after de-linearisation:\n"); - print_expr_queues(state); - ivy_ast_node_print(*expr_tree); - debug_printf("------\n"); -#endif - - /* the final node remaining on the temp operand stack is the root node - * of the new expression tree */ - tmp = fx_queue_pop_back(&q); - *expr_tree = fx_unbox(struct ivy_ast_node, tmp, n_entry); - - return IVY_OK; -} - -struct token_parse_result arith_parse_fstring( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type == EXPR_TYPE_STMT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_component == EXPR_CMP_OPERAND) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_type = EXPR_TYPE_ARITH; - state->s_prev_component = EXPR_CMP_OPERAND; - state->s_prev_token = tok->t_type; - - parser_push_state(ctx, IVY_AST_FSTRING, 0); - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result arith_parse_operand( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type == EXPR_TYPE_STMT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { - /* this is an unlabeled complex message arg */ - if (state->s_prev_token != IVY_SYM_COMMA - && state->s_prev_token != IVY_SYM_LEFT_PAREN) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - struct ivy_token *empty_label = malloc(sizeof *empty_label); - if (!empty_label) { - return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); - } - memset(empty_label, 0x0, sizeof *empty_label); - empty_label->t_type = IVY_TOK_LABEL; - - fx_queue_push_back(&state->s_labels, &empty_label->t_entry); - - struct expr_parser_state *arg_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_copy_terminators(state, arg_expr); - expr_add_terminator(arg_expr, IVY_SYM_COMMA); - arg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_ARG; - arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); - } - - if (state->s_prev_component == EXPR_CMP_OPERAND) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_type = EXPR_TYPE_ARITH; - - arith_push_operand(state, tok); - // print_expr_queues(state); - state->s_prev_component = EXPR_CMP_OPERAND; - state->s_prev_token = tok->t_type; - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result arith_parse_operator( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - unsigned short tok_id = 0; - - switch (tok->t_type) { - case IVY_TOK_SYMBOL: - tok_id = tok->t_symbol; - state->s_prev_token = tok->t_symbol; - break; - case IVY_TOK_KEYWORD: - tok_id = tok->t_keyword; - state->s_prev_token = tok->t_keyword; - break; - default: - tok_id = tok->t_type; - state->s_prev_token = tok->t_type; - break; - } - - if (expr_terminates_at_token(state, tok_id)) { - /* treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - struct ivy_ast_node *op = create_operator_node_from_token(tok); - if (!op) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - arith_push_operator(state, op); - state->s_prev_component = EXPR_CMP_OPERATOR; - -#ifdef IVY_LANG_DEBUG - print_expr_queues(state); -#endif - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result arith_parse_in( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (expr_terminates_at_token(state, IVY_KW_IN)) { - /* treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); -} - -struct token_parse_result arith_parse_do( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - bool terminator = false; - if (expr_terminates_at_token(state, IVY_KW_DO)) { - terminator = true; - } - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG - || state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { - terminator = true; - } - - if (terminator) { - state->s_prev_token = IVY_KW_DO; - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags = PARSE_REPEAT_TOKEN; - return result; - } - - /* next component will be a block. */ - struct block_parser_state *block - = (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. */ - - state->s_prev_token = IVY_KW_DO; - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result arith_parse_ident( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - struct token_parse_result result; - - if (state->s_sub_type == EXPR_SUBTYPE_MSG) { - if (state->s_prev_component == EXPR_CMP_MSG) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - result = arith_parse_operator(ctx, tok); - state->s_prev_component = EXPR_CMP_MSG; - return result; - } - - if (state->s_prev_component == EXPR_CMP_OPERAND - || state->s_prev_component == EXPR_CMP_MSG) { - result = arith_parse_operator(ctx, tok); - state->s_prev_component = EXPR_CMP_MSG; - } else { - result = arith_parse_operand(ctx, tok); - } - - return result; -} - -struct token_parse_result arith_parse_left_paren( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type == EXPR_TYPE_NONE) { - state->s_type = EXPR_TYPE_ARITH; - } - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token == IVY_TOK_IDENT) { - /* this might be the opening parenthesis for a complex message. */ - fx_queue_entry *msg_entry = fx_queue_last(&state->s_operator_stack); - struct ivy_ast_node *msg - = fx_unbox(struct ivy_ast_node, msg_entry, n_entry); - - if (!msg || msg->n_type != IVY_AST_MSG) { - /* this is not a complex message, it's probably a - * call-operator */ - goto not_complex_msg; - } - - fx_queue_pop_back(&state->s_operator_stack); - - struct expr_parser_state *msg_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - expr_add_terminator(msg_expr, IVY_SYM_COMMA); - msg_expr->s_msg = (struct ivy_ast_msg_node *)msg; - msg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_MSG; - msg_expr->s_type = EXPR_TYPE_ARITH; - msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - - msg_expr->s_prev_token = state->s_prev_token = IVY_SYM_LEFT_PAREN; - - return PARSE_RESULT(IVY_OK, 0); - } - -not_complex_msg: - if (state->s_prev_component == EXPR_CMP_OPERAND) { - /* this is the opening parenthesis for a call-operator */ - struct ivy_ast_msg_node *msg - = (struct ivy_ast_msg_node *)ast_node_create(IVY_AST_MSG); - msg->n_sel = unary_selector_from_token( - ivy_token_create_ident("call")); - - struct expr_parser_state *msg_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - msg_expr->s_msg = (struct ivy_ast_msg_node *)msg; - msg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_MSG; - msg_expr->s_type = EXPR_TYPE_ARITH; - msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - - msg_expr->s_prev_token = state->s_prev_token = IVY_SYM_LEFT_PAREN; - - return PARSE_RESULT(IVY_OK, 0); - } - - /* this is a generic parenthesis-enclosed sub-expression. - * create a new sub-expr parser to handle it */ - - if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { - /* this is an unlabeled complex message arg */ - if (state->s_prev_token != IVY_SYM_COMMA - && state->s_prev_token != IVY_SYM_LEFT_PAREN) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - struct ivy_token *empty_label = malloc(sizeof *empty_label); - if (!empty_label) { - return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); - } - memset(empty_label, 0x0, sizeof *empty_label); - empty_label->t_type = IVY_TOK_LABEL; - - fx_queue_push_back(&state->s_labels, &empty_label->t_entry); - - struct expr_parser_state *arg_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_copy_terminators(state, arg_expr); - expr_add_terminator(arg_expr, IVY_SYM_COMMA); - arg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_ARG; - arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); - } - - struct expr_parser_state *sub_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_copy_terminators(state, sub_expr); - sub_expr->s_paren_depth = state->s_paren_depth + 1; - sub_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - sub_expr->s_sub_type = EXPR_SUBTYPE_PAREN; - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result arith_parse_right_paren( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (expr_terminates_at_token(state, IVY_SYM_RIGHT_PAREN)) { - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags = PARSE_REPEAT_TOKEN; - return result; - } - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_paren_depth == 0 && state->s_sub_type == EXPR_SUBTYPE_NONE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev_token = IVY_SYM_RIGHT_PAREN; - return expr_finalise_and_return(ctx, state); -} - -struct token_parse_result arith_parse_left_brace( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type == EXPR_TYPE_NONE) { - state->s_type = EXPR_TYPE_ARITH; - } - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_component != EXPR_CMP_OPERATOR - && state->s_prev_component != EXPR_CMP_NONE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_push_state(ctx, IVY_AST_PKG, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result arith_parse_right_brace( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - state->s_prev_token = IVY_SYM_RIGHT_BRACE; - struct token_parse_result result = expr_finalise_and_return(ctx, state); - result.r_flags = PARSE_REPEAT_TOKEN; - return result; -} - -struct token_parse_result arith_parse_left_bracket( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type == EXPR_TYPE_STMT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_component == EXPR_CMP_OPERAND - || state->s_prev_component == EXPR_CMP_MSG) { - /* subscript operator */ - - state->s_prev_token = IVY_SYM_LEFT_BRACKET; - struct ivy_ast_op_node *subscript - = (struct ivy_ast_op_node *)ast_node_create(IVY_AST_OP); - subscript->n_op = ivy_operator_get_by_id(IVY_OP_SUBSCRIPT); - arith_push_operator(state, (struct ivy_ast_node *)subscript); - - struct expr_parser_state *index - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(index, IVY_SYM_RIGHT_BRACKET); - index->s_subexpr_depth = state->s_subexpr_depth + 1; - - return PARSE_RESULT(IVY_OK, 0); - } - - /* lambda */ - - state->s_prev_token = IVY_SYM_LEFT_BRACKET; - state->s_type = EXPR_TYPE_ARITH; - - parser_push_state(ctx, IVY_AST_LAMBDA, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result arith_parse_right_bracket( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (expr_terminates_at_token(state, IVY_SYM_RIGHT_BRACKET)) { - state->s_prev_token = IVY_SYM_RIGHT_BRACKET; - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags = PARSE_REPEAT_TOKEN; - return result; - } - - if (state->s_prev_token == IVY_SYM_LEFT_BRACKET) { - /* we've just parsed a subscript operator. nothing further to do here. */ - return PARSE_RESULT(IVY_OK, 0); - } - - state->s_prev_token = IVY_SYM_RIGHT_BRACKET; - struct token_parse_result result = expr_finalise_and_return(ctx, state); - result.r_flags = PARSE_REPEAT_TOKEN; - return result; -} - -static struct ivy_ast_selector_node *keyword_selector_from_label_list(fx_queue *labels) -{ - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)ast_node_create(IVY_AST_SELECTOR); - - fx_queue_entry *entry = fx_queue_first(labels); - fx_queue_entry *next = NULL; - - while (entry) { - struct ivy_token *label - = fx_unbox(struct ivy_token, entry, t_entry); - next = fx_queue_next(entry); - fx_queue_delete(labels, entry); - - fx_queue_push_back(&sel->n_arg_labels, &label->t_entry); - entry = next; - } - - return sel; -} - -static struct ivy_ast_cascade_node *expr_finalise_cascade( - struct expr_parser_state *state) -{ - struct ivy_ast_cascade_node *cascade - = (struct ivy_ast_cascade_node *)ast_node_create(IVY_AST_CASCADE); - - cascade->n_recipient = state->s_recipient; - - fx_queue_entry *entry = fx_queue_first(&state->s_cascade_msg); - fx_queue_entry *next = NULL; - - while (entry) { - struct ivy_ast_node *msg - = fx_unbox(struct ivy_ast_node, entry, n_entry); - next = fx_queue_next(entry); - fx_queue_delete(&state->s_cascade_msg, entry); - - fx_queue_push_back(&cascade->n_msg, &msg->n_entry); - entry = next; - } - - return cascade; -} - -static struct ivy_ast_msg_node *expr_finalise_keyword_msg( - struct expr_parser_state *state) -{ - struct ivy_ast_msg_node *msg - = (struct ivy_ast_msg_node *)ast_node_create(IVY_AST_MSG); - - msg->n_recipient = state->s_recipient; - msg->n_sel = keyword_selector_from_label_list(&state->s_labels); - - fx_queue_entry *entry = fx_queue_first(&state->s_args); - fx_queue_entry *next = NULL; - - while (entry) { - struct ivy_ast_node *arg - = fx_unbox(struct ivy_ast_node, entry, n_entry); - next = fx_queue_next(entry); - fx_queue_delete(&state->s_args, entry); - - fx_queue_push_back(&msg->n_arg, &arg->n_entry); - entry = next; - } - - return msg; -} - -static struct ivy_ast_msg_node *expr_finalise_complex_msg( - struct expr_parser_state *state) -{ - struct ivy_ast_msg_node *msg = state->s_msg; - if (!msg) { - return NULL; - } - - state->s_msg = NULL; - - fx_queue_entry *entry = fx_queue_first(&state->s_labels); - fx_queue_entry *next = NULL; - while (entry) { - struct ivy_token *label - = fx_unbox(struct ivy_token, entry, t_entry); - next = fx_queue_next(entry); - fx_queue_delete(&state->s_labels, entry); - fx_queue_push_back(&msg->n_sel->n_arg_labels, &label->t_entry); - - entry = next; - } - - entry = fx_queue_first(&state->s_args); - while (entry) { - struct ivy_ast_node *arg - = fx_unbox(struct ivy_ast_node, entry, n_entry); - next = fx_queue_next(entry); - fx_queue_delete(&state->s_args, entry); - - fx_queue_push_back(&msg->n_arg, &arg->n_entry); - - entry = next; - } - - return msg; -} - -static enum ivy_status begin_cascade_operation(struct ivy_parser *ctx) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - /* this is the beginning of a cascade operation */ - - struct ivy_ast_msg_node *first_msg = NULL; - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { - first_msg = expr_finalise_keyword_msg(state); - parser_pop_state(ctx, 0); - } else { - /* we need to find who the first message in the cascade is being sent to. */ - enum ivy_operator_precedence min_precedence - = IVY_PRECEDENCE_CASCADE; - - struct ivy_ast_node *prev = fx_unbox( - struct ivy_ast_node, - fx_queue_last(&state->s_operator_stack), n_entry); - if (prev && prev->n_type == IVY_AST_MSG) { - /* unary complex messages (which will be found on the - * operator stack) have a very high precedence (much - * higher than most arithmetic operators), so the - * recipient will be much narrower. this also means that - * any subsequent messages in the cascade inherit this - * high precedence, regardless of their type. */ - min_precedence = IVY_PRECEDENCE_UNARY_MSG; - } - - struct ivy_ast_node *expr = NULL; - enum ivy_status status - = expr_finalise_arith(state, &expr, min_precedence); - if (status != IVY_OK) { - return status; - } - - if (expr->n_type != IVY_AST_MSG) { - /* the recipient and first message of the cascade - * operation is ambiguous due to operator precedence. - * this is usually resolved by adding parentheses - * (either around the recipient or around the cascade) - * to make the recipient and first message clear. */ - return IVY_ERR_BAD_SYNTAX; - } - - first_msg = (struct ivy_ast_msg_node *)expr; - } - - struct expr_parser_state *cascade_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - if (!first_msg) { - return IVY_ERR_BAD_SYNTAX; - } - - cascade_expr->s_recipient = first_msg->n_recipient; - first_msg->n_recipient = NULL; - - cascade_expr->s_sub_type = EXPR_SUBTYPE_CASCADE; - cascade_expr->s_type = EXPR_TYPE_ARITH; - cascade_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - - fx_queue_push_back(&cascade_expr->s_cascade_msg, &first_msg->n_base.n_entry); - - struct expr_parser_state *msg_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - msg_expr->s_sub_type = EXPR_SUBTYPE_MSG; - msg_expr->s_type = EXPR_TYPE_ARITH; - msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - - return IVY_OK; -} - -struct token_parse_result arith_parse_semicolon( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - bool end_subexpr = false; - - switch (state->s_sub_type) { - case EXPR_SUBTYPE_KEYWORD_ARG: - case EXPR_SUBTYPE_MSG: - end_subexpr = true; - break; - case EXPR_SUBTYPE_KEYWORD_MSG: - case EXPR_SUBTYPE_CASCADE: - case EXPR_SUBTYPE_COMPLEX_ARG: - case EXPR_SUBTYPE_NONE: - break; - default: - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - break; - } - - if (end_subexpr) { - /* finish parsing this expression and let the parent context handle the semicolon. */ - struct ivy_ast_node *expr = NULL; - enum ivy_status status = expr_finalise_arith( - state, &expr, IVY_PRECEDENCE_ASSIGN); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - parser_replace_current_node(ctx, expr); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); - } - - struct expr_parser_state *parent_state = parser_get_parent_state( - ctx, IVY_AST_EXPR, struct expr_parser_state); - - if (state->s_sub_type == EXPR_SUBTYPE_CASCADE) { - /* this is another message in a cascade series. */ - struct expr_parser_state *msg_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - msg_expr->s_recipient = NULL; - msg_expr->s_sub_type = EXPR_SUBTYPE_MSG; - msg_expr->s_type = EXPR_TYPE_ARITH; - msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - - return PARSE_RESULT(IVY_OK, 0); - } - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG && !state->s_recipient) { - struct ivy_ast_msg_node *msg = expr_finalise_keyword_msg(state); - if (!msg) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_replace_current_node(ctx, (struct ivy_ast_node *)msg); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); - } - - enum ivy_status status = begin_cascade_operation(ctx); - - return PARSE_RESULT(status, 0); -} - -static struct ivy_ast_node *create_return_node(struct ivy_ast_node *val) -{ - struct ivy_ast_return_node *ret - = (struct ivy_ast_return_node *)ast_node_create(IVY_AST_RETURN); - if (!ret) { - return NULL; - } - - ret->n_val = val; - return (struct ivy_ast_node *)ret; -} - -struct token_parse_result expr_finalise( - struct ivy_parser *ctx, struct expr_parser_state *state, - enum ivy_operator_precedence min_precedence, struct ivy_ast_node **result) -{ - int flags = 0; - if (state->s_subexpr_depth > 0) { - flags = PARSE_REPEAT_TOKEN; - } - - if (state->s_paren_depth > 0 && state->s_prev_token == IVY_SYM_RIGHT_PAREN) { - /* this is the ending right paren in a parenthesised expression, so we need to consume it. */ - flags = 0; - } - - if (state->s_sub_type == EXPR_SUBTYPE_MSG) { - /* this is the end of a unary message (probably in a cascade operation). */ - struct ivy_ast_node *expr = NULL; - enum ivy_status status = expr_finalise_arith( - state, &expr, IVY_PRECEDENCE_CASCADE); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - if (state->s_return && expr) { - expr = create_return_node(expr); - } - - *result = expr; - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); - } - - if (state->s_sub_type == EXPR_SUBTYPE_CASCADE) { - /* this is the end of a cascade operation */ - struct ivy_ast_cascade_node *cascade - = expr_finalise_cascade(state); - - if (state->s_return && cascade) { - cascade = (struct ivy_ast_cascade_node *)create_return_node( - (struct ivy_ast_node *)cascade); - } - - *result = (struct ivy_ast_node *)cascade; - return PARSE_RESULT(IVY_OK, flags); - } - - if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { - /* this is the end of a complex message */ - struct ivy_ast_msg_node *msg = expr_finalise_complex_msg(state); - - if (state->s_return && msg) { - msg = (struct ivy_ast_msg_node *)create_return_node( - (struct ivy_ast_node *)msg); - } - - *result = (struct ivy_ast_node *)msg; - return PARSE_RESULT(IVY_OK, 0); - } - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { - /* this is the end of a keyword-message */ - struct ivy_ast_msg_node *msg = expr_finalise_keyword_msg(state); - - if (state->s_return && msg) { - msg = (struct ivy_ast_msg_node *)create_return_node( - (struct ivy_ast_node *)msg); - } - - *result = (struct ivy_ast_node *)msg; - return PARSE_RESULT(IVY_OK, flags); - } - - /* this is the end of a regular expression or sub-expression */ - struct ivy_ast_node *expr = NULL; - enum ivy_status status = expr_finalise_arith(state, &expr, min_precedence); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - if (expr && state->s_return) { - expr = create_return_node(expr); - } - - *result = expr; - return PARSE_RESULT(IVY_OK, flags); -} - -struct token_parse_result expr_finalise_and_return( - struct ivy_parser *ctx, struct expr_parser_state *state) -{ - struct ivy_ast_node *expr_node = NULL; - struct token_parse_result result - = expr_finalise(ctx, state, IVY_PRECEDENCE_ASSIGN, &expr_node); - - if (result.r_status != IVY_OK) { - return result; - } - - parser_replace_current_node(ctx, expr_node); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return result; -} - -struct token_parse_result arith_parse_dot( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_paren_depth > 0) { - /* end-of-expression with mismatched parentheses */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (expr_terminates_at_token(state, IVY_SYM_DOT)) { - /* treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - state->s_prev_token = IVY_SYM_DOT; - return expr_finalise_and_return(ctx, state); -} - -struct token_parse_result arith_parse_bang( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_paren_depth > 0) { - /* end-of-expression with mismatched parentheses */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev_token = IVY_SYM_BANG; - struct token_parse_result result = expr_finalise_and_return(ctx, state); - result.r_flags = PARSE_REPEAT_TOKEN; - return result; -} - -struct token_parse_result arith_parse_caret( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - /* caret must be used at the beginning of a top-level expression */ - if (state->s_subexpr_depth > 0 || state->s_paren_depth > 0) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!fx_queue_empty(&state->s_operator_stack) - || !fx_queue_empty(&state->s_output_queue)) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev_token = IVY_SYM_CARET; - state->s_return = true; - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result arith_parse_comma( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { - /* this is a comma separator between two complex message args */ - state->s_prev_token = IVY_SYM_COMMA; - return PARSE_RESULT(IVY_OK, 0); - } - - if (expr_terminates_at_token(state, IVY_SYM_COMMA)) { - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags = PARSE_REPEAT_TOKEN; - return result; - } - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_paren_depth > 0 - && (state->s_prev_component == EXPR_CMP_OPERAND - || state->s_prev_component == EXPR_CMP_MSG)) { - struct ivy_ast_node *item = NULL; - struct token_parse_result result - = expr_finalise(ctx, state, IVY_PRECEDENCE_ASSIGN, &item); - - if (result.r_status != IVY_OK) { - return result; - } - - if (!item) { - /* empty tuple member expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_sub_type == EXPR_SUBTYPE_PAREN - && fx_queue_empty(&state->s_output_queue) - && fx_queue_empty(&state->s_operator_stack)) { - parser_pop_state(ctx, 0); - } else { - /* the tuple parser will handle the parentheses for us. */ - state->s_paren_depth--; - } - - parser_push_state(ctx, IVY_AST_TUPLE, (uintptr_t)item); - return PARSE_RESULT(IVY_OK, 0); - } - - state->s_prev_token = IVY_SYM_COMMA; - return expr_finalise_and_return(ctx, state); -} - -extern struct token_parse_result arith_parse_equal_right_angle( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - state->s_prev_token = IVY_SYM_EQUAL_RIGHT_ANGLE; - struct token_parse_result result = expr_finalise_and_return(ctx, state); - - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; -} - -struct token_parse_result arith_parse_label( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_type != EXPR_TYPE_ARITH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { - /* we are currently parsing a keyword or complex message - * argument, and have just encountered the label denoting the - * next argument. terminate here and propagate this label to the - * parent keyword-message parser context. */ - struct ivy_ast_node *expr = NULL; - struct token_parse_result result - = expr_finalise(ctx, state, IVY_PRECEDENCE_ASSIGN, &expr); - if (result.r_status != IVY_OK) { - return result; - } - - result.r_flags |= PARSE_REPEAT_TOKEN; - - parser_replace_current_node(ctx, expr); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return result; - } - - if (state->s_sub_type != EXPR_SUBTYPE_KEYWORD_MSG - && state->s_sub_type != EXPR_SUBTYPE_COMPLEX_MSG) { - /* this is the beginning of a new keyword-message */ - struct expr_parser_state *msg_expr; - bool new_parser = true; - - if (fx_queue_empty(&state->s_operator_stack) - && fx_queue_empty(&state->s_output_queue)) { - new_parser = false; - } - - if (new_parser) { - msg_expr = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_copy_terminators(state, msg_expr); - } else { - msg_expr = state; - } - - /* the only operator with a lower precedence than - * keyword-messages is assignment. everything in the preceding - * expression, up to but not including any un-parenthesised - * assignments, is the recipient of the message. */ - struct ivy_ast_node *expr = NULL; - - if (state->s_sub_type != EXPR_SUBTYPE_MSG) { - enum ivy_status status = expr_finalise_arith( - state, &expr, IVY_PRECEDENCE_KEYWORD_MSG); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - } - - msg_expr->s_recipient = expr; - msg_expr->s_sub_type = EXPR_SUBTYPE_KEYWORD_MSG; - msg_expr->s_type = EXPR_TYPE_ARITH; - msg_expr->s_subexpr_depth = state->s_subexpr_depth; - - if (new_parser) { - msg_expr->s_subexpr_depth++; - } - - state = msg_expr; - } - - if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { - /* this label denotes the start of a complex message arg */ - if (state->s_prev_token != IVY_SYM_COMMA - && state->s_prev_token != IVY_SYM_LEFT_PAREN) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - fx_queue_push_back(&state->s_labels, &tok->t_entry); - - struct expr_parser_state *arg_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_copy_terminators(state, arg_expr); - expr_add_terminator(arg_expr, IVY_SYM_COMMA); - arg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_ARG; - arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - } else if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { - /* we may have just finished parsing a keyword-message argument, - * and this label marks the start of a new one. store the label - * and create a new argument parsing context. */ - fx_queue_push_back(&state->s_labels, &tok->t_entry); - - struct expr_parser_state *arg_expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_copy_terminators(state, arg_expr); - expr_add_terminator(arg_expr, IVY_TOK_LABEL); - arg_expr->s_sub_type = EXPR_SUBTYPE_KEYWORD_ARG; - arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; - } - - return PARSE_RESULT(IVY_OK, 0); -} - -enum ivy_status arith_add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct expr_parser_state *state = (struct expr_parser_state *)parent; - - if (state->s_sub_type == EXPR_SUBTYPE_CASCADE) { - /* treat the child node as a cascaded message */ - fx_queue_push_back(&state->s_cascade_msg, &child->n_entry); - } else if ( - state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG - || state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { - /* treat the child node as a keyword-message argument */ - fx_queue_push_back(&state->s_args, &child->n_entry); - } else if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { - /* treat the child node as a sub-expression enclosed in - * parentheses (i.e. an operand). */ - fx_queue_push_back(&state->s_output_queue, &child->n_entry); - state->s_prev_component = EXPR_CMP_OPERAND; - } else if (child->n_type == IVY_AST_MSG) { - arith_push_operator(state, child); - state->s_prev_component = EXPR_CMP_MSG; - } else { - /* treat the child node as a sub-expression enclosed in - * parentheses (i.e. an operand). */ - fx_queue_push_back(&state->s_output_queue, &child->n_entry); - state->s_prev_component = EXPR_CMP_OPERAND; - } - - return IVY_OK; -} diff --git a/lang/ast/expr/expr.c b/lang/ast/expr/expr.c deleted file mode 100644 index 82ccfee..0000000 --- a/lang/ast/expr/expr.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "expr.h" - -#include "../node.h" - -void expr_add_terminator(struct expr_parser_state *state, unsigned short tok) -{ - if (state->s_nr_terminators < EXPR_TERMINATOR_MAX) { - state->s_terminators[state->s_nr_terminators++] = tok; - } -} - -void expr_copy_terminators( - const struct expr_parser_state *src, struct expr_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 expr_terminates_at_token(struct expr_parser_state *state, unsigned short tok) -{ - for (unsigned int i = 0; i < EXPR_TERMINATOR_MAX; i++) { - if (state->s_terminators[i] == tok) { - return true; - } - } - - return false; -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct expr_parser_state *state = (struct expr_parser_state *)parent; - switch (state->s_type) { - case EXPR_TYPE_STMT: - return IVY_ERR_NOT_SUPPORTED; - case EXPR_TYPE_ARITH: - return arith_add_child(parent, child); - default: - return IVY_ERR_NOT_SUPPORTED; - } -} - -struct ast_node_type expr_node_ops = { - .n_add_child = add_child, - .n_state_size = sizeof(struct expr_parser_state), - .n_node_size = sizeof(struct ivy_ast_expr_node), - .n_token_parsers = { - TOK_PARSER(IDENT, arith_parse_ident), - TOK_PARSER(INT, arith_parse_operand), - TOK_PARSER(DOUBLE, arith_parse_operand), - TOK_PARSER(ATOM, arith_parse_operand), - TOK_PARSER(STRING, arith_parse_operand), - TOK_PARSER(STR_START, arith_parse_fstring), - TOK_PARSER(SYMBOL, arith_parse_operator), - TOK_PARSER(LABEL, arith_parse_label), - }, - .n_symbol_parsers = { - SYM_PARSER(LEFT_PAREN, arith_parse_left_paren), - SYM_PARSER(RIGHT_PAREN, arith_parse_right_paren), - SYM_PARSER(LEFT_BRACE, arith_parse_left_brace), - SYM_PARSER(RIGHT_BRACE, arith_parse_right_brace), - SYM_PARSER(LEFT_BRACKET, arith_parse_left_bracket), - SYM_PARSER(RIGHT_BRACKET, arith_parse_right_bracket), - SYM_PARSER(SEMICOLON, arith_parse_semicolon), - SYM_PARSER(UNDERSCORE, arith_parse_operand), - SYM_PARSER(CARET, arith_parse_caret), - /* treat colons as empty labels */ - SYM_PARSER(COLON, arith_parse_label), - SYM_PARSER(COMMA, arith_parse_comma), - SYM_PARSER(DOT, arith_parse_dot), - SYM_PARSER(BANG, arith_parse_bang), - SYM_PARSER(EQUAL_RIGHT_ANGLE, arith_parse_equal_right_angle), - }, - .n_keyword_parsers = { - /* statement keywords */ - KW_PARSER(FOR, stmt_parse_for), - KW_PARSER(WHILE, stmt_parse_while), - KW_PARSER(BREAK, stmt_parse_break), - KW_PARSER(CONTINUE, stmt_parse_continue), - KW_PARSER(TRY, stmt_parse_try), - KW_PARSER(MATCH, stmt_parse_match), - KW_PARSER(IF, stmt_parse_if), - KW_PARSER(THEN, stmt_parse_end), - KW_PARSER(ELSE, stmt_parse_end), - KW_PARSER(ELIF, stmt_parse_end), - KW_PARSER(CATCH, stmt_parse_end), - KW_PARSER(FINALLY, stmt_parse_end), - KW_PARSER(END, stmt_parse_end), - - /* keyword constants */ - KW_PARSER(TRUE, arith_parse_operand), - KW_PARSER(FALSE, arith_parse_operand), - KW_PARSER(NULL, arith_parse_operand), - - /* operator/block keywords */ - KW_PARSER(IN, arith_parse_in), - KW_PARSER(IS, arith_parse_operator), - KW_PARSER(DO, arith_parse_do), - } -}; diff --git a/lang/ast/expr/expr.h b/lang/ast/expr/expr.h deleted file mode 100644 index c86bed9..0000000 --- a/lang/ast/expr/expr.h +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef _AST_EXPR_EXPR_H_ -#define _AST_EXPR_EXPR_H_ - -#include "../ctx.h" -#include "../node.h" - -#include - -#define EXPR_TERMINATOR_MAX 8 - -struct ivy_ast_node; -struct ivy_ast_msg_node; - -enum expr_type { - EXPR_TYPE_NONE = 0, - /* if-else, while/for, match, etc (any expression that ends with an - * 'end' keyword */ - EXPR_TYPE_STMT, - /* arithmetic and message-sending expressions (any expression that ends - * implicitly or with an expression separator */ - EXPR_TYPE_ARITH, -}; - -enum expr_subtype { - EXPR_SUBTYPE_NONE = 0, - /* generic parenthesis-enclosed arithmetic expressions */ - EXPR_SUBTYPE_PAREN, - /* any kind of message */ - EXPR_SUBTYPE_MSG, - /* keyword messages */ - EXPR_SUBTYPE_KEYWORD_MSG, - /* expression delimited by labels */ - EXPR_SUBTYPE_KEYWORD_ARG, - /* complex messages */ - EXPR_SUBTYPE_COMPLEX_MSG, - /* expression delimited by commas */ - EXPR_SUBTYPE_COMPLEX_ARG, - /* message cascade operation */ - EXPR_SUBTYPE_CASCADE, -}; - -enum expr_component { - EXPR_CMP_NONE = 0, - EXPR_CMP_OPERATOR, - EXPR_CMP_OPERAND, - EXPR_CMP_MSG, - EXPR_CMP_KEYWORD, -}; - -struct expr_parser_state { - struct parser_state s_base; - enum expr_type s_type; - enum expr_subtype s_sub_type; - - /* this is a return statement (prefixed with a caret) */ - bool s_return; - - /* for arithmetic expressions, this records whether the previous - * component (either a token or parenthesised group of tokens) is an - * operator, operand, or message */ - enum expr_component s_prev_component; - /* the token type/keyword type/symbol type of the last token that was - * encountered */ - unsigned int s_prev_token; - /* if this is an arithmetic expression, this variable is the depth - * of parentheses that this sub-expression is at */ - unsigned int s_paren_depth; - - /* if this expression is parsing a sub-component of a larger expression, - * the depth of the expression is recorded here. */ - unsigned int s_subexpr_depth; - - /* the expression will be terminated when any token in this list - * is encountered. the token that terminated the expression will - * not be consumed. */ - unsigned short s_terminators[EXPR_TERMINATOR_MAX]; - unsigned short s_nr_terminators; - - fx_queue s_output_queue; - fx_queue s_operator_stack; - - /* these variables are for keyword-message expressions */ - struct ivy_ast_node *s_recipient; - struct ivy_ast_msg_node *s_msg; - fx_queue s_labels; - - union { - /* for keyword-messages, this is a list of arg values. */ - fx_queue s_args; - /* for cascade operators, this is a list of messages to send to the recipient. */ - fx_queue s_cascade_msg; - }; -}; - -/* general functions */ - -extern void expr_add_terminator(struct expr_parser_state *state, unsigned short tok); -extern void expr_copy_terminators( - const struct expr_parser_state *src, struct expr_parser_state *dest); -extern bool expr_terminates_at_token( - struct expr_parser_state *state, unsigned short tok); - -extern struct token_parse_result expr_finalise( - struct ivy_parser *ctx, struct expr_parser_state *state, - enum ivy_operator_precedence min_precedence, struct ivy_ast_node **expr); -extern struct token_parse_result expr_finalise_and_return( - struct ivy_parser *ctx, struct expr_parser_state *state); - -/* arithmetic parser callbacks */ - -extern void arith_push_operator( - struct expr_parser_state *state, struct ivy_ast_node *node); -extern enum ivy_status arith_push_operand( - struct expr_parser_state *state, struct ivy_token *tok); - -extern enum ivy_status arith_add_child( - struct parser_state *parent, struct ivy_ast_node *child); - -extern struct token_parse_result arith_parse_ident( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_fstring( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_operand( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_operator( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_label( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_left_paren( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_right_paren( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_left_brace( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_right_brace( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_left_bracket( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_right_bracket( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_semicolon( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_dot( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_bang( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_caret( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_comma( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_equal_right_angle( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_in( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_is( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result arith_parse_do( - struct ivy_parser *ctx, struct ivy_token *tok); - -/* statement parser callbacks */ - -extern struct token_parse_result stmt_parse_try( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result stmt_parse_for( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result stmt_parse_while( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result stmt_parse_match( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result stmt_parse_if( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result stmt_parse_then( - struct ivy_parser *ctx, struct ivy_token *tok); -struct token_parse_result stmt_parse_else( - struct ivy_parser *ctx, struct ivy_token *tok); -struct token_parse_result stmt_parse_end( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result stmt_parse_break( - struct ivy_parser *ctx, struct ivy_token *tok); -extern struct token_parse_result stmt_parse_continue( - struct ivy_parser *ctx, struct ivy_token *tok); - -#endif diff --git a/lang/ast/expr/stmt.c b/lang/ast/expr/stmt.c deleted file mode 100644 index 4b4926c..0000000 --- a/lang/ast/expr/stmt.c +++ /dev/null @@ -1,266 +0,0 @@ -#include "../node.h" -#include "expr.h" - -#include -#include -#include -#include - -struct token_parse_result stmt_parse_try( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (expr_terminates_at_token(state, IVY_KW_TRY)) { - /* treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { - /* try-catch cannot be used inline. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev_token = IVY_KW_TRY; - - if (fx_queue_empty(&state->s_operator_stack) - && fx_queue_empty(&state->s_output_queue)) { - parser_pop_state(ctx, 0); - } - - /* if expr is NULL, this is an if-then-else-end statement, - * otherwise, this is an expr-if-else-expr. */ - parser_push_state(ctx, IVY_AST_TRY, 0); - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result stmt_parse_for( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (expr_terminates_at_token(state, IVY_KW_FOR)) { - /* treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { - /* keyword messages have a higher precedence than inline - * conditionals, so treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - struct ivy_ast_node *expr = NULL; - struct token_parse_result result - = expr_finalise(ctx, state, IVY_PRECEDENCE_IF_ELSE, &expr); - if (result.r_status != IVY_OK) { - return result; - } - - state->s_prev_token = IVY_KW_FOR; - - if (fx_queue_empty(&state->s_operator_stack) - && fx_queue_empty(&state->s_output_queue)) { - parser_pop_state(ctx, 0); - } - - /* if expr is NULL, this is an if-then-else-end statement, - * otherwise, this is an expr-if-else-expr. */ - parser_push_state(ctx, IVY_AST_FOR_LOOP, (uintptr_t)expr); - - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -struct token_parse_result stmt_parse_while( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { - /* keyword messages have a higher precedence than inline - * conditionals, so treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - struct ivy_ast_node *expr = NULL; - struct token_parse_result result - = expr_finalise(ctx, state, IVY_PRECEDENCE_IF_ELSE, &expr); - if (result.r_status != IVY_OK) { - return result; - } - - state->s_prev_token = IVY_KW_WHILE; - - if (fx_queue_empty(&state->s_operator_stack) - && fx_queue_empty(&state->s_output_queue)) { - parser_pop_state(ctx, 0); - } - - /* if expr is NULL, this is an if-then-else-end statement, - * otherwise, this is an expr-if-else-expr. */ - parser_push_state(ctx, IVY_AST_WHILE_LOOP, (uintptr_t)expr); - - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -struct token_parse_result stmt_parse_match( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_prev_component == EXPR_CMP_OPERAND - || state->s_prev_component == EXPR_CMP_MSG) { - /* match statements are operands. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - struct ivy_ast_node *expr = NULL; - struct token_parse_result result - = expr_finalise(ctx, state, IVY_PRECEDENCE_IF_ELSE, &expr); - if (result.r_status != IVY_OK) { - return result; - } - - state->s_prev_token = IVY_KW_MATCH; - - if (fx_queue_empty(&state->s_operator_stack) - && fx_queue_empty(&state->s_output_queue)) { - parser_pop_state(ctx, 0); - } - - /* if expr is NULL, this is an if-then-else-end statement, - * otherwise, this is an expr-if-else-expr. */ - struct cond_group_parser_state *cond - = (struct cond_group_parser_state *)parser_push_state( - ctx, IVY_AST_MATCH, 0); - - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -struct token_parse_result stmt_parse_if( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (expr_terminates_at_token(state, IVY_KW_IF)) { - /* treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) { - /* keyword messages have a higher precedence than inline - * conditionals, so treat this as a statement terminator. */ - struct token_parse_result result - = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; - } - - struct ivy_ast_node *expr = NULL; - struct token_parse_result result - = expr_finalise(ctx, state, IVY_PRECEDENCE_IF_ELSE, &expr); - if (result.r_status != IVY_OK) { - return result; - } - - state->s_prev_token = IVY_KW_IF; - - if (fx_queue_empty(&state->s_operator_stack) - && fx_queue_empty(&state->s_output_queue)) { - parser_pop_state(ctx, 0); - } - - /* if expr is NULL, this is an if-then-else-end statement, - * otherwise, this is an expr-if-else-expr. */ - struct cond_group_parser_state *cond - = (struct cond_group_parser_state *)parser_push_state( - ctx, IVY_AST_COND_GROUP, (uintptr_t)expr); - - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -struct token_parse_result stmt_parse_then( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - /* treat this as a statement terminator. */ - struct token_parse_result result = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; -} - -struct token_parse_result stmt_parse_else( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - /* treat this as a statement terminator. */ - struct token_parse_result result = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; -} - -struct token_parse_result stmt_parse_end( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - /* treat this as a statement terminator. */ - struct token_parse_result result = expr_finalise_and_return(ctx, state); - result.r_flags |= PARSE_REPEAT_TOKEN; - return result; -} - -struct token_parse_result stmt_parse_break( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_prev_component != EXPR_CMP_NONE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - arith_push_operand(state, tok); - state->s_prev_component = EXPR_CMP_KEYWORD; - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result stmt_parse_continue( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *state - = parser_get_state(ctx, struct expr_parser_state); - - if (state->s_prev_component != EXPR_CMP_NONE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - arith_push_operand(state, tok); - state->s_prev_component = EXPR_CMP_KEYWORD; - - return PARSE_RESULT(IVY_OK, 0); -} diff --git a/lang/ast/for.c b/lang/ast/for.c index 10499e2..08d75fb 100644 --- a/lang/ast/for.c +++ b/lang/ast/for.c @@ -1,248 +1,5 @@ -#include "block.h" -#include "expr/expr.h" #include "iterate.h" - -struct for_parser_state { - struct parser_state s_base; - bool s_inline; - unsigned int s_prev_token; - - struct ivy_ast_node *s_body, *s_iterator, *s_iterable; - - struct ivy_ast_node *s_prev_node; -}; - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct for_parser_state *state = (struct for_parser_state *)sp; - state->s_prev_node = (struct ivy_ast_node *)arg; -} - -struct token_parse_result parse_for(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct for_parser_state *state - = parser_get_state(ctx, struct for_parser_state); - - if (state->s_prev_node) { - /* this is an inline for-loop */ - state->s_inline = true; - state->s_body = state->s_prev_node; - state->s_prev_node = NULL; - } else { - state->s_inline = false; - } - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - state->s_prev_token = IVY_KW_FOR; - expr_add_terminator(expr, IVY_KW_IN); - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_in( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct for_parser_state *state - = parser_get_state(ctx, struct for_parser_state); - - if (state->s_prev_token != IVY_KW_FOR) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - /* previous component was the for iterator */ - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_iterator = state->s_prev_node; - state->s_prev_node = NULL; - - /* next component will be the for iterable. */ - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - /* set the sub-expression depth to be non-zero so the expression parser doesn't consume the expression separator. */ - expr->s_subexpr_depth = 1; - expr_add_terminator(expr, IVY_KW_DO); - expr_add_terminator(expr, IVY_SYM_RIGHT_PAREN); - - state->s_prev_token = IVY_KW_IN; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_do( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct for_parser_state *state - = parser_get_state(ctx, struct for_parser_state); - - if (state->s_inline) { - struct ivy_diag *diag = parser_push_diag( - ctx, IVY_LANG_E_INCORRECT_INLINE_FOR_LOOP, - IVY_LANG_MSG_DO_UNEXPECTED_IN_INLINE_FOR, tok); - ivy_diag_push_msg( - diag, IVY_LANG_MSG_PREVIOUS_EXPRESSION_IS_FOR_BODY); - const struct ivy_char_cell *x = &state->s_body->n_end; - const struct ivy_char_cell *z = &tok->t_end; - - const struct ivy_diag_amendment a[] = { - IVY_DIAG_ADD(x->c_row, x->c_col + 1, "."), - }; - const size_t nr_a = sizeof a / sizeof a[0]; - - const struct ivy_diag_highlight hl[] = { - IVY_DIAG_HL( - HINT, x->c_row, x->c_col + 1, x->c_row, - x->c_col + 1), - }; - const size_t nr_hl = sizeof hl / sizeof hl[0]; - - ivy_diag_push_snippet(diag, x->c_row, z->c_row, a, nr_a, hl, nr_hl); - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token != IVY_KW_IN) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - /* previous component was the for iterable. */ - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_iterable = state->s_prev_node; - state->s_prev_node = NULL; - - /* next component will be a block. */ - struct block_parser_state *block - = (struct block_parser_state *)parser_push_state( - ctx, IVY_AST_BLOCK, 0); - - block_add_terminator(block, IVY_KW_END); - state->s_prev_token = IVY_KW_DO; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_expr_begin( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct for_parser_state *state - = parser_get_state(ctx, struct for_parser_state); - - if (state->s_prev_token != IVY_KW_DO) { - /* expression can only follow do keyword. */ - 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_add_terminator(block, IVY_KW_END); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static enum ivy_status finalise_for_loop(struct for_parser_state *state) -{ - struct ivy_ast_for_loop_node *loop - = (struct ivy_ast_for_loop_node *)state->s_base.s_node; - - if (state->s_inline) { - /* we have just reached the end of the for iterable. */ - if (!state->s_prev_node) { - /* for condition is empty. */ - return IVY_ERR_BAD_SYNTAX; - } - - state->s_iterable = state->s_prev_node; - state->s_prev_node = NULL; - - loop->n_iterator = state->s_iterator; - loop->n_iterable = state->s_iterable; - loop->n_body = state->s_body; - - state->s_iterator = NULL; - state->s_iterable = NULL; - state->s_body = NULL; - - return IVY_OK; - } - - if (!state->s_prev_node) { - /* for body is empty. */ - return IVY_ERR_BAD_SYNTAX; - } - - state->s_body = state->s_prev_node; - state->s_prev_node = NULL; - - loop->n_iterator = state->s_iterator; - loop->n_iterable = state->s_iterable; - loop->n_body = state->s_body; - - state->s_iterator = NULL; - state->s_iterable = NULL; - state->s_body = NULL; - - return IVY_OK; -} - -static struct token_parse_result parse_punct_terminator( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct for_parser_state *state - = parser_get_state(ctx, struct for_parser_state); - - if (!state->s_inline) { - /* only inline for loop can be ended with punctuation. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = finalise_for_loop(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static struct token_parse_result parse_end( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct for_parser_state *state - = parser_get_state(ctx, struct for_parser_state); - - if (state->s_inline) { - /* inline for loop must be terminated with punctuation. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = finalise_for_loop(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct for_parser_state *state = (struct for_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} +#include "node.h" static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) @@ -263,24 +20,6 @@ static void collect_children( } struct ast_node_type for_loop_node_ops = { - .n_init_state = init_state, - .n_add_child = add_child, .n_collect_children = collect_children, - .n_state_size = sizeof(struct for_parser_state), .n_node_size = sizeof(struct ivy_ast_for_loop_node), - .n_keyword_parsers = { - KW_PARSER(FOR, parse_for), - KW_PARSER(IN, parse_in), - KW_PARSER(DO, parse_do), - KW_PARSER(END, parse_end), - }, - .n_symbol_parsers = { - SYM_PARSER(DOT, parse_punct_terminator), - SYM_PARSER(COMMA, parse_punct_terminator), - SYM_PARSER(RIGHT_PAREN, parse_punct_terminator), - SYM_PARSER(BANG, parse_punct_terminator), - }, - .n_expr_parser = { - .expr_begin = parse_expr_begin, - }, }; diff --git a/lang/ast/global.c b/lang/ast/global.c index 5a8ebe3..45b98b3 100644 --- a/lang/ast/global.c +++ b/lang/ast/global.c @@ -1,108 +1,8 @@ -#include "ctx.h" -#include "expr/expr.h" #include "iterate.h" #include "node.h" #include -struct global_parser_state { - struct parser_state s_base; - unsigned int s_prev_token; -}; - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct global_parser_state *state = (struct global_parser_state *)sp; - state->s_prev_token = IVY_KW_GLOBAL; -} - -struct token_parse_result parse_ident(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct global_parser_state *state - = parser_get_state(ctx, struct global_parser_state); - if (state->s_prev_token != IVY_KW_GLOBAL) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - struct expr_parser_state *ident_parse - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(ident_parse, IVY_SYM_EQUAL); - expr_add_terminator(ident_parse, IVY_SYM_DOT); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -struct token_parse_result parse_left_paren( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct global_parser_state *state - = parser_get_state(ctx, struct global_parser_state); - - if (state->s_prev_token != IVY_KW_GLOBAL) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - struct expr_parser_state *tuple_ident_parse - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(tuple_ident_parse, IVY_SYM_EQUAL); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -struct token_parse_result parse_equal(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct global_parser_state *state - = parser_get_state(ctx, struct global_parser_state); - struct ivy_ast_global_node *global - = (struct ivy_ast_global_node *)state->s_base.s_node; - if (!global->n_left) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev_token = IVY_SYM_EQUAL; - - struct expr_parser_state *val_parse - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(val_parse, IVY_SYM_DOT); - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result parse_dot(struct ivy_parser *ctx, struct ivy_token *tok) -{ - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct global_parser_state *state = (struct global_parser_state *)parent; - struct ivy_ast_global_node *global - = (struct ivy_ast_global_node *)parent->s_node; - - switch (state->s_prev_token) { - case IVY_KW_GLOBAL: - if (global->n_left) { - return IVY_ERR_BAD_SYNTAX; - } - - global->n_left = child; - break; - case IVY_SYM_EQUAL: - if (global->n_val) { - return IVY_ERR_BAD_SYNTAX; - } - - global->n_val = child; - break; - default: - return IVY_ERR_BAD_SYNTAX; - } - - return IVY_OK; -} - static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { @@ -118,17 +18,6 @@ static void collect_children( } struct ast_node_type global_node_ops = { - .n_add_child = add_child, .n_collect_children = collect_children, - .n_state_size = sizeof(struct global_parser_state), .n_node_size = sizeof(struct ivy_ast_global_node), - .n_init_state = init_state, - .n_token_parsers = { - TOK_PARSER(IDENT, parse_ident), - }, - .n_symbol_parsers = { - SYM_PARSER(LEFT_PAREN, parse_left_paren), - SYM_PARSER(EQUAL, parse_equal), - SYM_PARSER(DOT, parse_dot), - }, }; diff --git a/lang/ast/ident.c b/lang/ast/ident.c index 9efb3c2..04325e9 100644 --- a/lang/ast/ident.c +++ b/lang/ast/ident.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "node.h" #include @@ -14,6 +13,5 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) struct ast_node_type ident_node_ops = { .n_to_string = to_string, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_ident_node), }; diff --git a/lang/ast/int.c b/lang/ast/int.c index 203a44d..6da8676 100644 --- a/lang/ast/int.c +++ b/lang/ast/int.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "node.h" #include @@ -14,6 +13,5 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) struct ast_node_type int_node_ops = { .n_to_string = to_string, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_int_node), }; diff --git a/lang/ast/lambda.c b/lang/ast/lambda.c deleted file mode 100644 index b5ed476..0000000 --- a/lang/ast/lambda.c +++ /dev/null @@ -1,180 +0,0 @@ -#include "block.h" -#include "ctx.h" -#include "iterate.h" -#include "node.h" - -#include - -struct lambda_parser_state { - struct parser_state s_base; - - struct ivy_ast_node *s_prev_node; - unsigned int s_prev; - - fx_queue s_args; - struct ivy_ast_node *s_body; -}; - -static struct token_parse_result parse_expr_begin( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct lambda_parser_state *state - = parser_get_state(ctx, struct lambda_parser_state); - - if (state->s_prev != IVY_SYM_LEFT_BRACKET && state->s_prev != IVY_SYM_PIPE) { - /* unexpected expression. */ - 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_add_terminator(block, IVY_SYM_RIGHT_BRACKET); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static struct token_parse_result parse_ident( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct lambda_parser_state *state - = parser_get_state(ctx, struct lambda_parser_state); - - if (state->s_prev == IVY_SYM_LEFT_BRACKET || state->s_prev == IVY_SYM_PIPE) { - return parse_expr_begin(ctx, tok); - } - - if (state->s_prev != IVY_SYM_COLON) { - /* the only idents we're expecting are parameter names, - * which are always preceded with a colon */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - struct ivy_ast_ident_node *arg - = (struct ivy_ast_ident_node *)ast_node_create(IVY_AST_IDENT); - if (!arg) { - return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); - } - - arg->n_content = tok; - fx_queue_push_back(&state->s_args, &arg->n_base.n_entry); - state->s_prev = IVY_TOK_IDENT; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_colon( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct lambda_parser_state *state - = parser_get_state(ctx, struct lambda_parser_state); - - if (state->s_prev != IVY_SYM_LEFT_BRACKET - && state->s_prev != IVY_TOK_IDENT) { - /* colons can only be used before arg names */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_COLON; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_pipe( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct lambda_parser_state *state - = parser_get_state(ctx, struct lambda_parser_state); - - if (state->s_prev != IVY_TOK_IDENT) { - /* pipe can only be used after an arg name. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_PIPE; - return PARSE_RESULT(IVY_OK, 0); -} - -static void finalise_lambda(struct lambda_parser_state *state) -{ - struct ivy_ast_lambda_node *lambda - = (struct ivy_ast_lambda_node *)state->s_base.s_node; - - lambda->n_arg = state->s_args; - lambda->n_body = state->s_body; - - state->s_args = FX_QUEUE_INIT; - state->s_body = NULL; -} - -static struct token_parse_result parse_right_bracket( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct lambda_parser_state *state - = parser_get_state(ctx, struct lambda_parser_state); - - if (!state->s_prev_node) { - /* empty lambda */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_body = state->s_prev_node; - state->s_prev_node = NULL; - - finalise_lambda(state); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct lambda_parser_state *state = (struct lambda_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct lambda_parser_state *state = (struct lambda_parser_state *)sp; - state->s_prev = IVY_SYM_LEFT_BRACKET; -} - -static void collect_children( - struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) -{ - struct ivy_ast_lambda_node *lambda = (struct ivy_ast_lambda_node *)node; - fx_queue_entry *entry = fx_queue_first(&lambda->n_arg); - while (entry) { - struct ivy_ast_node *expr - = fx_unbox(struct ivy_ast_node, entry, n_entry); - ast_node_iterator_enqueue_node(iterator, node, expr); - entry = fx_queue_next(entry); - } - - if (lambda->n_body) { - ast_node_iterator_enqueue_node(iterator, node, lambda->n_body); - } -} - -struct ast_node_type lambda_node_ops = { - .n_add_child = add_child, - .n_init_state = init_state, - .n_collect_children = collect_children, - .n_state_size = sizeof(struct lambda_parser_state), - .n_node_size = sizeof(struct ivy_ast_lambda_node), - .n_token_parsers = { - TOK_PARSER(IDENT, parse_ident), - }, - .n_symbol_parsers = { - SYM_PARSER(RIGHT_BRACKET, parse_right_bracket), - SYM_PARSER(PIPE, parse_pipe), - SYM_PARSER(COLON, parse_colon), - }, - .n_expr_parser = { - .expr_begin = parse_expr_begin, - }, -}; diff --git a/lang/ast/loop-control.c b/lang/ast/loop-control.c index 99c55e2..358bf83 100644 --- a/lang/ast/loop-control.c +++ b/lang/ast/loop-control.c @@ -1,21 +1,19 @@ -#include "ctx.h" #include "node.h" #include static void to_string(struct ivy_ast_node *node, fx_string *str) { - fx_string_append_cstrf(str, "%s", ivy_ast_node_type_to_string(node->n_type)); + fx_string_append_cstrf( + str, "%s", ivy_ast_node_type_to_string(node->n_type)); } struct ast_node_type loop_break_node_ops = { .n_to_string = to_string, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_loop_break_node), }; struct ast_node_type loop_repeat_node_ops = { .n_to_string = to_string, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_loop_repeat_node), }; diff --git a/lang/ast/match.c b/lang/ast/match.c index 65e6356..720dd51 100644 --- a/lang/ast/match.c +++ b/lang/ast/match.c @@ -1,259 +1,5 @@ -#include "block.h" -#include "expr/expr.h" #include "iterate.h" - -struct match_parser_state { - struct parser_state s_base; - unsigned int s_prev_token; - - struct ivy_ast_node *s_cond; - - struct ivy_ast_cond_node *s_cur_branch; - fx_queue s_branches; - - struct ivy_ast_node *s_prev_node; -}; - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct match_parser_state *state = (struct match_parser_state *)sp; - state->s_prev_node = (struct ivy_ast_node *)arg; -} - -struct token_parse_result parse_match(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct match_parser_state *state - = parser_get_state(ctx, struct match_parser_state); - - if (state->s_cur_branch || state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - 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); - } - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - state->s_prev_token = IVY_KW_MATCH; - expr->s_subexpr_depth = 1; - expr_add_terminator(expr, IVY_KW_IN); - - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status flush_current_branch(struct match_parser_state *state) -{ - if (!state->s_cur_branch) { - return IVY_ERR_INTERNAL_FAILURE; - } - - fx_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; - } - - return IVY_OK; -} - -struct token_parse_result parse_in(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct match_parser_state *state - = parser_get_state(ctx, struct match_parser_state); - - if (!state->s_cur_branch) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token != IVY_KW_MATCH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - /* previous component was the match-condition. */ - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cond = state->s_prev_node; - state->s_prev_node = NULL; - - /* next component will be a branch condition. */ - struct block_parser_state *block - = (struct block_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - state->s_prev_token = IVY_KW_IN; - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status finalise_match(struct match_parser_state *state) -{ - struct ivy_ast_match_node *match - = (struct ivy_ast_match_node *)state->s_base.s_node; - - /* we have just reached the 'end' keyword. */ - if (!state->s_cur_branch) { - /* not currently parsing a conditional branch. */ - return IVY_ERR_BAD_SYNTAX; - } - - match->n_cond = state->s_cond; - match->n_branches = state->s_branches; - state->s_branches = FX_QUEUE_INIT; - return IVY_OK; -} - -static struct token_parse_result parse_arrow( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct match_parser_state *state - = parser_get_state(ctx, struct match_parser_state); - - if (state->s_prev_token != IVY_KW_IN - && state->s_prev_token != IVY_SYM_COMMA) { - /* this token can only appear after the `in` keyword and an expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cur_branch->n_cond = state->s_prev_node; - state->s_prev_node = NULL; - state->s_prev_token = IVY_SYM_EQUAL_RIGHT_ANGLE; - - /* the next component is the branch body */ -#if 0 - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - expr_add_terminator(expr, IVY_KW_END); - expr_add_terminator(expr, IVY_SYM_COMMA); - expr->s_subexpr_depth = 1; -#endif - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_comma( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct match_parser_state *state - = parser_get_state(ctx, struct match_parser_state); - - if (state->s_prev_token != IVY_SYM_EQUAL_RIGHT_ANGLE) { - /* this token can only appear after the `=>` symbol and an expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cur_branch->n_body = state->s_prev_node; - flush_current_branch(state); - state->s_prev_node = NULL; - state->s_prev_token = IVY_SYM_COMMA; - - /* the next component is a branch condition */ - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - expr->s_subexpr_depth = 1; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_end( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct match_parser_state *state - = parser_get_state(ctx, struct match_parser_state); - - /* end can only be used after the '=>' symbol and an expression */ - if (state->s_prev_token != IVY_SYM_EQUAL_RIGHT_ANGLE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cur_branch->n_body = state->s_prev_node; - flush_current_branch(state); - state->s_prev_node = NULL; - state->s_prev_token = IVY_KW_END; - - enum ivy_status status = finalise_match(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_block( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct match_parser_state *state - = parser_get_state(ctx, struct match_parser_state); - - if (state->s_prev_token != IVY_SYM_EQUAL_RIGHT_ANGLE) { - 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); - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_expr( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct match_parser_state *state - = parser_get_state(ctx, struct match_parser_state); - - if (state->s_prev_token != IVY_SYM_EQUAL_RIGHT_ANGLE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - if (tok->t_type != IVY_TOK_KEYWORD) { - expr_add_terminator(expr, IVY_KW_END); - } - - expr_add_terminator(expr, IVY_SYM_COMMA); - expr->s_subexpr_depth = 1; - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct match_parser_state *state = (struct match_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} +#include "node.h" static void match_collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) @@ -267,24 +13,11 @@ static void match_collect_children( struct ivy_ast_node *branch = fx_unbox(struct ivy_ast_node, entry, n_entry); ast_node_iterator_enqueue_node(iterator, node, branch); + entry = fx_queue_next(entry); } } struct ast_node_type match_node_ops = { - .n_init_state = init_state, - .n_add_child = add_child, .n_collect_children = match_collect_children, - .n_state_size = sizeof(struct match_parser_state), .n_node_size = sizeof(struct ivy_ast_match_node), - .n_expr_parser = parse_expr, - .n_keyword_parsers = { - KW_PARSER(MATCH, parse_match), - KW_PARSER(IN, parse_in), - KW_PARSER(END, parse_end), - KW_PARSER(DO, parse_block), - }, - .n_symbol_parsers = { - SYM_PARSER(EQUAL_RIGHT_ANGLE, parse_arrow), - SYM_PARSER(COMMA, parse_comma), - }, }; diff --git a/lang/ast/msg.c b/lang/ast/msg.c index 81c28cf..61e315f 100644 --- a/lang/ast/msg.c +++ b/lang/ast/msg.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "iterate.h" #include "node.h" @@ -27,6 +26,5 @@ static void collect_children( struct ast_node_type msg_node_ops = { .n_collect_children = collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_msg_node), }; diff --git a/lang/ast/msgh.c b/lang/ast/msgh.c index 3152a09..16e65e8 100644 --- a/lang/ast/msgh.c +++ b/lang/ast/msgh.c @@ -1,5 +1,4 @@ #include "block.h" -#include "ctx.h" #include "iterate.h" #include "ivy/status.h" #include "node.h" @@ -7,107 +6,6 @@ #include #include -struct msgh_parser_state { - struct parser_state s_base; - bool s_oneline; - - unsigned int s_i; - unsigned int s_prev; -}; - -static struct token_parse_result parse_linefeed( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct msgh_parser_state *state - = parser_get_state(ctx, struct msgh_parser_state); - - struct ivy_ast_msgh_node *msgh - = (struct ivy_ast_msgh_node *)state->s_base.s_node; - - if (state->s_oneline) { - if (msgh->n_body) { - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); - } - - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!msgh->n_sel) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - struct block_parser_state *block_state - = (struct block_parser_state *)parser_push_state( - ctx, IVY_AST_BLOCK, 0); - block_add_terminator(block_state, IVY_SYM_BANG); - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_bang( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct msgh_parser_state *state - = parser_get_state(ctx, struct msgh_parser_state); - - struct ivy_ast_msgh_node *msgh - = (struct ivy_ast_msgh_node *)state->s_base.s_node; - - if (!msgh->n_sel || state->s_oneline) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_pipe( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct msgh_parser_state *state - = parser_get_state(ctx, struct msgh_parser_state); - - struct ivy_ast_msgh_node *msgh - = (struct ivy_ast_msgh_node *)state->s_base.s_node; - - if (!msgh->n_sel || state->s_oneline) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_oneline = true; - parser_push_state(ctx, IVY_AST_EXPR, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct ivy_ast_msgh_node *msgh = (struct ivy_ast_msgh_node *)parent->s_node; - - if (child->n_type == IVY_AST_SELECTOR && !msgh->n_sel) { - msgh->n_sel = (struct ivy_ast_selector_node *)child; - return IVY_OK; - } - - if (!msgh->n_body) { - msgh->n_body = child; - return IVY_OK; - } - - return IVY_OK; -} - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct msgh_parser_state *state = (struct msgh_parser_state *)sp; - state->s_oneline = false; - state->s_i = 0; - state->s_prev = IVY_SYM_HYPHEN; - - parser_push_state(ctx, IVY_AST_SELECTOR, 0); -} - static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { @@ -117,16 +15,6 @@ static void collect_children( } struct ast_node_type msgh_node_ops = { - .n_add_child = add_child, - .n_init_state = init_state, .n_collect_children = collect_children, - .n_state_size = sizeof(struct msgh_parser_state), .n_node_size = sizeof(struct ivy_ast_msgh_node), - .n_token_parsers = { - TOK_PARSER(LINEFEED, parse_linefeed), - }, - .n_symbol_parsers = { - SYM_PARSER(BANG, parse_bang), - SYM_PARSER(PIPE, parse_pipe), - }, }; diff --git a/lang/ast/node.c b/lang/ast/node.c index 10f1206..8021a9d 100644 --- a/lang/ast/node.c +++ b/lang/ast/node.c @@ -12,9 +12,9 @@ extern struct ast_node_type unit_import_node_ops; extern struct ast_node_type class_node_ops; extern struct ast_node_type msgh_node_ops; extern struct ast_node_type selector_node_ops; -extern struct ast_node_type expr_node_ops; extern struct ast_node_type block_node_ops; extern struct ast_node_type msg_node_ops; +extern struct ast_node_type do_node_ops; extern struct ast_node_type op_node_ops; extern struct ast_node_type global_node_ops; extern struct ast_node_type ident_node_ops; @@ -34,8 +34,6 @@ extern struct ast_node_type loop_break_node_ops; extern struct ast_node_type loop_repeat_node_ops; extern struct ast_node_type return_node_ops; extern struct ast_node_type property_node_ops; -extern struct ast_node_type lambda_node_ops; -extern struct ast_node_type pkg_node_ops; extern struct ast_node_type pkg_static_node_ops; extern struct ast_node_type pkg_static_item_node_ops; extern struct ast_node_type pkg_dynamic_node_ops; @@ -53,9 +51,9 @@ static const struct ast_node_type *node_ops[] = { [IVY_AST_CLASS] = &class_node_ops, [IVY_AST_MSGH] = &msgh_node_ops, [IVY_AST_SELECTOR] = &selector_node_ops, - [IVY_AST_EXPR] = &expr_node_ops, [IVY_AST_BLOCK] = &block_node_ops, [IVY_AST_MSG] = &msg_node_ops, + [IVY_AST_DO] = &do_node_ops, [IVY_AST_OP] = &op_node_ops, [IVY_AST_GLOBAL] = &global_node_ops, [IVY_AST_IDENT] = &ident_node_ops, @@ -75,8 +73,6 @@ static const struct ast_node_type *node_ops[] = { [IVY_AST_LOOP_REPEAT] = &loop_repeat_node_ops, [IVY_AST_RETURN] = &return_node_ops, [IVY_AST_PROPERTY] = &property_node_ops, - [IVY_AST_LAMBDA] = &lambda_node_ops, - [IVY_AST_PKG] = &pkg_node_ops, [IVY_AST_PKG_STATIC] = &pkg_static_node_ops, [IVY_AST_PKG_ITEM] = &pkg_static_item_node_ops, [IVY_AST_PKG_DYNAMIC] = &pkg_dynamic_node_ops, @@ -98,135 +94,6 @@ const struct ast_node_type *get_ast_node_type(enum ivy_ast_node_type type) return node_ops[type]; } -enum token_expr_type get_token_expr_type(struct ivy_token *tok) -{ - const struct ivy_operator *op = NULL; - - switch (tok->t_type) { - case IVY_TOK_IDENT: - case IVY_TOK_INT: - case IVY_TOK_DOUBLE: - case IVY_TOK_STRING: - case IVY_TOK_STR_START: - case IVY_TOK_ATOM: - return TOK_EXPR_BEGIN; - case IVY_TOK_SYMBOL: - switch (tok->t_symbol) { - case IVY_SYM_LEFT_PAREN: - case IVY_SYM_LEFT_BRACKET: - case IVY_SYM_LEFT_BRACE: - case IVY_SYM_CARET: - case IVY_SYM_UNDERSCORE: - return TOK_EXPR_BEGIN; - case IVY_SYM_COMMA: - return TOK_EXPR_ANY; - default: - op = ivy_operator_get_by_token(tok->t_symbol); - return op ? TOK_EXPR_ANY : TOK_EXPR_NONE; - } - case IVY_TOK_KEYWORD: - switch (tok->t_keyword) { - case IVY_KW_IF: - case IVY_KW_ELSE: - case IVY_KW_MATCH: - case IVY_KW_FOR: - case IVY_KW_WHILE: - case IVY_KW_BREAK: - case IVY_KW_CONTINUE: - case IVY_KW_TRY: - case IVY_KW_THROW: - case IVY_KW_TRUE: - case IVY_KW_FALSE: - case IVY_KW_NULL: - return TOK_EXPR_BEGIN; - default: - op = ivy_operator_get_by_token(tok->t_keyword); - return op ? TOK_EXPR_ANY : TOK_EXPR_NONE; - return TOK_EXPR_NONE; - } - default: - return TOK_EXPR_NONE; - } -} - -token_parse_function get_token_parser( - struct ivy_ast_node *context, struct ivy_token *tok) -{ - token_parse_function type_parser = NULL; - token_parse_function type_fallback_parser = NULL; - token_parse_function token_parser = NULL; - token_parse_function expr_begin_parser = NULL; - token_parse_function expr_other_parser = NULL; - token_parse_function expr_parser = NULL; - token_parse_function token_fallback_parser = NULL; - - const struct ast_node_type *type = get_ast_node_type(context->n_type); - if (!type) { - return NULL; - } - - token_parser = type->n_token_parsers[__TOK_PARSER_INDEX(tok->t_type)]; - token_fallback_parser = type->n_token_parsers[__TOK_PARSER_FALLBACK_INDEX]; - - token_parse_function better_parser = NULL; - - switch (tok->t_type) { - case IVY_TOK_KEYWORD: - type_parser - = type->n_keyword_parsers[__KW_PARSER_INDEX(tok->t_keyword)]; - if (type->n_keyword_parsers[__KW_PARSER_FALLBACK_INDEX]) { - type_fallback_parser - = type->n_keyword_parsers[__KW_PARSER_FALLBACK_INDEX]; - } - break; - case IVY_TOK_SYMBOL: - type_parser - = type->n_symbol_parsers[__SYM_PARSER_INDEX(tok->t_symbol)]; - if (type->n_symbol_parsers[__SYM_PARSER_FALLBACK_INDEX]) { - type_fallback_parser - = type->n_symbol_parsers[__SYM_PARSER_FALLBACK_INDEX]; - } - break; - default: - break; - } - - enum token_expr_type expr_type = get_token_expr_type(tok); - switch (expr_type) { - case TOK_EXPR_BEGIN: - expr_begin_parser = type->n_expr_parser.expr_begin; - expr_parser = type->n_expr_parser.expr_all; - break; - case TOK_EXPR_ANY: - expr_other_parser = type->n_expr_parser.expr_other; - expr_parser = type->n_expr_parser.expr_all; - break; - default: - break; - } - - bool token_has_sub_id - = (tok->t_type == IVY_TOK_KEYWORD || tok->t_type == IVY_TOK_SYMBOL); - - if (type_parser) - return type_parser; - if (token_parser && !token_has_sub_id) - return token_parser; - if (expr_begin_parser) - return expr_begin_parser; - if (expr_other_parser) - return expr_other_parser; - if (expr_parser) - return expr_parser; - if (type_fallback_parser) - return type_fallback_parser; - if (token_parser && token_has_sub_id) - return token_parser; - if (token_fallback_parser) - return token_fallback_parser; - return NULL; -} - struct ivy_ast_node *ivy_ast_node_create(enum ivy_ast_node_type type) { return ast_node_create(type); @@ -352,13 +219,12 @@ const char *ivy_ast_node_type_to_string(enum ivy_ast_node_type v) ENUM_STR(IVY_AST_NONE); ENUM_STR(IVY_AST_UNIT); ENUM_STR(IVY_AST_OP); + ENUM_STR(IVY_AST_DO); ENUM_STR(IVY_AST_MSG); ENUM_STR(IVY_AST_CLASS); ENUM_STR(IVY_AST_MSGH); ENUM_STR(IVY_AST_PROPERTY); ENUM_STR(IVY_AST_SELECTOR); - ENUM_STR(IVY_AST_EXPR); - ENUM_STR(IVY_AST_LAMBDA); ENUM_STR(IVY_AST_UNIT_PACKAGE); ENUM_STR(IVY_AST_UNIT_IMPORT); ENUM_STR(IVY_AST_DISCARD); @@ -379,7 +245,6 @@ const char *ivy_ast_node_type_to_string(enum ivy_ast_node_type v) ENUM_STR(IVY_AST_COND); ENUM_STR(IVY_AST_TUPLE); ENUM_STR(IVY_AST_BLOCK); - ENUM_STR(IVY_AST_PKG); ENUM_STR(IVY_AST_PKG_STATIC); ENUM_STR(IVY_AST_PKG_ITEM); ENUM_STR(IVY_AST_PKG_DYNAMIC); diff --git a/lang/ast/node.h b/lang/ast/node.h index a089967..078844a 100644 --- a/lang/ast/node.h +++ b/lang/ast/node.h @@ -5,71 +5,17 @@ #include #include -struct parser_state; - -#define PARSE_RESULT(status, flags) \ - ((struct token_parse_result) {.r_status = (status), .r_flags = (flags)}) - -#define __TOK_PARSER_INDEX(x) ((x) - __IVY_TOK_INDEX_BASE) -#define __SYM_PARSER_INDEX(x) ((x) - __IVY_SYM_INDEX_BASE) -#define __KW_PARSER_INDEX(x) ((x) - __IVY_KW_INDEX_BASE) - -#define __TOK_PARSER_FALLBACK_INDEX IVY_TOK_NONE -#define __SYM_PARSER_FALLBACK_INDEX IVY_SYM_NONE -#define __KW_PARSER_FALLBACK_INDEX IVY_KW_NONE - -#define TOK_PARSER(id, func) [__TOK_PARSER_INDEX(IVY_TOK_##id)] = func -#define SYM_PARSER(id, func) [__SYM_PARSER_INDEX(IVY_SYM_##id)] = func -#define KW_PARSER(id, func) [__KW_PARSER_INDEX(IVY_KW_##id)] = func - -#define TOK_PARSER_FALLBACK(func) [__TOK_PARSER_FALLBACK_INDEX] = func -#define SYM_PARSER_FALLBACK(func) [__SYM_PARSER_FALLBACK_INDEX] = func -#define KW_PARSER_FALLBACK(func) [__KW_PARSER_FALLBACK_INDEX] = func - -enum token_parse_flags { - PARSE_REPEAT_TOKEN = 0x01u, -}; - -enum token_expr_type { - TOK_EXPR_NONE = 0, - TOK_EXPR_BEGIN, - TOK_EXPR_ANY, -}; - -struct token_parse_result { - enum ivy_status r_status; - enum token_parse_flags r_flags; -}; - -typedef struct token_parse_result (*token_parse_function)( - struct ivy_parser *, struct ivy_token *); - struct ast_node_type { - enum ivy_status (*n_add_child)( - struct parser_state *, struct ivy_ast_node *); void (*n_to_string)(struct ivy_ast_node *, fx_string *); - void (*n_init_state)(struct ivy_parser *, struct parser_state *, uintptr_t); void (*n_collect_children)( struct ivy_ast_node *, struct ivy_ast_node_iterator *); void (*n_destroy)(struct ivy_ast_node *); size_t n_state_size; size_t n_node_size; - - token_parse_function n_token_parsers[__TOK_PARSER_INDEX(__IVY_TOK_INDEX_LIMIT)]; - token_parse_function n_keyword_parsers[__KW_PARSER_INDEX(__IVY_KW_INDEX_LIMIT)]; - token_parse_function n_symbol_parsers[__SYM_PARSER_INDEX(__IVY_SYM_INDEX_LIMIT)]; - - struct { - token_parse_function expr_begin; - token_parse_function expr_other; - token_parse_function expr_all; - } n_expr_parser; }; extern const struct ast_node_type *get_ast_node_type(enum ivy_ast_node_type type); -extern token_parse_function get_token_parser( - struct ivy_ast_node *context, struct ivy_token *tok); extern enum token_expr_type get_token_expr_type(struct ivy_token *tok); extern struct ivy_ast_node *ast_node_create(enum ivy_ast_node_type type); extern enum ivy_status ast_node_add_child( diff --git a/lang/ast/op.c b/lang/ast/op.c index 9b7505e..7e611ad 100644 --- a/lang/ast/op.c +++ b/lang/ast/op.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "iterate.h" #include "node.h" @@ -30,6 +29,5 @@ static void collect_children( struct ast_node_type op_node_ops = { .n_to_string = to_string, .n_collect_children = collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_op_node), }; diff --git a/lang/ast/package.c b/lang/ast/package.c index 4021e77..31b191b 100644 --- a/lang/ast/package.c +++ b/lang/ast/package.c @@ -1,373 +1,10 @@ #include "block.h" -#include "ctx.h" -#include "expr/expr.h" #include "iterate.h" #include "node.h" #include #include -enum package_type { - PACKAGE_NONE = 0, - /* package constructed using a list of key-value pairs. */ - PACKAGE_STATIC, - /* package constructed using an (X for X in Y if Z) pattern. */ - PACKAGE_DYNAMIC, -}; - -struct package_parser_state { - struct parser_state s_base; - enum package_type s_type; - - struct ivy_ast_node *s_prev_node; - unsigned int s_prev; - - /* only used for PACKAGE_STATIC */ - fx_queue s_items; - struct ivy_ast_node *s_next_index; - unsigned int s_next_implicit_index; - - /* only used for PACKAGE_DYNAMIC */ - struct ivy_ast_node *s_transform; - struct ivy_ast_node *s_item; - struct ivy_ast_node *s_source; - struct ivy_ast_node *s_cond; -}; - -static enum ivy_status add_package_item( - struct package_parser_state *state, struct ivy_ast_node *index, - struct ivy_ast_node *value) -{ - struct ivy_ast_pkg_static_item_node *item - = (struct ivy_ast_pkg_static_item_node *)ast_node_create( - IVY_AST_PKG_ITEM); - if (!item) { - return IVY_ERR_NO_MEMORY; - } - - item->n_value = value; - - if (index) { - item->n_index = index; - } else { - item->n_implicit_index = state->s_next_implicit_index++; - } - - fx_queue_push_back(&state->s_items, &item->n_base.n_entry); - - state->s_next_index = NULL; - state->s_prev_node = NULL; - - return IVY_OK; -} - -static struct ivy_ast_node *finalise_package(struct package_parser_state *state) -{ - struct ivy_ast_pkg_static_node *s = NULL; - struct ivy_ast_pkg_dynamic_node *d = NULL; - - switch (state->s_type) { - case PACKAGE_STATIC: - s = (struct ivy_ast_pkg_static_node *)ast_node_create( - IVY_AST_PKG_STATIC); - - if (!s) { - return NULL; - } - - s->n_items = state->s_items; - state->s_items = FX_QUEUE_INIT; - return (struct ivy_ast_node *)s; - case PACKAGE_DYNAMIC: - d = (struct ivy_ast_pkg_dynamic_node *)ast_node_create( - IVY_AST_PKG_DYNAMIC); - if (!d) { - return NULL; - } - - d->n_transform = state->s_transform; - d->n_item = state->s_item; - d->n_source = state->s_source; - d->n_cond = state->s_cond; - - state->s_transform = NULL; - state->s_item = NULL; - state->s_source = NULL; - state->s_cond = NULL; - - return (struct ivy_ast_node *)d; - default: - return NULL; - } -} - -static struct token_parse_result parse_equal_right_angle( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct package_parser_state *state - = parser_get_state(ctx, struct package_parser_state); - - if (state->s_type == PACKAGE_NONE) { - state->s_type = PACKAGE_STATIC; - } - - if (state->s_type != PACKAGE_STATIC) { - /* this token cannot be used in this context. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA) { - /* token unexpected at this time. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - /* empty index expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_EQUAL_RIGHT_ANGLE; - state->s_next_index = state->s_prev_node; - state->s_prev_node = NULL; - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_SYM_COMMA); - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_comma( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct package_parser_state *state - = parser_get_state(ctx, struct package_parser_state); - - if (state->s_type == PACKAGE_NONE) { - state->s_type = PACKAGE_STATIC; - } - - if (state->s_type != PACKAGE_STATIC) { - /* this token cannot be used in this context. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA - && state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) { - /* token unexpected at this time. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - /* empty value expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = add_package_item( - state, state->s_next_index, state->s_prev_node); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - state->s_prev = IVY_SYM_COMMA; - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_SYM_EQUAL_RIGHT_ANGLE); - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_right_brace( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct package_parser_state *state - = parser_get_state(ctx, struct package_parser_state); - - if (state->s_type == PACKAGE_NONE) { - state->s_type = PACKAGE_STATIC; - } - - enum ivy_status status = IVY_OK; - - switch (state->s_type) { - case PACKAGE_STATIC: - if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA - && state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) { - /* token unexpected at this time. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_node) { - status = add_package_item( - state, state->s_next_index, state->s_prev_node); - } - - break; - case PACKAGE_DYNAMIC: - if (!state->s_prev_node) { - /* empty expression */ - status = IVY_ERR_BAD_SYNTAX; - break; - } - - switch (state->s_prev) { - case IVY_KW_IN: - state->s_source = state->s_prev_node; - break; - case IVY_KW_IF: - state->s_cond = state->s_prev_node; - break; - default: - /* token unexpected at this time. */ - status = IVY_ERR_BAD_SYNTAX; - break; - } - break; - default: - /* not sure how we got here. */ - status = IVY_ERR_INTERNAL_FAILURE; - break; - } - - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - struct ivy_ast_node *pkg = finalise_package(state); - if (!pkg) { - return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); - } - - parser_replace_current_node(ctx, pkg); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_for( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct package_parser_state *state - = parser_get_state(ctx, struct package_parser_state); - - if (state->s_type == PACKAGE_NONE) { - state->s_type = PACKAGE_DYNAMIC; - } - - if (state->s_type != PACKAGE_DYNAMIC) { - /* this token cannot be used in this context. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_SYM_LEFT_BRACE) { - /* token unexpected at this time. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - /* empty expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_KW_FOR; - state->s_transform = state->s_prev_node; - state->s_prev_node = NULL; - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_KW_IN); - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_in( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct package_parser_state *state - = parser_get_state(ctx, struct package_parser_state); - - if (state->s_type != PACKAGE_DYNAMIC) { - /* this token cannot be used in this context. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_KW_FOR) { - /* token unexpected at this time. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - /* empty expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_KW_IN; - state->s_item = state->s_prev_node; - state->s_prev_node = NULL; - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_KW_IF); - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_if( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct package_parser_state *state - = parser_get_state(ctx, struct package_parser_state); - - if (state->s_type != PACKAGE_DYNAMIC) { - /* this token cannot be used in this context. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_KW_IN) { - /* token unexpected at this time. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - /* empty expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_KW_IF; - state->s_source = state->s_prev_node; - state->s_prev_node = NULL; - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_SYM_RIGHT_BRACE); - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct package_parser_state *state = (struct package_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} - static void pkg_static_collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { @@ -433,54 +70,18 @@ static void pkg_dynamic_collect_children( } } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct package_parser_state *state = (struct package_parser_state *)sp; - state->s_type = PACKAGE_NONE; - state->s_prev = IVY_SYM_LEFT_BRACE; - state->s_next_implicit_index = 0; - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_KW_FOR); - expr->s_subexpr_depth = 1; -} - -struct ast_node_type pkg_node_ops = { - .n_init_state = init_state, - .n_add_child = add_child, - .n_state_size = sizeof(struct package_parser_state), - /* placeholder node, will be replaced with either ivy_ast_pkg_static_node - * or ivy_ast_pkg_dynamic_node when finished. */ - .n_node_size = sizeof(struct ivy_ast_node), - .n_keyword_parsers = { - KW_PARSER(FOR, parse_for), - KW_PARSER(IN, parse_in), - KW_PARSER(IF, parse_if), - }, - .n_symbol_parsers = { - SYM_PARSER(COMMA, parse_comma), - SYM_PARSER(EQUAL_RIGHT_ANGLE, parse_equal_right_angle), - SYM_PARSER(RIGHT_BRACE, parse_right_brace), - }, -}; - struct ast_node_type pkg_static_node_ops = { .n_collect_children = pkg_static_collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_pkg_static_node), }; struct ast_node_type pkg_static_item_node_ops = { .n_to_string = pkg_static_item_to_string, .n_collect_children = pkg_static_item_collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_pkg_static_item_node), }; struct ast_node_type pkg_dynamic_node_ops = { .n_collect_children = pkg_dynamic_collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_pkg_dynamic_node), }; diff --git a/lang/ast/property.c b/lang/ast/property.c index ce5094c..b018b00 100644 --- a/lang/ast/property.c +++ b/lang/ast/property.c @@ -1,8 +1,4 @@ -#include "block.h" -#include "ctx.h" -#include "expr/expr.h" #include "iterate.h" -#include "ivy/status.h" #include "node.h" #include @@ -11,352 +7,6 @@ #define PROPERTY_TYPE(flags) (flags & (PROPERTY_FULL | PROPERTY_AUTO)) -enum property_flags { - PROPERTY_NONE = 0x00u, - /* a property defined across multiple lines using get/set => syntax */ - PROPERTY_FULL = 0x01u, - /* a property defined across a single line lines (get, set) syntax */ - PROPERTY_AUTO = 0x02u, - /* property has getter defined. */ - PROPERTY_GET = 0x04u, - /* property has setter defined. */ - PROPERTY_SET = 0x08u, -}; - -struct property_parser_state { - struct parser_state s_base; - enum property_flags s_flags; - - struct ivy_ast_node *s_prev_node; - - struct ivy_token *s_ident; - struct ivy_ast_node *s_get, *s_set; - - /* one of either 0, PROPERTY_GET, or PROPERTY_SET, depending on which - * part of the property is currently being parsed. */ - unsigned int s_cur_component; - unsigned int s_prev; -}; - -static void finalise_property(struct property_parser_state *state) -{ - struct ivy_ast_property_node *prop - = (struct ivy_ast_property_node *)state->s_base.s_node; - - if (state->s_flags & PROPERTY_GET) { - prop->n_flags |= IVY_AST_PROPERTY_GET; - } - - if (state->s_flags & PROPERTY_SET) { - prop->n_flags |= IVY_AST_PROPERTY_SET; - } - - prop->n_ident = state->s_ident; - prop->n_get = state->s_get; - prop->n_set = state->s_set; - - state->s_ident = NULL; - state->s_get = NULL; - state->s_set = NULL; -} - -static struct token_parse_result parse_ident( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (state->s_prev != IVY_SYM_DOLLAR) { - /* the only ident we're looking for is the property name, which - * can only occur after the $ symbol. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_ident = tok; - state->s_prev = IVY_TOK_IDENT; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_pipe( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (state->s_prev != IVY_TOK_IDENT) { - /* the only pipe we're looking for is the property - * name/implementation separator, which can only occur after - * the property name. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (PROPERTY_TYPE(state->s_flags) != PROPERTY_NONE) { - /* we've already determined what kind of syntax is being used - * to define this property (which is what the pipe symbol is - * for). */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_PIPE; - state->s_flags |= PROPERTY_FULL; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_left_paren( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (state->s_prev != IVY_TOK_IDENT) { - /* the only left paren we're looking for comes after the - * property name */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (PROPERTY_TYPE(state->s_flags) != PROPERTY_NONE) { - /* we've already determined what kind of syntax is being used - * to define this property (which is what this symbol is - * for). */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_LEFT_PAREN; - state->s_flags |= PROPERTY_AUTO; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_right_paren( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (PROPERTY_TYPE(state->s_flags) != PROPERTY_AUTO) { - /* can only use parenthesis in auto-properties. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_KW_GET && state->s_prev != IVY_KW_SET) { - /* the only left paren we're looking for comes after an expression */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if ((state->s_flags & (PROPERTY_GET | PROPERTY_SET)) == 0) { - /* auto-property with neither a getter nor a setter. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - finalise_property(state); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_equal_right_arrow( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (PROPERTY_TYPE(state->s_flags) != PROPERTY_FULL) { - /* this symbol cannot be used in auto-properties. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_KW_GET && state->s_prev != IVY_KW_SET) { - /* this symbol can only be used after get or set */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_EQUAL_RIGHT_ANGLE; - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_SYM_COMMA); - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_comma( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (PROPERTY_TYPE(state->s_flags) == PROPERTY_FULL - && state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) { - /* this symbol can only be used after get or set */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_cur_component != PROPERTY_GET - && state->s_cur_component != PROPERTY_SET) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_COMMA; - - if (PROPERTY_TYPE(state->s_flags) == PROPERTY_AUTO) { - state->s_cur_component = 0; - return PARSE_RESULT(IVY_OK, 0); - } - - if (!state->s_prev_node) { - /* empty getter/setter expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - switch (state->s_cur_component) { - case PROPERTY_GET: - state->s_get = state->s_prev_node; - break; - case PROPERTY_SET: - state->s_set = state->s_prev_node; - break; - default: - /* this case is handled at the start of this function. */ - break; - } - - state->s_cur_component = 0; - state->s_prev_node = NULL; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_dot( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (PROPERTY_TYPE(state->s_flags) != PROPERTY_FULL) { - /* this symbol cannot be used in auto-properties. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_cur_component != PROPERTY_GET - && state->s_cur_component != PROPERTY_SET) { - /* not actually parsing a getter or setter */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) { - /* this symbol can only be used after => and an expression */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - /* empty expression. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - switch (state->s_cur_component) { - case PROPERTY_GET: - state->s_get = state->s_prev_node; - break; - case PROPERTY_SET: - state->s_set = state->s_prev_node; - break; - default: - /* this case is handled at the start of this function. */ - break; - } - - state->s_cur_component = 0; - - finalise_property(state); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_get( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (state->s_flags & PROPERTY_GET) { - /* property already has getter defined */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (PROPERTY_TYPE(state->s_flags) == PROPERTY_FULL - && state->s_prev != IVY_SYM_PIPE && state->s_prev != IVY_SYM_COMMA) { - /* getter is not expected here. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (PROPERTY_TYPE(state->s_flags) == PROPERTY_AUTO - && state->s_prev != IVY_SYM_LEFT_PAREN - && state->s_prev != IVY_SYM_COMMA) { - /* getter is not expected here. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_flags |= PROPERTY_GET; - state->s_cur_component = PROPERTY_GET; - state->s_prev = IVY_KW_GET; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_set( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct property_parser_state *state - = parser_get_state(ctx, struct property_parser_state); - - if (state->s_flags & PROPERTY_SET) { - /* property already has setter defined */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (PROPERTY_TYPE(state->s_flags) == PROPERTY_FULL - && state->s_prev != IVY_SYM_PIPE && state->s_prev != IVY_SYM_COMMA) { - /* setter is not expected here. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (PROPERTY_TYPE(state->s_flags) == PROPERTY_AUTO - && state->s_prev != IVY_SYM_LEFT_PAREN - && state->s_prev != IVY_SYM_COMMA) { - /* setter is not expected here. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_flags |= PROPERTY_SET; - state->s_cur_component = PROPERTY_SET; - state->s_prev = IVY_KW_SET; - - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct property_parser_state *state - = (struct property_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct property_parser_state *state = (struct property_parser_state *)sp; - state->s_flags = PROPERTY_NONE; - state->s_prev = IVY_SYM_DOLLAR; -} - static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { @@ -397,24 +47,6 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) struct ast_node_type property_node_ops = { .n_to_string = to_string, - .n_add_child = add_child, - .n_init_state = init_state, .n_collect_children = collect_children, - .n_state_size = sizeof(struct property_parser_state), .n_node_size = sizeof(struct ivy_ast_property_node), - .n_token_parsers = { - TOK_PARSER(IDENT, parse_ident), - }, - .n_keyword_parsers = { - KW_PARSER(GET, parse_get), - KW_PARSER(SET, parse_set), - }, - .n_symbol_parsers = { - SYM_PARSER(PIPE, parse_pipe), - SYM_PARSER(EQUAL_RIGHT_ANGLE, parse_equal_right_arrow), - SYM_PARSER(COMMA, parse_comma), - SYM_PARSER(DOT, parse_dot), - SYM_PARSER(LEFT_PAREN, parse_left_paren), - SYM_PARSER(RIGHT_PAREN, parse_right_paren), - }, }; diff --git a/lang/ast/return.c b/lang/ast/return.c index c20f7d1..0f66b0d 100644 --- a/lang/ast/return.c +++ b/lang/ast/return.c @@ -1,4 +1,3 @@ -#include "ctx.h" #include "iterate.h" #include "node.h" @@ -14,6 +13,5 @@ static void collect_children( struct ast_node_type return_node_ops = { .n_collect_children = collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_return_node), }; diff --git a/lang/ast/selector.c b/lang/ast/selector.c index e71fdc8..0b11316 100644 --- a/lang/ast/selector.c +++ b/lang/ast/selector.c @@ -1,228 +1,9 @@ -#include "ctx.h" -#include "ivy/status.h" #include "node.h" #include #include #include -struct selector_parser_state { - struct parser_state s_base; - unsigned int s_prev; - bool s_complete; -}; - -#define CHECK_SELECTOR_COMPLETE() \ - do { \ - if (state->s_complete) { \ - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); \ - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); \ - } \ - } while (0) - -static struct token_parse_result parse_plus( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - if (sel->n_recipient != IVY_SELECTOR_RECIPIENT_NONE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - sel->n_recipient = IVY_SELECTOR_RECIPIENT_CLASS; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_hyphen( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - if (sel->n_recipient != IVY_SELECTOR_RECIPIENT_NONE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - sel->n_recipient = IVY_SELECTOR_RECIPIENT_OBJECT; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_ident( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - CHECK_SELECTOR_COMPLETE(); - - if (state->s_prev == 0) { - /* message name */ - sel->n_msg_name = tok; - state->s_prev = IVY_TOK_IDENT; - state->s_complete = true; - return PARSE_RESULT(IVY_OK, 0); - } - - if (state->s_prev == IVY_TOK_LABEL) { - /* internal parameter name */ - fx_queue_push_back(&sel->n_arg_names, &tok->t_entry); - state->s_prev = IVY_TOK_IDENT; - state->s_complete = true; - return PARSE_RESULT(IVY_OK, 0); - } - - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); -} - -static struct token_parse_result parse_label( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - if (sel->n_recipient == IVY_SELECTOR_RECIPIENT_NONE - && state->s_prev != IVY_TOK_IDENT - && state->s_prev != IVY_SYM_LEFT_PAREN) { - /* if recipient is not NONE, this selector appears at the beginning of a message - * handler. only then is a label without a preceding identifier allowed. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - fx_queue_push_back(&sel->n_arg_labels, &tok->t_entry); - state->s_prev = IVY_TOK_LABEL; - state->s_complete = false; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_linefeed( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - CHECK_SELECTOR_COMPLETE(); - - if (!fx_queue_empty(&sel->n_arg_labels) - && state->s_prev != IVY_SYM_RIGHT_PAREN) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev != IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - state->s_prev = IVY_TOK_LINEFEED; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_left_paren( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - if (state->s_prev != IVY_TOK_IDENT || !fx_queue_empty(&sel->n_arg_labels)) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_LEFT_PAREN; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_right_paren( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - if (state->s_prev != IVY_TOK_IDENT || fx_queue_empty(&sel->n_arg_labels)) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev = IVY_SYM_RIGHT_PAREN; - state->s_complete = true; - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_pipe( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - switch (state->s_prev) { - case IVY_SYM_RIGHT_PAREN: - /* this looks like a complex message selector */ - if (fx_queue_empty(&sel->n_arg_labels) - || fx_queue_empty(&sel->n_arg_names)) { - /* no message args */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!sel->n_msg_name) { - /* no message name */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - break; - case IVY_TOK_IDENT: - /* this looks like a unary or keyword message. */ - if (!fx_queue_empty(&sel->n_arg_labels) - && fx_queue_empty(&sel->n_arg_names)) { - /* keyword message with no arg names. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - break; - default: - /* not sure what we're parsing. unknown token at end of selector. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static struct token_parse_result parse_other( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct selector_parser_state *state - = parser_get_state(ctx, struct selector_parser_state); - - struct ivy_ast_selector_node *sel - = (struct ivy_ast_selector_node *)state->s_base.s_node; - - CHECK_SELECTOR_COMPLETE(); - - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); -} - static void to_string(struct ivy_ast_node *node, fx_string *str) { struct ivy_ast_selector_node *sel = (struct ivy_ast_selector_node *)node; @@ -291,28 +72,7 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) fx_string_append_cstr(str, "]"); } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct selector_parser_state *state = (struct selector_parser_state *)sp; - state->s_prev = 0; - state->s_complete = false; -} - struct ast_node_type selector_node_ops = { - .n_init_state = init_state, .n_to_string = to_string, - .n_state_size = sizeof(struct selector_parser_state), - .n_node_size = sizeof(struct ivy_ast_selector_node), - .n_token_parsers = { - TOK_PARSER(IDENT, parse_ident), - TOK_PARSER(LABEL, parse_label), - TOK_PARSER_FALLBACK(parse_other), - }, - .n_symbol_parsers = { - SYM_PARSER(PLUS, parse_plus), - SYM_PARSER(HYPHEN, parse_hyphen), - SYM_PARSER(LEFT_PAREN, parse_left_paren), - SYM_PARSER(RIGHT_PAREN, parse_right_paren), - SYM_PARSER(PIPE, parse_pipe), - }, + .n_node_size = sizeof(struct ivy_ast_selector_node), }; diff --git a/lang/ast/string.c b/lang/ast/string.c index b990758..483e811 100644 --- a/lang/ast/string.c +++ b/lang/ast/string.c @@ -1,5 +1,3 @@ -#include "ctx.h" -#include "expr/expr.h" #include "iterate.h" #include "node.h" @@ -13,57 +11,6 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) s->n_value->t_str); } -struct token_parse_result parse_string(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct parser_state *state = parser_get_state_generic(ctx); - struct ivy_ast_fstring_node *parent - = (struct ivy_ast_fstring_node *)state->s_node; - struct ivy_ast_string_node *child - = (struct ivy_ast_string_node *)ast_node_create(IVY_AST_STRING); - - if (!child) { - return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0); - } - - child->n_value = tok; - fx_queue_push_back(&parent->n_value, &child->n_base.n_entry); - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result parse_left_brace( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_SYM_RIGHT_BRACE); - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result parse_right_brace( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result parse_str_end( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct ivy_ast_fstring_node *str - = (struct ivy_ast_fstring_node *)parent->s_node; - - fx_queue_push_back(&str->n_value, &child->n_entry); - - return IVY_OK; -} - static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { @@ -79,21 +26,10 @@ static void collect_children( struct ast_node_type string_node_ops = { .n_to_string = to_string, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_string_node), }; struct ast_node_type fstring_node_ops = { - .n_add_child = add_child, .n_collect_children = collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_fstring_node), - .n_token_parsers = { - TOK_PARSER(STRING, parse_string), - TOK_PARSER(STR_END, parse_str_end), - }, - .n_symbol_parsers = { - SYM_PARSER(LEFT_BRACE, parse_left_brace), - SYM_PARSER(RIGHT_BRACE, parse_right_brace), - }, }; diff --git a/lang/ast/try.c b/lang/ast/try.c index d4ada82..4f547b7 100644 --- a/lang/ast/try.c +++ b/lang/ast/try.c @@ -1,233 +1,5 @@ -#include "block.h" -#include "expr/expr.h" #include "iterate.h" - -struct try_parser_state { - struct parser_state s_base; - unsigned int s_prev_token; - - struct ivy_ast_node *s_prev_node; - - struct ivy_ast_block_node *s_try, *s_finally; - - fx_queue s_catch_branches; - struct ivy_ast_try_catch_node *s_cur_catch_branch; -}; - -static enum ivy_status flush_catch_branch(struct try_parser_state *state) -{ - fx_queue_push_back( - &state->s_catch_branches, - &state->s_cur_catch_branch->n_base.n_entry); - - state->s_cur_catch_branch - = (struct ivy_ast_try_catch_node *)ast_node_create( - IVY_AST_TRY_CATCH); - - if (!state->s_cur_catch_branch) { - return IVY_ERR_NO_MEMORY; - } - - return IVY_OK; -} - -static enum ivy_status finalise_try(struct try_parser_state *state) -{ - struct ivy_ast_try_node *try - = (struct ivy_ast_try_node *)state->s_base.s_node; - try->n_try = (struct ivy_ast_node *)state->s_try; - try->n_finally = (struct ivy_ast_node *)state->s_finally; - try->n_catch = state->s_catch_branches; - - state->s_try = NULL; - state->s_finally = NULL; - state->s_catch_branches = FX_QUEUE_INIT; - - return IVY_OK; -} - -struct token_parse_result parse_catch(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct try_parser_state *try - = parser_get_state(ctx, struct try_parser_state); - - if (!try->s_prev_node || try->s_prev_node->n_type != IVY_AST_BLOCK) { - /* there must always be a block between a catch and the keyword - * that came before it */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = IVY_OK; - - if (try->s_prev_token == IVY_KW_TRY) { - try->s_try = (struct ivy_ast_block_node *)try->s_prev_node; - try->s_prev_node = NULL; - } else if (try->s_prev_token == IVY_KW_IN) { - try->s_cur_catch_branch->n_block = try->s_prev_node; - try->s_prev_node = NULL; - - status = flush_catch_branch(try); - - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - } else { - /* catch can only come after `try` or `in` */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - /* next input should be the catch pattern */ - struct expr_parser_state *pattern - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - expr_add_terminator(pattern, IVY_KW_IN); - - try->s_prev_token = IVY_KW_CATCH; - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_in( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct try_parser_state *try - = parser_get_state(ctx, struct try_parser_state); - - if (try->s_prev_token != IVY_KW_CATCH) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!try->s_prev_node) { - /* there must always be an expression between catch and in */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - try->s_cur_catch_branch->n_pattern = try->s_prev_node; - try->s_prev_node = NULL; - try->s_prev_token = IVY_KW_IN; - - struct block_parser_state *block - = (struct block_parser_state *)parser_push_state( - ctx, IVY_AST_BLOCK, 0); - block_add_terminator(block, IVY_KW_CATCH); - block_add_terminator(block, IVY_KW_FINALLY); - block_add_terminator(block, IVY_KW_END); - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result parse_finally( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct try_parser_state *try - = parser_get_state(ctx, struct try_parser_state); - - if (try->s_prev_token != IVY_KW_IN && try->s_prev_token != IVY_KW_TRY) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!try->s_prev_node || try->s_prev_node->n_type != IVY_AST_BLOCK) { - /* there must always be a block between a catch and the keyword - * that came before it */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = IVY_OK; - - if (try->s_prev_token == IVY_KW_TRY) { - try->s_try = (struct ivy_ast_block_node *)try->s_prev_node; - try->s_prev_node = NULL; - } else if (try->s_prev_token == IVY_KW_IN) { - try->s_cur_catch_branch->n_block = try->s_prev_node; - try->s_prev_node = NULL; - - status = flush_catch_branch(try); - - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - } else { - /* finally can only come after `try` or `in` */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - try->s_prev_token = IVY_KW_FINALLY; - - 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, 0); -} - -struct token_parse_result parse_end(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct try_parser_state *try - = parser_get_state(ctx, struct try_parser_state); - - if (!try->s_prev_node || try->s_prev_node->n_type != IVY_AST_BLOCK) { - /* there must always be a block between an end and the keyword - * that came before it */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = IVY_OK; - - if (try->s_prev_token == IVY_KW_TRY) { - try->s_try = (struct ivy_ast_block_node *)try->s_prev_node; - try->s_prev_node = NULL; - } else if (try->s_prev_token == IVY_KW_FINALLY) { - try->s_finally = (struct ivy_ast_block_node *)try->s_prev_node; - try->s_prev_node = NULL; - } else if (try->s_prev_token == IVY_KW_IN) { - try->s_cur_catch_branch->n_block = try->s_prev_node; - status = flush_catch_branch(try); - - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - } else { - /* catch can only come after `try`, `in`, or `finally` */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - finalise_try(try); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - - return PARSE_RESULT(IVY_OK, 0); -} - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct try_parser_state *state = (struct try_parser_state *)sp; - state->s_prev_token = IVY_KW_TRY; - - state->s_cur_catch_branch - = (struct ivy_ast_try_catch_node *)ast_node_create( - IVY_AST_TRY_CATCH); - - struct block_parser_state *block - = (struct block_parser_state *)parser_push_state( - ctx, IVY_AST_BLOCK, 0); - block_add_terminator(block, IVY_KW_CATCH); - block_add_terminator(block, IVY_KW_FINALLY); - block_add_terminator(block, IVY_KW_END); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct try_parser_state *state = (struct try_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} +#include "node.h" static void try_collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) @@ -260,21 +32,11 @@ static void try_catch_collect_children( } struct ast_node_type try_node_ops = { - .n_init_state = init_state, - .n_add_child = add_child, .n_collect_children = try_collect_children, - .n_state_size = sizeof(struct try_parser_state), .n_node_size = sizeof(struct ivy_ast_try_node), - .n_keyword_parsers = { - KW_PARSER(CATCH, parse_catch), - KW_PARSER(IN, parse_in), - KW_PARSER(FINALLY, parse_finally), - KW_PARSER(END, parse_end), - }, }; struct ast_node_type try_catch_node_ops = { - .n_state_size = sizeof(struct parser_state), - .n_node_size = sizeof(struct ivy_ast_try_catch_node), .n_collect_children = try_catch_collect_children, + .n_node_size = sizeof(struct ivy_ast_try_catch_node), }; diff --git a/lang/ast/tuple.c b/lang/ast/tuple.c index c59facb..b6ed426 100644 --- a/lang/ast/tuple.c +++ b/lang/ast/tuple.c @@ -1,5 +1,3 @@ -#include "ctx.h" -#include "expr/expr.h" #include "iterate.h" #include "ivy/status.h" #include "node.h" @@ -8,110 +6,6 @@ #include #include -struct tuple_parser_state { - struct parser_state s_base; - - struct ivy_ast_node *s_prev_node; - unsigned int s_prev; - - fx_queue s_items; -}; - -static void finalise_tuple(struct tuple_parser_state *state) -{ - struct ivy_ast_tuple_node *tuple - = (struct ivy_ast_tuple_node *)state->s_base.s_node; - - tuple->n_members = state->s_items; - state->s_items = FX_QUEUE_INIT; -} - -struct token_parse_result parse_comma(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct tuple_parser_state *state - = parser_get_state(ctx, struct tuple_parser_state); - if (state->s_prev != IVY_SYM_LEFT_PAREN && state->s_prev != IVY_SYM_COMMA) { - /* token not expected at this time. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - /* empty tuple member */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - fx_queue_push_back(&state->s_items, &state->s_prev_node->n_entry); - state->s_prev_node = NULL; - state->s_prev = IVY_SYM_COMMA; - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_SYM_COMMA); - expr_add_terminator(expr, IVY_SYM_RIGHT_PAREN); - expr->s_subexpr_depth = 1; - - return PARSE_RESULT(IVY_OK, 0); -} - -struct token_parse_result parse_right_paren( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct tuple_parser_state *state - = parser_get_state(ctx, struct tuple_parser_state); - if (state->s_prev != IVY_SYM_COMMA) { - /* token not expected at this time. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (!state->s_prev_node) { - /* empty tuple member */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - fx_queue_push_back(&state->s_items, &state->s_prev_node->n_entry); - state->s_prev_node = NULL; - state->s_prev = IVY_SYM_RIGHT_PAREN; - - finalise_tuple(state); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct tuple_parser_state *state = (struct tuple_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct tuple_parser_state *state = (struct tuple_parser_state *)sp; - state->s_prev = IVY_SYM_LEFT_PAREN; - - if (arg) { - /* arg is the first node in the tuple */ - struct ivy_ast_node *item = (struct ivy_ast_node *)arg; - fx_queue_push_back(&state->s_items, &item->n_entry); - state->s_prev = IVY_SYM_COMMA; - } - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - expr_add_terminator(expr, IVY_SYM_COMMA); - expr_add_terminator(expr, IVY_SYM_RIGHT_PAREN); - expr->s_subexpr_depth = 1; -} - static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { @@ -127,13 +21,6 @@ static void collect_children( } struct ast_node_type tuple_node_ops = { - .n_add_child = add_child, - .n_init_state = init_state, .n_collect_children = collect_children, - .n_state_size = sizeof(struct tuple_parser_state), .n_node_size = sizeof(struct ivy_ast_tuple_node), - .n_symbol_parsers = { - SYM_PARSER(COMMA, parse_comma), - SYM_PARSER(RIGHT_PAREN, parse_right_paren), - }, }; diff --git a/lang/ast/unit-import.c b/lang/ast/unit-import.c index f9d45df..f2a214d 100644 --- a/lang/ast/unit-import.c +++ b/lang/ast/unit-import.c @@ -1,62 +1,9 @@ -#include "ctx.h" #include "node.h" #include #include #include -struct unit_import_parser_state { - struct parser_state s_base; - int s_prev_token; -}; - -static struct token_parse_result parse_dot( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct unit_import_parser_state *state - = parser_get_state(ctx, struct unit_import_parser_state); - - if (state->s_prev_token != IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev_token = IVY_SYM_DOT; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_ident( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct unit_import_parser_state *state - = parser_get_state(ctx, struct unit_import_parser_state); - - struct ivy_ast_unit_import_node *node - = (struct ivy_ast_unit_import_node *)(state->s_base.s_node); - - if (state->s_prev_token == IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - fx_queue_push_back(&node->n_ident, &tok->t_entry); - - state->s_prev_token = IVY_TOK_IDENT; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_linefeed( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct unit_import_parser_state *state - = parser_get_state(ctx, struct unit_import_parser_state); - - if (state->s_prev_token != IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - static void to_string(struct ivy_ast_node *node, fx_string *str) { struct ivy_ast_unit_import_node *unit_import @@ -84,24 +31,7 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) fx_string_append_cstr(str, ")"); } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct unit_import_parser_state *state - = (struct unit_import_parser_state *)sp; - state->s_prev_token = IVY_KW_PACKAGE; -} - struct ast_node_type unit_import_node_ops = { .n_to_string = to_string, - .n_init_state = init_state, - .n_state_size = sizeof(struct unit_import_parser_state), .n_node_size = sizeof(struct ivy_ast_unit_import_node), - .n_symbol_parsers = { - SYM_PARSER(DOT, parse_dot), - }, - .n_token_parsers = { - TOK_PARSER(IDENT, parse_ident), - TOK_PARSER(LINEFEED, parse_linefeed), - } - }; diff --git a/lang/ast/unit-package.c b/lang/ast/unit-package.c index 8561666..5f69e3f 100644 --- a/lang/ast/unit-package.c +++ b/lang/ast/unit-package.c @@ -1,62 +1,9 @@ -#include "ctx.h" #include "node.h" #include #include #include -struct unit_package_parser_state { - struct parser_state s_base; - int s_prev_token; -}; - -static struct token_parse_result parse_dot( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct unit_package_parser_state *state - = parser_get_state(ctx, struct unit_package_parser_state); - - if (state->s_prev_token != IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_prev_token = IVY_SYM_DOT; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_ident( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct unit_package_parser_state *state - = parser_get_state(ctx, struct unit_package_parser_state); - - struct ivy_ast_unit_package_node *node - = (struct ivy_ast_unit_package_node *)(state->s_base.s_node); - - if (state->s_prev_token == IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - fx_queue_push_back(&node->n_ident, &tok->t_entry); - - state->s_prev_token = IVY_TOK_IDENT; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_linefeed( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct unit_package_parser_state *state - = parser_get_state(ctx, struct unit_package_parser_state); - - if (state->s_prev_token != IVY_TOK_IDENT) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - static void to_string(struct ivy_ast_node *node, fx_string *str) { struct ivy_ast_unit_package_node *unit_package @@ -83,24 +30,7 @@ static void to_string(struct ivy_ast_node *node, fx_string *str) fx_string_append_cstr(str, ")"); } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct unit_package_parser_state *state - = (struct unit_package_parser_state *)sp; - state->s_prev_token = IVY_KW_PACKAGE; -} - struct ast_node_type unit_package_node_ops = { .n_to_string = to_string, - .n_init_state = init_state, - .n_state_size = sizeof(struct unit_package_parser_state), .n_node_size = sizeof(struct ivy_ast_unit_package_node), - .n_symbol_parsers = { - SYM_PARSER(DOT, parse_dot), - }, - .n_token_parsers = { - TOK_PARSER(IDENT, parse_ident), - TOK_PARSER(LINEFEED, parse_linefeed), - } - }; diff --git a/lang/ast/unit.c b/lang/ast/unit.c index 02b5892..471a44b 100644 --- a/lang/ast/unit.c +++ b/lang/ast/unit.c @@ -1,59 +1,8 @@ -#include "ctx.h" -#include "expr/expr.h" #include "iterate.h" #include "node.h" #include -static struct token_parse_result parse_package_keyword( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - parser_push_state(ctx, IVY_AST_UNIT_PACKAGE, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_use_keyword( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - parser_push_state(ctx, IVY_AST_UNIT_IMPORT, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_global_keyword( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - parser_push_state(ctx, IVY_AST_GLOBAL, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_class_keyword( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - parser_push_state(ctx, IVY_AST_CLASS, 0); - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_expr_begin( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - parser_push_state(ctx, IVY_AST_EXPR, 0); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static struct token_parse_result parse_dot( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct ivy_ast_unit_node *unit = (struct ivy_ast_unit_node *)parent->s_node; - fx_queue_push_back(&unit->n_children, &child->n_entry); - return IVY_OK; -} - static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) { @@ -68,20 +17,6 @@ static void collect_children( } struct ast_node_type unit_node_ops = { - .n_add_child = add_child, .n_collect_children = collect_children, - .n_state_size = sizeof(struct parser_state), .n_node_size = sizeof(struct ivy_ast_unit_node), - .n_keyword_parsers = { - KW_PARSER(PACKAGE, parse_package_keyword), - KW_PARSER(CLASS, parse_class_keyword), - KW_PARSER(USE, parse_use_keyword), - KW_PARSER(GLOBAL, parse_global_keyword), - }, - .n_symbol_parsers = { - SYM_PARSER(DOT, parse_dot), - }, - .n_expr_parser = { - .expr_begin = parse_expr_begin, - }, }; diff --git a/lang/ast/while.c b/lang/ast/while.c index 686353e..9c6eaf9 100644 --- a/lang/ast/while.c +++ b/lang/ast/while.c @@ -1,184 +1,7 @@ -#include "block.h" -#include "expr/expr.h" #include "iterate.h" +#include "node.h" -struct while_parser_state { - struct parser_state s_base; - bool s_inline; - unsigned int s_prev_token; - - struct ivy_ast_node *s_body, *s_cond; - - struct ivy_ast_node *s_prev_node; -}; - -static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg) -{ - struct while_parser_state *state = (struct while_parser_state *)sp; - state->s_prev_node = (struct ivy_ast_node *)arg; -} - -struct token_parse_result parse_while(struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct while_parser_state *state - = parser_get_state(ctx, struct while_parser_state); - - if (state->s_prev_node) { - /* this is an inline while-loop */ - state->s_inline = true; - state->s_body = state->s_prev_node; - state->s_prev_node = NULL; - } else { - state->s_inline = false; - } - - struct expr_parser_state *expr - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR, 0); - - state->s_prev_token = IVY_KW_WHILE; - expr->s_subexpr_depth = 1; - expr_add_terminator(expr, IVY_KW_DO); - - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_do( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct while_parser_state *state - = parser_get_state(ctx, struct while_parser_state); - - if (state->s_inline) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - if (state->s_prev_token != IVY_KW_WHILE) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - /* previous component was the while-condition. */ - if (!state->s_prev_node) { - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - state->s_cond = state->s_prev_node; - state->s_prev_node = NULL; - - /* next component will be a block. */ - struct block_parser_state *block - = (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_add_terminator(block, IVY_KW_END); - - state->s_prev_token = IVY_KW_DO; - return PARSE_RESULT(IVY_OK, 0); -} - -static struct token_parse_result parse_expr_begin( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct while_parser_state *state - = parser_get_state(ctx, struct while_parser_state); - - if (state->s_prev_token != IVY_KW_DO) { - /* 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_add_terminator(block, IVY_KW_END); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static enum ivy_status finalise_while_loop(struct while_parser_state *state) -{ - struct ivy_ast_while_loop_node *loop - = (struct ivy_ast_while_loop_node *)state->s_base.s_node; - - if (state->s_inline) { - /* we have just reached the end of either the while condition. */ - if (!state->s_prev_node) { - /* while condition is empty. */ - return IVY_ERR_BAD_SYNTAX; - } - - /* the condition and body are parsed in reverse order for inline loops. */ - loop->n_cond = state->s_prev_node; - loop->n_body = state->s_body; - state->s_prev_node = NULL; - return IVY_OK; - } - - if (!state->s_prev_node) { - /* while body is empty. */ - return IVY_ERR_BAD_SYNTAX; - } - - loop->n_cond = state->s_cond; - loop->n_body = state->s_prev_node; - - state->s_cond = NULL; - state->s_prev_node = NULL; - - return IVY_OK; -} - -static struct token_parse_result parse_punct_terminator( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct while_parser_state *state - = parser_get_state(ctx, struct while_parser_state); - - if (!state->s_inline) { - /* only inline while loop can be ended with punctuation. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = finalise_while_loop(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); -} - -static struct token_parse_result parse_end( - struct ivy_parser *ctx, struct ivy_token *tok) -{ - struct while_parser_state *state - = parser_get_state(ctx, struct while_parser_state); - - if (state->s_inline) { - /* inline while loop must be terminated with punctuation. */ - return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); - } - - enum ivy_status status = finalise_while_loop(state); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); -} - -static enum ivy_status add_child( - struct parser_state *parent, struct ivy_ast_node *child) -{ - struct while_parser_state *state = (struct while_parser_state *)parent; - - if (state->s_prev_node) { - return IVY_ERR_BAD_SYNTAX; - } - - state->s_prev_node = child; - return IVY_OK; -} +#include static void collect_children( struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) @@ -196,23 +19,6 @@ static void collect_children( } struct ast_node_type while_loop_node_ops = { - .n_init_state = init_state, - .n_add_child = add_child, .n_collect_children = collect_children, - .n_state_size = sizeof(struct while_parser_state), .n_node_size = sizeof(struct ivy_ast_while_loop_node), - .n_keyword_parsers = { - KW_PARSER(WHILE, parse_while), - KW_PARSER(DO, parse_do), - KW_PARSER(END, parse_end), - }, - .n_symbol_parsers = { - SYM_PARSER(DOT, parse_punct_terminator), - SYM_PARSER(COMMA, parse_punct_terminator), - SYM_PARSER(RIGHT_PAREN, parse_punct_terminator), - SYM_PARSER(BANG, parse_punct_terminator), - }, - .n_expr_parser = { - .expr_begin = parse_expr_begin, - }, }; diff --git a/lang/codegen/codegen.c b/lang/codegen/codegen.c index ec101f4..ec55492 100644 --- a/lang/codegen/codegen.c +++ b/lang/codegen/codegen.c @@ -352,7 +352,6 @@ static bool node_is_expr(struct ivy_ast_node *node) switch (node->n_type) { case IVY_AST_OP: case IVY_AST_MSG: - case IVY_AST_LAMBDA: case IVY_AST_DISCARD: case IVY_AST_INT: case IVY_AST_DOUBLE: diff --git a/lang/codegen/expr.c b/lang/codegen/expr.c index 306bb96..d2b4048 100644 --- a/lang/codegen/expr.c +++ b/lang/codegen/expr.c @@ -744,7 +744,6 @@ struct code_generator expr_generator = { NODE_CODEGEN(INT, gen_int), NODE_CODEGEN(OP, gen_op), NODE_CODEGEN(MSG, gen_msg), - NODE_CODEGEN(LAMBDA, gen_lambda), NODE_CODEGEN(STRING, gen_string), NODE_CODEGEN(FSTRING, gen_fstring), NODE_CODEGEN(IDENT, gen_var_reference), diff --git a/lang/codegen/generator.c b/lang/codegen/generator.c index c561823..36ef139 100644 --- a/lang/codegen/generator.c +++ b/lang/codegen/generator.c @@ -8,7 +8,6 @@ extern const struct code_generator expr_generator; extern const struct code_generator global_generator; extern const struct code_generator msg_generator; extern const struct code_generator fstring_generator; -extern const struct code_generator lambda_generator; extern const struct code_generator return_generator; extern const struct code_generator cond_generator; extern const struct code_generator cond_group_generator; @@ -23,7 +22,6 @@ static const struct code_generator *code_generators[] = { [CODE_GENERATOR_GLOBAL] = &global_generator, [CODE_GENERATOR_MSG] = &msg_generator, [CODE_GENERATOR_FSTRING] = &fstring_generator, - [CODE_GENERATOR_LAMBDA] = &lambda_generator, [CODE_GENERATOR_RETURN] = &return_generator, [CODE_GENERATOR_COND] = &cond_generator, [CODE_GENERATOR_COND_GROUP] = &cond_group_generator, diff --git a/lang/codegen/lambda.c b/lang/codegen/lambda.c deleted file mode 100644 index 244b470..0000000 --- a/lang/codegen/lambda.c +++ /dev/null @@ -1,275 +0,0 @@ -#include "codegen.h" - -#include -#include -#include -#include - -enum lambda_part { - LAMBDA_NONE, - LAMBDA_START, - LAMBDA_ARG, - LAMBDA_BLOCK, -}; - -struct lambda_codegen_state { - struct code_generator_state s_base; - enum lambda_part s_prev_part; - struct mie_func *s_func; - struct mie_value *s_ctx_internal; - struct mie_value *s_ctx_external; - struct mie_block *s_outer_block; - struct codegen_var_map s_args; - struct codegen_var_map s_captured_vars; -}; - -static enum ivy_status switch_to_lambda_func( - struct ivy_codegen *gen, struct lambda_codegen_state *lambda) -{ -#if 0 - if (!lambda->s_outer_block) { - lambda->s_outer_block - = mie_builder_get_current_block(gen->c_builder); - } - - struct mie_block *block = mie_func_get_last_block(lambda->s_func); - if (!block) { - block = mie_func_create_block(lambda->s_func, "entry"); - mie_func_insert_block(lambda->s_func, block, NULL); - } - - if (mie_block_is_terminated(block)) { - block = mie_func_create_block(lambda->s_func, NULL); - mie_func_insert_block(lambda->s_func, block, NULL); - } - - mie_builder_set_insert_point(gen->c_builder, block); - - return IVY_OK; -#endif - return IVY_ERR_NOT_SUPPORTED; -} - -static enum ivy_status switch_to_outer_block( - struct ivy_codegen *gen, struct lambda_codegen_state *lambda) -{ -#if 0 - mie_builder_set_insert_point(gen->c_builder, lambda->s_outer_block); - return IVY_OK; -#endif - return IVY_ERR_NOT_SUPPORTED; -} - -static struct code_generator_result gen_lambda( - struct ivy_codegen *gen, struct code_generator_state *state, - struct ivy_ast_node *node, size_t depth) -{ - struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; -#if 0 - if (lambda->s_prev_part != LAMBDA_NONE) { - return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); - } - - struct mie_type *id = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID); - struct mie_type *func_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_FUNC); - - lambda->s_prev_part = LAMBDA_START; - lambda->s_func = mie_func_create(MIE_FUNC_STATIC, id); - lambda->s_ctx_internal = mie_func_add_arg(lambda->s_func, id, "ctx"); - - struct mie_value *lambda_class - = mie_builder_get_data_ptr(gen->c_builder, "Lambda"); - struct mie_value *sel = mie_ctx_get_selector(gen->c_ctx, "_M3new4funcE"); - struct mie_value *func_value = mie_builder_load( - gen->c_builder, func_type, MIE_VALUE(lambda->s_func), NULL); - struct mie_value *args[] = { - func_value, - }; - - lambda->s_ctx_external = mie_builder_msg( - gen->c_builder, id, lambda_class, sel, args, - sizeof args / sizeof args[0], 0, NULL); - - switch_to_lambda_func(gen, lambda); - - return CODEGEN_RESULT_OK(0); -#endif - return CODEGEN_RESULT_ERR(IVY_ERR_NOT_SUPPORTED); -} - -static struct code_generator_result gen_ident( - struct ivy_codegen *gen, struct code_generator_state *state, - struct ivy_ast_node *node, size_t depth) -{ - struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; -#if 0 - if (lambda->s_prev_part != LAMBDA_START - && lambda->s_prev_part != LAMBDA_ARG) { - return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); - } - - lambda->s_prev_part = LAMBDA_ARG; - - struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node; - const char *arg_name = ident->n_content->t_str; - struct mie_type *id = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID); - struct mie_value *arg = mie_func_add_arg(lambda->s_func, id, arg_name); - - struct codegen_var arg_var = { - .v_node = node, - .v_type = id, - .v_value = arg, - }; - - codegen_var_map_put(&lambda->s_args, arg_name, &arg_var); - - return CODEGEN_RESULT_OK(0); -#endif - return CODEGEN_RESULT_ERR(IVY_ERR_NOT_SUPPORTED); -} - -static struct code_generator_result gen_block( - struct ivy_codegen *gen, struct code_generator_state *state, - struct ivy_ast_node *node, size_t depth) -{ - struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; - if (lambda->s_prev_part != LAMBDA_START - && lambda->s_prev_part != LAMBDA_ARG) { - return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX); - } - - codegen_push_generator(gen, CODE_GENERATOR_BLOCK, 0, NULL); - - return CODEGEN_RESULT_OK(0); -} - -static enum ivy_status state_init( - struct ivy_codegen *gen, struct code_generator_state *state, - uintptr_t argv, void *argp) -{ - struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; - codegen_var_map_init(&lambda->s_args); - codegen_var_map_init(&lambda->s_captured_vars); - lambda->s_prev_part = LAMBDA_NONE; - return IVY_OK; -} - -static enum ivy_status state_fini( - struct ivy_codegen *gen, struct code_generator_state *state, - struct code_generator_value *result) -{ - struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; - -#if 0 - switch_to_outer_block(gen, lambda); - mie_module_add_function(gen->c_module, lambda->s_func, ".anon"); - result->v_type = CODE_GENERATOR_VALUE_MIE_VALUE; - result->v_value.mie_value = MIE_VALUE(lambda->s_ctx_external); - - codegen_var_map_fini(&lambda->s_args); - codegen_var_map_fini(&lambda->s_captured_vars); - - return IVY_OK; -#endif - return IVY_ERR_NOT_SUPPORTED; -} - -static enum ivy_status resolve_var( - struct ivy_codegen *gen, struct code_generator_state *state, - const char *ident, struct codegen_var *var) -{ - struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; - struct codegen_var *result = NULL; - enum ivy_status status - = codegen_var_map_get(&lambda->s_args, ident, &result); - - if (status == IVY_OK) { - memcpy(var, result, sizeof *var); - return status; - } - - status = codegen_var_map_get(&lambda->s_captured_vars, ident, &result); - - if (status == IVY_OK) { - memcpy(var, result, sizeof *var); - return status; - } - - return IVY_ERR_NO_ENTRY; -} - -static enum ivy_status capture_var( - struct ivy_codegen *gen, struct code_generator_state *state, - const char *ident, struct codegen_var *var) -{ - struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state; - -#if 0 - struct mie_type *str_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_STR); - struct mie_type *void_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_VOID); - struct mie_value *ident_ptr - = mie_builder_get_string_ptr(gen->c_builder, ident); - - switch_to_outer_block(gen, lambda); - - struct mie_value *ident_str - = mie_builder_load(gen->c_builder, str_type, ident_ptr, NULL); - - struct mie_value *capture_value = codegen_load_variable(gen, var); - struct mie_value *put_sel - = mie_ctx_get_selector(gen->c_ctx, "_M02at3putE"); - struct mie_value *put_args[] = { - ident_str, - capture_value, - }; - - struct mie_value *capture_store = mie_builder_msg( - gen->c_builder, void_type, lambda->s_ctx_external, put_sel, - put_args, sizeof put_args / sizeof put_args[0], - MIE_BUILDER_IGNORE_RESULT, NULL); - - switch_to_lambda_func(gen, lambda); - - struct codegen_var capture = { - .v_type = var->v_type, - .v_node = var->v_node, - .v_flags = CODEGEN_VAR_F_CAPTURE | CODEGEN_VAR_F_PTR, - }; - - ident_str = mie_builder_load(gen->c_builder, str_type, ident_ptr, NULL); - - struct mie_value *at_sel = mie_ctx_get_selector(gen->c_ctx, "_M02atE"); - struct mie_value *at_args[] = { - ident_str, - }; - - struct mie_value *stack_ptr - = mie_builder_alloca(gen->c_builder, var->v_type, ident); - - struct mie_value *value = mie_builder_msg( - gen->c_builder, var->v_type, lambda->s_ctx_internal, at_sel, - at_args, sizeof at_args / sizeof at_args[0], 0, NULL); - mie_builder_store(gen->c_builder, value, stack_ptr); - - capture.v_value = stack_ptr; - - *var = capture; - - return IVY_OK; -#endif - return IVY_ERR_NOT_SUPPORTED; -} - -struct code_generator lambda_generator = { - .g_type = CODE_GENERATOR_LAMBDA, - .g_state_size = sizeof(struct lambda_codegen_state), - .g_state_init = state_init, - .g_state_fini = state_fini, - .g_resolve_var = resolve_var, - .g_capture_var = capture_var, - .g_node_generators = { - NODE_CODEGEN(LAMBDA, gen_lambda), - NODE_CODEGEN(IDENT, gen_ident), - NODE_CODEGEN(BLOCK, gen_block), - }, -}; diff --git a/lang/codegen/return.c b/lang/codegen/return.c index 92b7a78..fca2ad9 100644 --- a/lang/codegen/return.c +++ b/lang/codegen/return.c @@ -70,7 +70,6 @@ static struct code_generator_result value_received( } ret->s_value = value->v_value.mie_value; - ret->s_prev_node = IVY_AST_EXPR; return CODEGEN_RESULT_OK(CODEGEN_R_POP_GENERATOR); } diff --git a/lang/include/ivy/lang/ast.h b/lang/include/ivy/lang/ast.h index ec6466c..ac33cd8 100644 --- a/lang/include/ivy/lang/ast.h +++ b/lang/include/ivy/lang/ast.h @@ -10,7 +10,6 @@ struct ivy_diag_ctx; struct ivy_token; -struct ivy_parser; struct fx_string; enum ivy_ast_node_type { @@ -24,11 +23,11 @@ enum ivy_ast_node_type { IVY_AST_BLOCK, IVY_AST_SELECTOR, IVY_AST_PROPERTY, - IVY_AST_LAMBDA, IVY_AST_UNIT_PACKAGE, IVY_AST_UNIT_IMPORT, IVY_AST_GLOBAL, IVY_AST_DISCARD, + IVY_AST_DO, IVY_AST_INT, IVY_AST_DOUBLE, IVY_AST_STRING, @@ -54,12 +53,6 @@ enum ivy_ast_node_type { IVY_AST_C_FALSE, IVY_AST_C_NULL, - /* these are pseudo-types. a finished AST will never have these nodes in - * it, but they are necessary to identifier AST parsers that will - * produce nodes of other, related types. */ - IVY_AST_PKG, - IVY_AST_EXPR, - IVY_AST_TYPE_COUNT, }; @@ -143,7 +136,7 @@ struct ivy_ast_class_node { struct ivy_ast_msgh_node { struct ivy_ast_node n_base; struct ivy_ast_selector_node *n_sel; - /* expressions to evaluate when lambda is executed. */ + /* expressions to evaluate when block is executed. */ struct ivy_ast_node *n_body; }; @@ -159,26 +152,26 @@ struct ivy_ast_property_node { } n_flags; /* one of either: - * a) a lambda. the lambda is executed to get the property value; or, + * a) a block. the block is executed to get the property value; or, * b) a constant value. the constant is returned as the property * value. c) NULL. the property is write-only. */ struct ivy_ast_node *n_get; /* one of either: - * a) a lambda. the lambda is executed with the provided value as a + * a) a block. the block is executed with the provided value as a * parameter to set the property value; or, * b) NULL. the property is read-only. */ struct ivy_ast_node *n_set; }; -struct ivy_ast_lambda_node { +struct ivy_ast_block_node { struct ivy_ast_node n_base; - /* queue of struct ivy_ast_ident_node; contains the names of the lambda + /* queue of struct ivy_ast_ident_node; contains the names of the block * parameters. */ fx_queue n_arg; - /* expressions to evaluate when lambda is executed. */ - struct ivy_ast_node *n_body; + /* expressions to evaluate when block is executed. */ + fx_queue n_expr; }; struct ivy_ast_unit_package_node { @@ -202,6 +195,11 @@ struct ivy_ast_discard_node { struct ivy_ast_node n_base; }; +struct ivy_ast_do_node { + struct ivy_ast_node n_base; + struct ivy_ast_node *n_block; +}; + struct ivy_ast_int_node { struct ivy_ast_node n_base; /* lex token of type IVY_TOK_INT. */ @@ -336,31 +334,10 @@ struct ivy_ast_pkg_dynamic_node { struct ivy_ast_node *n_cond; }; -struct ivy_ast_block_node { - struct ivy_ast_node n_base; - /* queue of struct ivy_ast_node. expressions to evaluate when the do node itself is evaluated. */ - fx_queue n_expr; -}; - typedef enum ivy_status (*ivy_ast_node_iteration_callback)( struct ivy_ast_node *, enum ivy_ast_iteration_type, struct ivy_ast_node_iterator *, void *); -IVY_API enum ivy_status ivy_parser_create(struct ivy_parser **parser); -IVY_API void ivy_parser_destroy( - struct ivy_parser *parser, struct ivy_ast_node **result); - -IVY_API enum ivy_status ivy_parser_set_diag_ctx( - struct ivy_parser *parser, struct ivy_diag_ctx *ctx); -IVY_API enum ivy_status ivy_parser_get_status(struct ivy_parser *parser); -IVY_API bool ivy_parser_is_node_complete(struct ivy_parser *parser); -IVY_API struct ivy_ast_node *ivy_parser_root_node(struct ivy_parser *parser); -IVY_API struct ivy_ast_node *ivy_parser_dequeue_node(struct ivy_parser *parser); - -IVY_API enum ivy_status ivy_parser_push_token( - struct ivy_parser *parser, struct ivy_token *tok); -IVY_API enum ivy_status ivy_parser_push_eof(struct ivy_parser *parser); - IVY_API struct ivy_ast_node *ivy_ast_node_create(enum ivy_ast_node_type type); IVY_API enum ivy_status ivy_ast_node_iterate( struct ivy_ast_node *node, struct ivy_ast_node_iterator *it, diff --git a/lang/include/ivy/lang/lex.h b/lang/include/ivy/lang/lex.h index 2305c56..7f8ac4b 100644 --- a/lang/include/ivy/lang/lex.h +++ b/lang/include/ivy/lang/lex.h @@ -151,6 +151,7 @@ IVY_API struct ivy_token *ivy_lexer_peek(struct ivy_lexer *lex); IVY_API struct ivy_token *ivy_lexer_read(struct ivy_lexer *lex); IVY_API bool ivy_lexer_tokens_available(struct ivy_lexer *lex); +IVY_API struct ivy_token *ivy_token_create_discard(void); IVY_API struct ivy_token *ivy_token_create_ident(const char *s); IVY_API void ivy_token_destroy(struct ivy_token *tok); @@ -163,6 +164,7 @@ static inline bool ivy_token_is_keyword(struct ivy_token *tok, enum ivy_keyword return (tok->t_type == IVY_TOK_KEYWORD && tok->t_keyword == kw); } +IVY_API const char *ivy_token_to_string(const struct ivy_token *tok); IVY_API const char *ivy_lex_token_type_to_string(enum ivy_token_type type); IVY_API const char *ivy_keyword_to_string(enum ivy_keyword keyword); IVY_API const char *ivy_symbol_to_string(enum ivy_symbol sym); diff --git a/lang/include/ivy/lang/parse.h b/lang/include/ivy/lang/parse.h new file mode 100644 index 0000000..afa9973 --- /dev/null +++ b/lang/include/ivy/lang/parse.h @@ -0,0 +1,23 @@ +#ifndef IVY_LANG_PARSE_H_ +#define IVY_LANG_PARSE_H_ + +#include +#include + +struct ivy_lexer; +struct ivy_parser; +struct ivy_ast_node; +struct ivy_diag_ctx; + +IVY_API enum ivy_status ivy_parser_create(struct ivy_parser **parser); +IVY_API void ivy_parser_destroy(struct ivy_parser *parser); + +IVY_API enum ivy_status ivy_parser_set_diag_ctx( + struct ivy_parser *parser, struct ivy_diag_ctx *ctx); +IVY_API enum ivy_status ivy_parser_get_status(struct ivy_parser *parser); + +IVY_API enum ivy_status ivy_parser_parse( + struct ivy_parser *parser, struct ivy_lexer *src, + struct ivy_ast_node **out); + +#endif diff --git a/lang/lex.c b/lang/lex.c index f8a5493..019e2b9 100644 --- a/lang/lex.c +++ b/lang/lex.c @@ -1,11 +1,11 @@ #include "lex.h" +#include #include #include #include #include #include -#include #include #include #include @@ -132,6 +132,7 @@ static void report_unrecognised_char(struct ivy_lexer *lex, int c) diag, lex->lex_cursor_row, lex->lex_cursor_row, NULL, 0, hl, nr_hl); } +#if 0 static void report_missing_whitespace(struct ivy_lexer *lex, int msg) { struct ivy_diag *diag = ivy_diag_ctx_create_diag( @@ -150,6 +151,7 @@ static void report_missing_whitespace(struct ivy_lexer *lex, int msg) ivy_diag_push_snippet( diag, lex->lex_cursor_row, lex->lex_cursor_row, NULL, 0, hl, nr_hl); } +#endif static struct lexer_state *push_lexer_state( struct ivy_lexer *lex, enum lexer_state_type state_type) @@ -490,7 +492,7 @@ static int advance(struct ivy_lexer *lex) lex->lex_cur_char = lex->lex_linebuf[lex->lex_linebuf_ptr]; lex->lex_cursor_col++; - if (lex->lex_cur_char == '\n') { + if (lex->lex_prev_char == '\n') { lex->lex_cursor_col = 1; lex->lex_cursor_row++; } @@ -1014,12 +1016,14 @@ static enum ivy_status read_symbol(struct ivy_lexer *lex) return read_number(lex, true); } +#if 0 if ((node->s_def->flags & LEX_TOK_REQUIRES_WHITESPACE) && (!isspace(prev) || !isspace(prefix))) { report_missing_whitespace( lex, IVY_LANG_MSG_WHITESPACE_REQUIRED_AROUND_BINARY_OP); return IVY_ERR_BAD_SYNTAX; } +#endif switch (node->s_def->id) { case IVY_SYM_SQUOTE: @@ -1080,8 +1084,11 @@ static enum ivy_status read_ident(struct ivy_lexer *lex) break; } - if (c == '-' && prev == '-') { - return IVY_ERR_BAD_SYNTAX; + if (c == '-') { + char next = peek_next(lex); + if (!isalnum(next)) { + break; + } } char s[2] = {c, 0}; @@ -1245,6 +1252,21 @@ struct ivy_token *ivy_token_create_ident(const char *s) return tok; } +struct ivy_token *ivy_token_create_discard(void) +{ + struct ivy_token *tok = malloc(sizeof *tok); + + if (!tok) { + return NULL; + } + + memset(tok, 0x0, sizeof *tok); + + tok->t_type = IVY_TOK_NONE; + + return tok; +} + void ivy_token_destroy(struct ivy_token *tok) { switch (tok->t_type) { @@ -1382,3 +1404,17 @@ const char *ivy_symbol_to_string(enum ivy_symbol sym) return ""; } } + +const char *ivy_token_to_string(const struct ivy_token *tok) +{ + switch (tok->t_type) { + case IVY_TOK_SYMBOL: + return ivy_symbol_to_string(tok->t_symbol); + case IVY_TOK_IDENT: + return tok->t_str; + case IVY_TOK_KEYWORD: + return ivy_keyword_to_string(tok->t_keyword); + default: + return ivy_lex_token_type_to_string(tok->t_type); + } +} diff --git a/lang/operator.c b/lang/operator.c index c1a58b3..e5cbbbf 100644 --- a/lang/operator.c +++ b/lang/operator.c @@ -96,8 +96,8 @@ static const struct ivy_operator *operator_symbols[] = { SYM_OP(BINARY_XOR_ASSIGN, CARET_EQUAL), SYM_OP(RANGE, DOUBLE_DOT), SYM_OP(RANGE_INCLUSIVE, DOUBLE_DOT_EQUAL), - SYM_OP(SELF_ACCESS, DOUBLE_COLON), - SYM_OP(PKG_ACCESS, HYPHEN_RIGHT_ANGLE), + SYM_OP(SELF_ACCESS, HYPHEN_RIGHT_ANGLE), + SYM_OP(PKG_ACCESS, DOT), /* parser-internal pseudo-operators. */ SYM_OP(LEFT_PAREN, LEFT_PAREN), diff --git a/lang/parse/block.c b/lang/parse/block.c new file mode 100644 index 0000000..cfbd0dd --- /dev/null +++ b/lang/parse/block.c @@ -0,0 +1,103 @@ +#include "ctx.h" + +#include + +static bool parse_block_params( + struct ivy_parser *parser, struct ivy_ast_block_node *block) +{ + while (1) { + if (parse_symbol(parser, IVY_SYM_PIPE)) { + break; + } + + if (!parse_symbol(parser, IVY_SYM_COLON)) { + parse_trace( + parser, + "expected `|`, or `:` followed by parameter " + "name"); + return false; + } + + struct ivy_token *ident = NULL; + if (!parse_word(parser, &ident)) { + parse_trace( + parser, + "expected parameter identifier after `:`"); + return false; + } + + struct ivy_ast_ident_node *ident_node = create_node(IVY_AST_IDENT); + ident_node->n_content = ident; + fx_queue_push_back(&block->n_arg, &ident_node->n_base.n_entry); + } + + return true; +} + +bool parse_block(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) { + parse_trace(parser, "expected `[` before block contents"); + return false; + } + + struct ivy_ast_block_node *block = create_node(IVY_AST_BLOCK); + if (!block) { + parser->p_status = IVY_ERR_NO_MEMORY; + return false; + } + + bool result = true; + + if (peek_symbol(parser, IVY_SYM_COLON)) { + result = parse_block_params(parser, block); + } + + if (!result) { + parse_trace(parser, "invalid block parameter list"); + return false; + } + + bool prev_was_expr = false; + + while (1) { + struct ivy_ast_node *child = NULL; + if (parse_linefeed(parser)) { + continue; + } + + if (parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) { + break; + } + + if (prev_was_expr) { + if (!parse_symbol(parser, IVY_SYM_DOT)) { + parse_trace( + parser, + "expected `.` after expression"); + result = false; + break; + } + + prev_was_expr = false; + continue; + } + + if (peek_expr_start(parser)) { + result = parse_expr(parser, EXPR_PARSE_NORMAL, &child); + prev_was_expr = true; + } else { + parse_trace(parser, "expected `]` or expression"); + result = false; + } + + if (!result || !child) { + break; + } + + fx_queue_push_back(&block->n_expr, &child->n_entry); + } + + *out = generic_node(block); + return result; +} diff --git a/lang/parse/cascade.c b/lang/parse/cascade.c new file mode 100644 index 0000000..1d0f905 --- /dev/null +++ b/lang/parse/cascade.c @@ -0,0 +1,79 @@ +#include "ctx.h" + +#include + +bool parse_cascade( + struct ivy_parser *parser, struct ivy_ast_node *first_msg, + struct ivy_ast_node **out) +{ + if (!peek_symbol(parser, IVY_SYM_SEMICOLON)) { + parse_trace(parser, "expected `;`"); + return false; + } + + struct ivy_ast_msg_node *first = (struct ivy_ast_msg_node *)first_msg; + if (first->n_base.n_type != IVY_AST_MSG) { + parse_trace(parser, "cascade operand is not a message"); + return false; + } + + struct ivy_ast_cascade_node *cascade = create_node(IVY_AST_CASCADE); + cascade->n_recipient = first->n_recipient; + first->n_recipient = NULL; + fx_queue_push_back(&cascade->n_msg, &first->n_base.n_entry); + + bool ok = true; + while (ok) { + parse_linefeed(parser); + + if (!parse_symbol(parser, IVY_SYM_SEMICOLON)) { + break; + } + + parse_linefeed(parser); + fx_queue_entry *entry = NULL; + struct ivy_ast_msg_node *msg = NULL; + struct ivy_token *tok = peek_token(parser); + if (!tok) { + break; + } + + switch (tok->t_type) { + case IVY_TOK_LABEL: + ok = parse_keyword_msg( + parser, cascade->n_recipient, + EXPR_PARSE_STOP_SEMICOLON, + (struct ivy_ast_node **)&msg); + if (!ok) { + break; + } + + break; + case IVY_TOK_IDENT: + ok = parse_unary_msg( + parser, cascade->n_recipient, + (struct ivy_ast_node **)&msg); + if (!ok) { + break; + } + + if (peek_symbol(parser, IVY_SYM_LEFT_PAREN)) { + ok = parse_complex_msg( + parser, generic_node(msg), + (struct ivy_ast_node **)&msg); + } + + break; + default: + parse_trace(parser, "expected message after `;`"); + ok = false; + break; + } + + msg->n_recipient = NULL; + fx_queue_push_back(&cascade->n_msg, &msg->n_base.n_entry); + } + + *out = generic_node(cascade); + return true; +} diff --git a/lang/parse/class.c b/lang/parse/class.c new file mode 100644 index 0000000..f04adb0 --- /dev/null +++ b/lang/parse/class.c @@ -0,0 +1,365 @@ +#include "ctx.h" + +#include + +static bool parse_named_selector( + struct ivy_parser *parser, struct ivy_ast_selector_node *sel) +{ + struct ivy_token *tok = NULL; + if (!parse_word(parser, &tok)) { + parse_trace(NULL, "expected selector name"); + return false; + } + + sel->n_msg_name = tok; + + if (!parse_symbol(parser, IVY_SYM_LEFT_PAREN)) { + return true; + } + + bool ok = true; + while (1) { + if (parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) { + break; + } + + struct ivy_token *label = NULL, *arg = NULL; + if (!fx_queue_empty(&sel->n_arg_labels) + && !parse_symbol(parser, IVY_SYM_COMMA)) { + parse_trace(NULL, "expected comma after selector arg"); + ok = false; + break; + } + + if (!parse_label(parser, &label)) { + parse_trace(NULL, "expected selector arg label"); + ok = false; + break; + } + + if (!parse_word(parser, &arg)) { + parse_trace(NULL, "expected selector arg name"); + ok = false; + break; + } + + fx_queue_push_back(&sel->n_arg_labels, &label->t_entry); + fx_queue_push_back(&sel->n_arg_names, &arg->t_entry); + } + + return true; +} + +static bool parse_unnamed_selector( + struct ivy_parser *parser, struct ivy_ast_selector_node *sel) +{ + bool ok = true; + while (1) { + struct ivy_token *label = NULL, *arg = NULL; + if (!parse_label(parser, &label)) { + break; + } + + if (!parse_word(parser, &arg)) { + parse_trace(NULL, "expected selector arg name"); + ok = false; + break; + } + + fx_queue_push_back(&sel->n_arg_labels, &label->t_entry); + fx_queue_push_back(&sel->n_arg_names, &arg->t_entry); + } + + return true; +} + +static bool parse_selector(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + struct ivy_ast_selector_node *sel = create_node(IVY_AST_SELECTOR); + if (parse_symbol(parser, IVY_SYM_PLUS)) { + sel->n_recipient = IVY_SELECTOR_RECIPIENT_CLASS; + } else if (parse_symbol(parser, IVY_SYM_HYPHEN)) { + sel->n_recipient = IVY_SELECTOR_RECIPIENT_OBJECT; + } else { + parse_trace(NULL, "invalid selector prefix"); + return false; + } + + bool ok = true; + if (peek_word(parser)) { + ok = parse_named_selector(parser, sel); + } else { + ok = parse_unnamed_selector(parser, sel); + } + + if (!ok) { + return false; + } + + *out = generic_node(sel); + return true; +} + +static bool parse_msg(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + struct ivy_ast_node *sel = NULL; + if (!parse_selector(parser, &sel)) { + parse_trace(NULL, "invalid message handler selector"); + return false; + } + + struct ivy_ast_msgh_node *msgh = create_node(IVY_AST_MSGH); + msgh->n_sel = (struct ivy_ast_selector_node *)sel; + + bool ok = true; + struct ivy_ast_node *body = NULL; + if (peek_symbol(parser, IVY_SYM_LEFT_BRACKET)) { + ok = parse_block(parser, &body); + } else if (parse_symbol(parser, IVY_SYM_PIPE)) { + ok = parse_expr(parser, EXPR_PARSE_NORMAL, &body); + ok = ok && parse_symbol(parser, IVY_SYM_DOT); + } else { + parse_trace(NULL, "expected message handler body"); + ok = false; + } + + if (!ok) { + return false; + } + + msgh->n_body = body; + *out = generic_node(msgh); + return true; +} + +static bool parse_default_property( + struct ivy_parser *parser, struct ivy_ast_property_node *prop) +{ + if (!parse_symbol(parser, IVY_SYM_LEFT_PAREN)) { + parse_trace(parser, "expected '('"); + return false; + } + + bool ok = true; + while (ok) { + parse_linefeed(parser); + + if (parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) { + break; + } + + int access_types_set + = prop->n_flags + & (IVY_AST_PROPERTY_SET | IVY_AST_PROPERTY_GET); + + if (access_types_set != 0 && !parse_symbol(parser, IVY_SYM_COMMA)) { + parse_trace( + NULL, + "expected `,` or `)` after property access " + "type"); + ok = false; + break; + } + + parse_linefeed(parser); + + int access_type = 0; + if (parse_keyword(parser, IVY_KW_GET)) { + access_type = IVY_AST_PROPERTY_GET; + } else if (parse_keyword(parser, IVY_KW_SET)) { + access_type = IVY_AST_PROPERTY_SET; + } else { + parse_trace(parser, "unknown property access type"); + ok = false; + break; + } + + parse_linefeed(parser); + + if (prop->n_flags & access_type) { + parse_trace(parser, "property access type already set"); + ok = false; + break; + } + + prop->n_flags |= access_type; + } + + return true; +} + +static bool parse_property(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + struct ivy_token *tok = NULL; + if (!parse_word(parser, &tok)) { + parse_trace(NULL, "expected property name"); + return false; + } + + struct ivy_ast_property_node *prop = create_node(IVY_AST_PROPERTY); + prop->n_ident = tok; + + if (peek_symbol(parser, IVY_SYM_LEFT_PAREN)) { + return parse_default_property(parser, prop); + } + + if (!parse_symbol(parser, IVY_SYM_PIPE)) { + parse_trace(NULL, "expected `|` after property name"); + return false; + } + + bool ok = true; + + while (ok) { + if (parse_symbol(parser, IVY_SYM_DOT)) { + break; + } + + parse_linefeed(parser); + + if ((prop->n_get || prop->n_set) + && !parse_symbol(parser, IVY_SYM_COMMA)) { + parse_trace( + NULL, + "expected `,` or `.` after property " + "branch"); + ok = false; + break; + } + + parse_linefeed(parser); + + int access_type = 0; + if (parse_keyword(parser, IVY_KW_GET)) { + access_type = IVY_AST_PROPERTY_GET; + } else if (parse_keyword(parser, IVY_KW_SET)) { + access_type = IVY_AST_PROPERTY_SET; + } else { + parse_trace(NULL, "unknown property access type"); + ok = false; + break; + } + + parse_linefeed(parser); + + if (!parse_symbol(parser, IVY_SYM_EQUAL_RIGHT_ANGLE)) { + parse_trace( + NULL, + "expected `=>` after property branch " + "type"); + ok = false; + break; + } + + parse_linefeed(parser); + + struct ivy_ast_node *body = NULL; + if (peek_symbol(parser, IVY_SYM_LEFT_BRACKET)) { + ok = parse_block(parser, &body); + } else { + ok = parse_expr(parser, EXPR_PARSE_STOP_COMMA, &body); + } + + if (!ok) { + parse_trace(parser, "invalid property value"); + break; + } + + prop->n_flags |= access_type; + switch (access_type) { + case IVY_AST_PROPERTY_GET: + if (prop->n_get) { + parse_trace(NULL, "property getter already set"); + ok = false; + break; + } + + prop->n_get = body; + break; + case IVY_AST_PROPERTY_SET: + if (prop->n_set) { + parse_trace(NULL, "property setter already set"); + ok = false; + break; + } + + prop->n_set = body; + break; + default: + ok = false; + break; + } + } + + if (!ok) { + return false; + } + + *out = generic_node(prop); + return true; +} + +bool parse_class(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_CLASS)) { + return false; + } + + struct ivy_token *ident = NULL; + if (!parse_word(parser, &ident)) { + parse_trace(NULL, "expected class identifier"); + return false; + } + + if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) { + parse_trace(NULL, "expected `[` after class identifier"); + return false; + } + + struct ivy_ast_class_node *class = create_node(IVY_AST_CLASS); + if (!class) { + parser->p_status = IVY_ERR_NO_MEMORY; + return false; + } + + class->n_ident = ident; + + bool result = true; + while (1) { + struct ivy_ast_node *msg = NULL, *property = NULL; + if (parse_linefeed(parser)) { + continue; + } + + if (parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) { + break; + } + + if (peek_symbol(parser, IVY_SYM_HYPHEN)) { + result = parse_msg(parser, &msg); + } else if (peek_symbol(parser, IVY_SYM_PLUS)) { + result = parse_msg(parser, &msg); + } else if (peek_word(parser)) { + result = parse_property(parser, &property); + } else { + parse_trace( + parser, "unexpected token %s in class", + ivy_token_to_string(peek_token(parser))); + result = false; + } + + if (!result) { + break; + } + + if (msg) { + fx_queue_push_back(&class->n_msg_handlers, &msg->n_entry); + } else if (property) { + fx_queue_push_back( + &class->n_msg_handlers, &property->n_entry); + } + } + + *out = generic_node(class); + return result; +} diff --git a/lang/parse/ctx.c b/lang/parse/ctx.c new file mode 100644 index 0000000..0639d18 --- /dev/null +++ b/lang/parse/ctx.c @@ -0,0 +1,126 @@ +#include "ctx.h" + +#include +#include +#include + +enum ivy_status ivy_parser_create(struct ivy_parser **parser) +{ + struct ivy_parser *out = malloc(sizeof *out); + if (!out) { + return IVY_ERR_NO_MEMORY; + } + + memset(out, 0x0, sizeof *out); + + *parser = out; + return IVY_OK; +} + +void ivy_parser_destroy(struct ivy_parser *parser) +{ + free(parser); +} + +enum ivy_status ivy_parser_set_diag_ctx( + struct ivy_parser *parser, struct ivy_diag_ctx *ctx) +{ + parser->p_diag = ctx; + return IVY_OK; +} + +enum ivy_status ivy_parser_get_status(struct ivy_parser *parser) +{ + return parser->p_status; +} + +enum ivy_status ivy_parser_parse( + struct ivy_parser *parser, struct ivy_lexer *src, struct ivy_ast_node **out) +{ + parser->p_src = src; + enum ivy_status status = parse_unit(parser, out); + if (status == IVY_ERR_EOF && *out != NULL) { + status = IVY_OK; + } + + return status; +} + +struct ivy_token *peek_token(struct ivy_parser *parser) +{ + fx_queue_entry *entry = fx_queue_first(&parser->p_tokens); + if (!entry) { + return ivy_lexer_peek(parser->p_src); + } + + return fx_unbox(struct ivy_token, entry, t_entry); +} + +struct ivy_token *peek_next_token(struct ivy_parser *parser) +{ + if (fx_queue_empty(&parser->p_tokens)) { + struct ivy_token *tok = parse_token(parser); + fx_queue_push_back(&parser->p_tokens, &tok->t_entry); + return ivy_lexer_peek(parser->p_src); + } + + fx_queue_entry *buf = fx_queue_first(&parser->p_tokens); + if (buf) { + buf = fx_queue_next(buf); + } + + if (buf) { + return fx_unbox(struct ivy_token, buf, t_entry); + } + + return ivy_lexer_peek(parser->p_src); +} + +struct ivy_token *parse_token(struct ivy_parser *parser) +{ + fx_queue_entry *entry = fx_queue_pop_front(&parser->p_tokens); + if (!entry) { + return ivy_lexer_read(parser->p_src); + } + + return fx_unbox(struct ivy_token, entry, t_entry); +} + +void discard_token(struct ivy_parser *parser) +{ + struct ivy_token *tok = parse_token(parser); + if (tok) { + ivy_token_destroy(tok); + } +} + +void __parse_trace( + struct ivy_parser *parser, const char *func, int line, + const char *format, ...) +{ + struct ivy_token *tok = NULL; + if (parser) { + tok = peek_token(parser); + if (tok) { + fprintf(stderr, "[%zu:%zu] ", tok->t_start.c_row, + tok->t_start.c_col); + } else { + fprintf(stderr, "[EOF] "); + } + } else { + fprintf(stderr, "[UNK] "); + } + + fprintf(stderr, "%s:%d: ", func, line); + + if (tok) { + fprintf(stderr, "(%s) ", ivy_token_to_string(tok)); + } + + va_list va; + va_start(va, format); + vfprintf(stderr, format, va); + va_end(va); + + fputc('\n', stderr); +} diff --git a/lang/parse/ctx.h b/lang/parse/ctx.h new file mode 100644 index 0000000..205f374 --- /dev/null +++ b/lang/parse/ctx.h @@ -0,0 +1,116 @@ +#ifndef _LANG_PARSE_CTX_H_ +#define _LANG_PARSE_CTX_H_ + +#include +#include +#include + +#define parse_trace(p, ...) \ + __parse_trace(p, __FUNCTION__, __LINE__, __VA_ARGS__) + +struct ivy_lexer; +struct ivy_diag_ctx; +struct ivy_ast_node; + +struct ivy_parser { + struct ivy_lexer *p_src; + struct ivy_diag_ctx *p_diag; + enum ivy_status p_status; + fx_queue p_tokens; +}; + +#define create_node(type) ((void *)ivy_ast_node_create(type)) +#define destroy_node(p) ivy_ast_node_destroy((struct ivy_ast_node *)(p)) +#define generic_node(p) ((struct ivy_ast_node *)(p)) + +enum expr_parse_flags { + EXPR_PARSE_NORMAL = 0, + EXPR_PARSE_CONSUME_TERMINATOR = 0x01u, + EXPR_PARSE_STOP_KW_CONTROL = 0x02u, + EXPR_PARSE_STOP_KW_IN = 0x04u, + EXPR_PARSE_STOP_COMMA = 0x08u, + EXPR_PARSE_STOP_LABEL = 0x10u, + EXPR_PARSE_STOP_LEFT_BRACKET = 0x20u, + EXPR_PARSE_STOP_TUPLE_TERMINATOR = 0x40u, + EXPR_PARSE_STOP_SEMICOLON = 0x80u, +}; + +extern bool is_tuple_terminator(struct ivy_token *tok); + +extern const struct ivy_operator *get_operator_from_token(struct ivy_token *tok); +extern struct ivy_ast_node *create_operator_node_from_token(struct ivy_token *tok); +extern const struct ivy_operator *get_operator_from_node(struct ivy_ast_node *n); + +extern struct ivy_token *peek_token(struct ivy_parser *parser); +extern struct ivy_token *peek_next_token(struct ivy_parser *parser); +extern struct ivy_token *parse_token(struct ivy_parser *parser); +extern void discard_token(struct ivy_parser *parser); + +extern bool peek_word(struct ivy_parser *parser); +extern bool peek_keyword(struct ivy_parser *parser, enum ivy_keyword kw); +extern bool peek_symbol(struct ivy_parser *parser, enum ivy_symbol sym); +extern bool peek_linefeed(struct ivy_parser *parser); + +extern bool parse_eof(struct ivy_parser *parser); +extern bool parse_keyword(struct ivy_parser *parser, enum ivy_keyword kw); +extern bool parse_symbol(struct ivy_parser *parser, enum ivy_symbol sym); +extern bool parse_word(struct ivy_parser *parser, struct ivy_token **out); +extern bool parse_string(struct ivy_parser *parser, struct ivy_token **out); +extern bool parse_label(struct ivy_parser *parser, struct ivy_token **out); +extern bool parse_str_start(struct ivy_parser *parser); +extern bool parse_str_end(struct ivy_parser *parser); +extern bool parse_linefeed(struct ivy_parser *parser); + +extern bool peek_expr_start(struct ivy_parser *parser); + +extern bool parse_tuple( + struct ivy_parser *parser, struct ivy_ast_node *first_item, + struct ivy_ast_node **out); +extern bool parse_cascade( + struct ivy_parser *parser, struct ivy_ast_node *first_msg, + struct ivy_ast_node **out); +extern bool parse_unary_msg( + struct ivy_parser *parser, struct ivy_ast_node *recipient, + struct ivy_ast_node **out); +extern bool parse_keyword_msg( + struct ivy_parser *parser, struct ivy_ast_node *recipient, + enum expr_parse_flags flags, struct ivy_ast_node **out); +extern bool parse_complex_msg( + struct ivy_parser *parser, struct ivy_ast_node *unary_msg, + struct ivy_ast_node **out); +extern bool parse_fstring(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_index( + struct ivy_parser *parser, struct ivy_ast_node *container, + struct ivy_ast_node **out); + +extern bool parse_unit(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_block(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_class(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_package(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_match(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_for(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_for_inline( + struct ivy_parser *parser, struct ivy_ast_node *body, + struct ivy_ast_node **out); +extern bool parse_while(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_while_inline( + struct ivy_parser *parser, struct ivy_ast_node *body, + struct ivy_ast_node **out); +extern bool parse_if(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_if_inline( + struct ivy_parser *parser, struct ivy_ast_node *body, + struct ivy_ast_node **out); +extern bool parse_try(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_package_id(struct ivy_parser *parser, struct ivy_ast_node **out); +extern bool parse_package_import( + struct ivy_parser *parser, struct ivy_ast_node **out); + +extern bool parse_expr( + struct ivy_parser *parser, enum expr_parse_flags flags, + struct ivy_ast_node **out); + +extern void __parse_trace( + struct ivy_parser *parser, const char *func, int line, + const char *format, ...); + +#endif diff --git a/lang/parse/do.c b/lang/parse/do.c new file mode 100644 index 0000000..e69de29 diff --git a/lang/parse/eof.c b/lang/parse/eof.c new file mode 100644 index 0000000..9cb898f --- /dev/null +++ b/lang/parse/eof.c @@ -0,0 +1,7 @@ +#include "ctx.h" + +bool parse_eof(struct ivy_parser *parser) +{ + struct ivy_token *tok = peek_token(parser); + return (!tok && ivy_lexer_get_status(parser->p_src) == IVY_ERR_EOF); +} diff --git a/lang/parse/expr.c b/lang/parse/expr.c new file mode 100644 index 0000000..686d024 --- /dev/null +++ b/lang/parse/expr.c @@ -0,0 +1,966 @@ +#include "ctx.h" + +#include + +enum expr_component { + EXPR_C_NONE = 0, + EXPR_C_BINARY_OP, + EXPR_C_UNARY_OP, + EXPR_C_OPERAND, +}; + +struct expr_parse_ctx { + fx_queue expr_operator_stack, expr_out_queue; + enum expr_component expr_prev; + enum expr_parse_flags expr_flags; +}; + +static bool finalise_expr( + struct expr_parse_ctx *ctx, struct ivy_ast_node **out, + enum ivy_operator_precedence minimum_precedence); + +bool peek_expr_start(struct ivy_parser *parser) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok) { + return false; + } + + switch (tok->t_type) { + case IVY_TOK_INT: + case IVY_TOK_ATOM: + case IVY_TOK_DOUBLE: + case IVY_TOK_IDENT: + case IVY_TOK_STRING: + case IVY_TOK_STR_START: + return true; + case IVY_TOK_KEYWORD: + switch (tok->t_keyword) { + case IVY_KW_IF: + case IVY_KW_WHILE: + case IVY_KW_FOR: + case IVY_KW_TRY: + case IVY_KW_UNLESS: + case IVY_KW_CONTINUE: + case IVY_KW_BREAK: + case IVY_KW_MATCH: + case IVY_KW_TRUE: + case IVY_KW_FALSE: + case IVY_KW_NULL: + return true; + default: + return false; + } + break; + case IVY_TOK_SYMBOL: + switch (tok->t_symbol) { + case IVY_SYM_LEFT_BRACE: + case IVY_SYM_LEFT_BRACKET: + case IVY_SYM_LEFT_PAREN: + case IVY_SYM_CARET: + case IVY_SYM_UNDERSCORE: + return true; + default: + return false; + } + break; + default: + return false; + } +} + +static struct ivy_ast_node *pop_operand( + struct expr_parse_ctx *expr, enum ivy_operator_precedence min_precedence) +{ + struct ivy_ast_node *out = NULL; + bool ok = finalise_expr(expr, &out, min_precedence); + if (!ok) { + parse_trace(NULL, "sub-expression is invalid"); + return NULL; + } + + return out; +} + +static bool parse_simple_operand( + struct ivy_parser *parser, struct expr_parse_ctx *expr) +{ + if (expr->expr_prev == EXPR_C_OPERAND) { + parse_trace(parser, "encountered two operands in a row"); + return false; + } + + expr->expr_prev = EXPR_C_OPERAND; + struct ivy_token *tok = peek_token(parser); + switch (tok->t_type) { + case IVY_TOK_INT: { + struct ivy_ast_int_node *v = create_node(IVY_AST_INT); + v->n_value = parse_token(parser); + fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry); + return true; + } + case IVY_TOK_DOUBLE: { + struct ivy_ast_double_node *v = create_node(IVY_AST_DOUBLE); + v->n_value = parse_token(parser); + fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry); + return true; + } + case IVY_TOK_STRING: { + struct ivy_ast_string_node *v = create_node(IVY_AST_STRING); + v->n_value = parse_token(parser); + fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry); + return true; + } + case IVY_TOK_IDENT: { + struct ivy_ast_ident_node *v = create_node(IVY_AST_IDENT); + v->n_content = parse_token(parser); + fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry); + return true; + } + case IVY_TOK_ATOM: { + struct ivy_ast_atom_node *v = create_node(IVY_AST_ATOM); + v->n_content = parse_token(parser); + fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry); + return true; + } + case IVY_TOK_SYMBOL: + switch (tok->t_symbol) { + case IVY_SYM_UNDERSCORE: { + struct ivy_ast_discard_node *v + = create_node(IVY_AST_DISCARD); + discard_token(parser); + fx_queue_push_back( + &expr->expr_out_queue, &v->n_base.n_entry); + return true; + } + default: + parse_trace( + parser, "token %s is not a simple operand", + ivy_symbol_to_string(tok->t_symbol)); + return false; + } + break; + default: + parse_trace( + parser, "token %s is not a simple operand", + ivy_lex_token_type_to_string(tok->t_type)); + return false; + } +} + +void arith_push_operator(struct expr_parse_ctx *state, struct ivy_ast_node *node) +{ + const struct ivy_operator *op = get_operator_from_node(node); + if (!op) { + return; + } + + while (true) { + fx_queue_entry *top = fx_queue_last(&state->expr_operator_stack); + if (!top) { + break; + } + + struct ivy_ast_node *top_node + = fx_unbox(struct ivy_ast_node, top, n_entry); + const struct ivy_operator *top_op = NULL; + + switch (top_node->n_type) { + case IVY_AST_OP: { + struct ivy_ast_op_node *op_node + = (struct ivy_ast_op_node *)top_node; + top_op = op_node->n_op; + break; + } + case IVY_AST_MSG: { + struct ivy_ast_msg_node *msg_node + = (struct ivy_ast_msg_node *)top_node; + top_op = ivy_operator_get_by_id(IVY_OP_MSG); + break; + } + default: + return; + } + + if (top_op->op_precedence < op->op_precedence + || (top_op->op_precedence == op->op_precedence + && op->op_associativity != IVY_ASSOCIATIVITY_LEFT)) { + break; + } + + fx_queue_delete(&state->expr_operator_stack, top); + fx_queue_push_back(&state->expr_out_queue, top); + } + + fx_queue_push_back(&state->expr_operator_stack, &node->n_entry); +} + +static bool parse_binary_operator( + struct ivy_parser *parser, struct expr_parse_ctx *expr) +{ + struct ivy_token *tok = parse_token(parser); + + if (expr->expr_prev != EXPR_C_OPERAND) { + parse_trace(parser, "expected operand before binary operator"); + return false; + } + + expr->expr_prev = EXPR_C_BINARY_OP; + + struct ivy_ast_node *op_node = create_operator_node_from_token(tok); + if (!op_node) { + parse_trace(parser, "unrecognised binary operator"); + return false; + } + + arith_push_operator(expr, op_node); + return true; +} + +static bool expr_is_empty(struct expr_parse_ctx *expr) +{ + return fx_queue_empty(&expr->expr_out_queue) + && fx_queue_empty(&expr->expr_operator_stack); +} + +static bool op_node_is_complete(struct ivy_ast_op_node *node) +{ + if (!node->n_op) { + return false; + } + + switch (node->n_op->op_arity) { + case IVY_OP_UNARY: + return node->n_right != NULL; + case IVY_OP_BINARY: + return (node->n_left != NULL && node->n_right != NULL); + default: + return false; + } +} + +static bool finalise_expr( + struct expr_parse_ctx *ctx, struct ivy_ast_node **out, + enum ivy_operator_precedence minimum_precedence) +{ + fx_queue_entry *entry = NULL; + while (true) { + entry = fx_queue_pop_back(&ctx->expr_operator_stack); + if (!entry) { + break; + } + + struct ivy_ast_node *node + = fx_unbox(struct ivy_ast_node, entry, n_entry); + if (!node) { + /* this should never happen */ + return false; + } + + const struct ivy_operator *op = NULL; + + switch (node->n_type) { + case IVY_AST_OP: { + struct ivy_ast_op_node *n = (struct ivy_ast_op_node *)node; + op = n->n_op; + break; + } + case IVY_AST_MSG: + /* all unary message operators have the same + * pre-defined precedence */ + op = ivy_operator_get_by_id(IVY_OP_MSG); + break; + default: + return false; + } + + /* if we aren't processing operators below a certain precedence + * then leave them on the stack and stop here. */ + if (op->op_precedence < minimum_precedence) { + fx_queue_push_back(&ctx->expr_operator_stack, entry); + break; + } + + fx_queue_push_back(&ctx->expr_out_queue, entry); + } + + fx_queue q = FX_QUEUE_INIT; + fx_queue_entry *tmp = NULL; + entry = fx_queue_first(&ctx->expr_out_queue); + int i = 0; + + while (entry) { + struct ivy_ast_node *item + = fx_unbox(struct ivy_ast_node, entry, n_entry); + fx_queue_entry *next = fx_queue_next(entry); + fx_queue_delete(&ctx->expr_out_queue, entry); + + /* if the node is an operand, just push it to a + * temporary queue and come back to it later. */ + if (item->n_type != IVY_AST_OP && item->n_type != IVY_AST_MSG) { + /* operand */ + fx_queue_push_back(&q, &item->n_entry); + goto next; + } + + const struct ivy_operator *op = NULL; + + if (item->n_type == IVY_AST_MSG) { + struct ivy_ast_msg_node *msg + = (struct ivy_ast_msg_node *)item; + /* if the message has no recipient, it is a unary message, + * and the recipient is located on the operand stack. + * + * if the message DOES have a recipient, it is a + * self-contained keyword message, and can be pushed to + * the operand queue as-is. */ + if (!msg->n_recipient) { + tmp = fx_queue_pop_back(&q); + msg->n_recipient = fx_unbox( + struct ivy_ast_node, tmp, n_entry); + } + fx_queue_push_back(&q, &msg->n_base.n_entry); + goto next; + } + + struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)item; + /* if an operator node is already complete (i.e. it + * already has all the operands it needs, it can be + * pushed to the operand queue as-is */ + if (op_node_is_complete(op_node)) { + fx_queue_push_back(&q, &item->n_entry); + goto next; + } + + /* otherwise, pop the relevant operands from the operand + * queue... */ + op = op_node->n_op; + tmp = fx_queue_pop_back(&q); + op_node->n_right = fx_unbox(struct ivy_ast_node, tmp, n_entry); + + if (op_node->n_right) { + op_node->n_right->n_parent = (struct ivy_ast_node *)op_node; + + ivy_ast_node_extend_bounds_recursive( + (struct ivy_ast_node *)op_node, + (struct ivy_ast_node *)tmp); + } + + if (op->op_arity == IVY_OP_BINARY) { + tmp = fx_queue_pop_back(&q); + op_node->n_left + = fx_unbox(struct ivy_ast_node, tmp, n_entry); + + if (op_node->n_left) { + op_node->n_left->n_parent + = (struct ivy_ast_node *)op_node; + + ivy_ast_node_extend_bounds_recursive( + (struct ivy_ast_node *)op_node, + (struct ivy_ast_node *)tmp); + } + } + + /* ...and push the newly-completed operator node to the + * operand queue */ + fx_queue_push_back(&q, &op_node->n_base.n_entry); + next: + entry = next; + } + +#if 0 + debug_printf("** after hierarchisation:\n"); + print_expr_queues(state); +#endif + + /* if we are not processing operators below a certain precedence, + * i.e. when determining the recipient of a keyword-message), these + * operators will still be on the parser state's operator stack, but + * their operands have just been moved to the temporary operand stack + * used above. move them back to the parser state's output queue here + * so they can be used later. */ + entry = fx_queue_first(&ctx->expr_operator_stack); + while (entry) { + fx_queue_entry *entry2 = fx_queue_pop_front(&q); + if (!entry2) { + return false; + } + + fx_queue_push_back(&ctx->expr_out_queue, entry2); + entry = fx_queue_next(entry); + } + +#if 0 + debug_printf("** after de-linearisation:\n"); + print_expr_queues(state); + ivy_ast_node_print(*expr_tree); + debug_printf("------\n"); +#endif + + /* the final node remaining on the temp operand stack is the + * root node of the new expression tree */ + tmp = fx_queue_pop_back(&q); + *out = fx_unbox(struct ivy_ast_node, tmp, n_entry); + + return true; +} + +static bool parse_call( + struct ivy_parser *parser, struct ivy_ast_node *target, + struct ivy_ast_node **out) +{ + if (!parse_symbol(parser, IVY_SYM_LEFT_PAREN)) { + parse_trace(parser, "expected `(` before call arguments"); + } + + struct ivy_ast_msg_node *call = create_node(IVY_AST_MSG); + call->n_recipient = target; + call->n_sel = create_node(IVY_AST_SELECTOR); + + call->n_sel->n_msg_name = ivy_token_create_ident("call"); + + bool ok = true; + while (ok) { + if (parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) { + break; + } + + if (!fx_queue_empty(&call->n_arg) + && !parse_symbol(parser, IVY_SYM_COMMA)) { + parse_trace( + parser, + "expected `,` or `)` after call argument"); + ok = false; + break; + } + + struct ivy_ast_node *arg = NULL; + if (!parse_expr(parser, EXPR_PARSE_STOP_COMMA, &arg)) { + parse_trace(parser, "invalid call argument"); + ok = false; + break; + } + + struct ivy_token *label = ivy_token_create_discard(); + fx_queue_push_back(&call->n_sel->n_arg_labels, &label->t_entry); + fx_queue_push_back(&call->n_arg, &arg->n_entry); + } + + *out = generic_node(call); + return true; +} + +static bool cleanup_expr(struct expr_parse_ctx *ctx) +{ + return false; +} + +bool parse_expr( + struct ivy_parser *parser, enum expr_parse_flags flags, + struct ivy_ast_node **out) +{ + struct expr_parse_ctx ctx = {0}; + ctx.expr_flags = flags; + bool ok = true; + bool done = false; + bool return_expr = false; + bool end_without_dot = false; + + while (ok && !done) { + struct ivy_token *tok = peek_token(parser); + if (!tok) { + break; + } + + if ((flags & EXPR_PARSE_STOP_TUPLE_TERMINATOR) + && is_tuple_terminator(tok)) { + done = true; + break; + } + + switch (tok->t_type) { + case IVY_TOK_LINEFEED: + discard_token(parser); + break; + case IVY_TOK_IDENT: + if (ctx.expr_prev == EXPR_C_OPERAND) { + struct ivy_ast_node *msg = NULL; + ok = parse_unary_msg(parser, NULL, &msg); + if (!ok) { + break; + } + + fx_queue_push_back( + &ctx.expr_out_queue, &msg->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + } else { + ok = parse_simple_operand(parser, &ctx); + } + break; + case IVY_TOK_INT: + case IVY_TOK_STRING: + case IVY_TOK_DOUBLE: + case IVY_TOK_ATOM: + ok = parse_simple_operand(parser, &ctx); + break; + case IVY_TOK_STR_START: { + struct ivy_ast_node *v = NULL; + ok = parse_fstring(parser, &v); + if (!ok) { + break; + } + + fx_queue_push_back(&ctx.expr_out_queue, &v->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + break; + } + + case IVY_TOK_LABEL: { + if (flags & EXPR_PARSE_STOP_LABEL) { + done = true; + break; + } + + struct ivy_ast_node *recipient + = pop_operand(&ctx, IVY_PRECEDENCE_KEYWORD_MSG); + if (!recipient) { + parse_trace( + parser, + "no valid recipient for keyword msg"); + ok = false; + break; + } + + struct ivy_ast_node *v = NULL; + ok = parse_keyword_msg( + parser, recipient, ctx.expr_flags, &v); + + if (!ok) { + break; + } + + fx_queue_push_back(&ctx.expr_out_queue, &v->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + break; + } + case IVY_TOK_KEYWORD: { + struct ivy_ast_node *operand = NULL; + if (expr_is_empty(&ctx)) { + end_without_dot = true; + } + + switch (tok->t_keyword) { + case IVY_KW_ELSE: + case IVY_KW_CATCH: + done = true; + break; + case IVY_KW_MATCH: + ok = parse_match(parser, &operand); + break; + case IVY_KW_DO: { + discard_token(parser); + struct ivy_ast_do_node *do_node + = create_node(IVY_AST_DO); + ok = parse_block(parser, &do_node->n_block); + if (!ok) { + break; + } + + operand = generic_node(do_node); + break; + } + case IVY_KW_IF: + if (flags & EXPR_PARSE_STOP_KW_CONTROL) { + done = true; + break; + } + + if (ctx.expr_prev == EXPR_C_OPERAND) { + struct ivy_ast_node *body = pop_operand( + &ctx, IVY_PRECEDENCE_IF_ELSE); + if (!body) { + parse_trace( + parser, + "invalid " + "inline-if " + "body"); + } + + ok = parse_if_inline(parser, body, &operand); + } else { + ok = parse_if(parser, &operand); + } + break; + case IVY_KW_FOR: + if (flags & EXPR_PARSE_STOP_KW_CONTROL) { + done = true; + break; + } + + if (ctx.expr_prev == EXPR_C_OPERAND) { + struct ivy_ast_node *body = pop_operand( + &ctx, IVY_PRECEDENCE_IF_ELSE); + if (!body) { + parse_trace( + parser, + "invalid " + "inline-for " + "body"); + } + + ok = parse_for_inline( + parser, body, &operand); + } else { + ok = parse_for(parser, &operand); + } + + break; + case IVY_KW_WHILE: + if (flags & EXPR_PARSE_STOP_KW_CONTROL) { + done = true; + break; + } + + if (ctx.expr_prev == EXPR_C_OPERAND) { + struct ivy_ast_node *body = pop_operand( + &ctx, IVY_PRECEDENCE_IF_ELSE); + if (!body) { + parse_trace( + parser, + "invalid " + "inline-while " + "body"); + } + + ok = parse_while_inline( + parser, body, &operand); + } else { + ok = parse_while(parser, &operand); + } + break; + case IVY_KW_IN: + if (flags & EXPR_PARSE_STOP_KW_IN) { + done = true; + break; + } + + case IVY_KW_IS: + ok = parse_binary_operator(parser, &ctx); + break; + case IVY_KW_TRY: + if (flags & EXPR_PARSE_STOP_KW_CONTROL) { + done = true; + break; + } + + ok = parse_try(parser, &operand); + break; + default: + parse_trace( + parser, "unrecognised keyword %s", + ivy_keyword_to_string(tok->t_keyword)); + ok = false; + break; + } + + if (ok && operand) { + fx_queue_push_back( + &ctx.expr_out_queue, &operand->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + + if (end_without_dot && parse_linefeed(parser)) { + done = true; + } + } + + break; + } + case IVY_TOK_SYMBOL: + switch (tok->t_symbol) { + case IVY_SYM_DOUBLE_COLON: + case IVY_SYM_PLUS: + case IVY_SYM_HYPHEN: + case IVY_SYM_FORWARD_SLASH: + case IVY_SYM_ASTERISK: + case IVY_SYM_PERCENT: + case IVY_SYM_AMPERSAND: + case IVY_SYM_EQUAL: + case IVY_SYM_HYPHEN_RIGHT_ANGLE: + case IVY_SYM_DOUBLE_EQUAL: + case IVY_SYM_LEFT_ANGLE: + case IVY_SYM_RIGHT_ANGLE: + case IVY_SYM_DOUBLE_LEFT_ANGLE: + case IVY_SYM_DOUBLE_RIGHT_ANGLE: + case IVY_SYM_LEFT_ANGLE_EQUAL: + case IVY_SYM_RIGHT_ANGLE_EQUAL: + case IVY_SYM_DOUBLE_LEFT_ANGLE_EQUAL: + case IVY_SYM_DOUBLE_RIGHT_ANGLE_EQUAL: + case IVY_SYM_PLUS_EQUAL: + case IVY_SYM_HYPHEN_EQUAL: + case IVY_SYM_FORWARD_SLASH_EQUAL: + case IVY_SYM_ASTERISK_EQUAL: + case IVY_SYM_AMPERSAND_EQUAL: + case IVY_SYM_PIPE_EQUAL: + case IVY_SYM_PERCENT_EQUAL: + case IVY_SYM_CARET_EQUAL: + case IVY_SYM_BANG_EQUAL: + ok = parse_binary_operator(parser, &ctx); + break; + case IVY_SYM_EQUAL_RIGHT_ANGLE: + done = true; + break; + case IVY_SYM_UNDERSCORE: + ok = parse_simple_operand(parser, &ctx); + break; + case IVY_SYM_COMMA: { + if (flags & EXPR_PARSE_STOP_COMMA) { + done = true; + break; + } + + struct ivy_ast_node *first = pop_operand( + &ctx, IVY_PRECEDENCE_KEYWORD_MSG); + if (!first) { + parse_trace( + parser, + "no valid item for tuple"); + return false; + } + + struct ivy_ast_node *v = NULL; + ok = parse_tuple(parser, first, &v); + if (!ok) { + break; + } + + fx_queue_push_back(&ctx.expr_out_queue, &v->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + break; + } + + case IVY_SYM_SEMICOLON: { + if (flags & EXPR_PARSE_STOP_SEMICOLON) { + done = true; + break; + } + + struct ivy_ast_node *first = pop_operand( + &ctx, IVY_PRECEDENCE_CASCADE); + if (!first) { + parse_trace( + parser, + "no valid recipient for " + "cascade"); + return false; + } + + struct ivy_ast_node *v = NULL; + ok = parse_cascade(parser, first, &v); + if (!ok) { + break; + } + + fx_queue_push_back(&ctx.expr_out_queue, &v->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + break; + } + + case IVY_SYM_LEFT_PAREN: { + if (ctx.expr_prev == EXPR_C_OPERAND) { + fx_queue_entry *entry = fx_queue_pop_back( + &ctx.expr_out_queue); + if (!entry) { + parse_trace( + parser, + "no valid recipient " + "for complex msg"); + return false; + } + + struct ivy_ast_node *target = fx_unbox( + struct ivy_ast_node, entry, + n_entry); + if (target->n_type == IVY_AST_MSG) { + ok = parse_complex_msg( + parser, target, &target); + } else { + ok = parse_call( + parser, target, &target); + } + + if (!ok) { + break; + } + + fx_queue_push_back( + &ctx.expr_out_queue, + &target->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + break; + } + + struct ivy_ast_node *subexpr = NULL; + discard_token(parser); + ok = parse_expr(parser, EXPR_PARSE_NORMAL, &subexpr); + if (!ok) { + break; + } + + if (!parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) { + parse_trace( + parser, + "expected `)` after " + "parenthesized " + "expression"); + ok = false; + break; + } + + fx_queue_push_back( + &ctx.expr_out_queue, &subexpr->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + break; + } + + case IVY_SYM_LEFT_BRACKET: { + if (flags & EXPR_PARSE_STOP_LEFT_BRACKET) { + done = true; + break; + } + + if (ctx.expr_prev == EXPR_C_OPERAND) { + struct ivy_ast_node *container = pop_operand( + &ctx, IVY_PRECEDENCE_SUBSCRIPT); + if (!container) { + parse_trace( + parser, + "invalid subscript " + "container"); + return false; + } + + struct ivy_ast_node *v = NULL; + ok = parse_index(parser, container, &v); + if (!ok) { + break; + } + + fx_queue_push_back( + &ctx.expr_out_queue, &v->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + break; + } + + struct ivy_ast_node *block = NULL; + ok = parse_block(parser, &block); + if (ok) { + fx_queue_push_back( + &ctx.expr_out_queue, + &block->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + } + break; + } + + case IVY_SYM_LEFT_BRACE: { + if (ctx.expr_prev == EXPR_C_OPERAND) { + parse_trace( + parser, + "package cannot be " + "used after " + "operand"); + ok = false; + break; + } + + struct ivy_ast_node *pkg = NULL; + ok = parse_package(parser, &pkg); + if (ok) { + fx_queue_push_back( + &ctx.expr_out_queue, &pkg->n_entry); + ctx.expr_prev = EXPR_C_OPERAND; + } + break; + } + case IVY_SYM_DOT: { + struct ivy_token *dot = tok; + struct ivy_token *next = peek_next_token(parser); + if (next && next->t_type == IVY_TOK_LINEFEED) { + if (flags & EXPR_PARSE_CONSUME_TERMINATOR) { + discard_token(parser); + } + + done = true; + break; + } + + ok = parse_binary_operator(parser, &ctx); + break; + } + case IVY_SYM_CARET: { + if (expr_is_empty(&ctx)) { + if (return_expr) { + parse_trace( + parser, + "`^` can only " + "be used " + "once in " + "an " + "expression"); + ok = false; + break; + } + + discard_token(parser); + return_expr = true; + break; + } + + ok = parse_binary_operator(parser, &ctx); + break; + } + case IVY_SYM_RIGHT_PAREN: + case IVY_SYM_RIGHT_BRACE: + case IVY_SYM_RIGHT_BRACKET: + done = true; + break; + default: + parse_trace( + parser, "unrecognised symbol %s", + ivy_symbol_to_string(tok->t_symbol)); + ok = false; + break; + } + break; + default: + parse_trace( + parser, "unrecognised token %s", + ivy_lex_token_type_to_string(tok->t_type)); + ok = false; + break; + } + + if (!ok) { + break; + } + } + + if (!ok) { + cleanup_expr(&ctx); + return false; + } + + ok = finalise_expr(&ctx, out, IVY_PRECEDENCE_ASSIGN); + if (!ok) { + cleanup_expr(&ctx); + return false; + } + + if (return_expr) { + struct ivy_ast_return_node *ret = create_node(IVY_AST_RETURN); + ret->n_val = *out; + *out = generic_node(ret); + } + + return true; +} diff --git a/lang/parse/for.c b/lang/parse/for.c new file mode 100644 index 0000000..b5e4370 --- /dev/null +++ b/lang/parse/for.c @@ -0,0 +1,67 @@ +#include "ctx.h" + +#include + +bool parse_for(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_FOR)) { + parse_trace(parser, "expected `for` keyword"); + return false; + } + + struct ivy_ast_for_loop_node *for_node = create_node(IVY_AST_FOR_LOOP); + + if (!parse_expr(parser, EXPR_PARSE_STOP_KW_IN, &for_node->n_iterator)) { + parse_trace(parser, "invalid for-loop iterator"); + return false; + } + + if (!parse_keyword(parser, IVY_KW_IN)) { + parse_trace(parser, "expected `in` after for-loop iterator"); + return false; + } + + if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &for_node->n_iterable)) { + parse_trace(parser, "invalid for-loop iterable"); + return false; + } + + if (!parse_block(parser, &for_node->n_body)) { + parse_trace(parser, "invalid for-loop body"); + return false; + } + + *out = generic_node(for_node); + return true; +} + +bool parse_for_inline( + struct ivy_parser *parser, struct ivy_ast_node *body, + struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_FOR)) { + parse_trace(parser, "expected `for` keyword"); + return false; + } + + struct ivy_ast_for_loop_node *for_node = create_node(IVY_AST_FOR_LOOP); + for_node->n_body = body; + + if (!parse_expr(parser, EXPR_PARSE_STOP_KW_IN, &for_node->n_iterator)) { + parse_trace(parser, "invalid for-loop iterator"); + return false; + } + + if (!parse_keyword(parser, IVY_KW_IN)) { + parse_trace(parser, "expected `in` after for-loop iterator"); + return false; + } + + if (!parse_expr(parser, EXPR_PARSE_NORMAL, &for_node->n_iterable)) { + parse_trace(parser, "invalid for-loop iterable"); + return false; + } + + *out = generic_node(for_node); + return true; +} diff --git a/lang/parse/fstring.c b/lang/parse/fstring.c new file mode 100644 index 0000000..b3722a8 --- /dev/null +++ b/lang/parse/fstring.c @@ -0,0 +1,64 @@ +#include "ctx.h" + +#include + +bool parse_fstring(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_str_start(parser)) { + parse_trace(parser, "expected STR_START"); + return false; + } + + struct ivy_ast_fstring_node *fstring = create_node(IVY_AST_FSTRING); + bool ok = true; + + while (1) { + if (parse_str_end(parser)) { + break; + } + + struct ivy_token *tok = NULL; + if (parse_string(parser, &tok)) { + struct ivy_ast_string_node *string + = create_node(IVY_AST_STRING); + string->n_value = tok; + fx_queue_push_back( + &fstring->n_value, &string->n_base.n_entry); + continue; + } + + if (parse_symbol(parser, IVY_SYM_LEFT_BRACE)) { + struct ivy_ast_node *expr = NULL; + if (!parse_expr(parser, EXPR_PARSE_NORMAL, &expr)) { + parse_trace( + parser, + "invalid expression in fstring"); + ok = false; + break; + } + + if (!parse_symbol(parser, IVY_SYM_RIGHT_BRACE)) { + parse_trace( + parser, + "expected `}` after expression in " + "fstring"); + ok = false; + break; + } + + fx_queue_push_back(&fstring->n_value, &expr->n_entry); + continue; + } + + parse_trace(parser, "unexpected token in fstring"); + ok = false; + break; + } + + if (!ok) { + return ok; + } + + *out = generic_node(fstring); + return ok; +} diff --git a/lang/parse/if-else.c b/lang/parse/if-else.c new file mode 100644 index 0000000..35db6a3 --- /dev/null +++ b/lang/parse/if-else.c @@ -0,0 +1,99 @@ +#include "ctx.h" + +#include + +bool parse_if(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_IF)) { + parse_trace(parser, "expected `if` keyword"); + return false; + } + + struct ivy_ast_cond_group_node *cond_group + = create_node(IVY_AST_COND_GROUP); + struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND); + + if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &cond->n_cond)) { + parse_trace(parser, "invalid if predicate"); + return false; + } + + if (!parse_block(parser, &cond->n_body)) { + parse_trace(parser, "invalid if body"); + return false; + } + + fx_queue_push_back(&cond_group->n_branches, &cond->n_base.n_entry); + + bool ok = true; + while (1) { + struct ivy_ast_node *branch_pred = NULL; + struct ivy_ast_node *branch_block = NULL; + if (parse_keyword(parser, IVY_KW_ELIF)) { + if (!parse_expr( + parser, EXPR_PARSE_STOP_LEFT_BRACKET, + &branch_pred)) { + parse_trace( + parser, + "invalid elif branch predicate"); + ok = false; + break; + } + } else if (!parse_keyword(parser, IVY_KW_ELSE)) { + break; + } + + if (!parse_block(parser, &branch_block)) { + parse_trace(parser, "invalid branch body"); + ok = false; + break; + } + + struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND); + cond->n_cond = branch_pred; + cond->n_body = branch_block; + fx_queue_push_back(&cond_group->n_branches, &cond->n_base.n_entry); + + if (!branch_pred) { + break; + } + } + + *out = generic_node(cond_group); + return true; +} + +bool parse_if_inline( + struct ivy_parser *parser, struct ivy_ast_node *body, + struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_IF)) { + parse_trace(parser, "expected `if` keyword"); + return false; + } + + struct ivy_ast_cond_group_node *cond_group + = create_node(IVY_AST_COND_GROUP); + struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND); + cond->n_body = body; + + if (!parse_expr(parser, EXPR_PARSE_NORMAL, &cond->n_cond)) { + parse_trace(parser, "invalid if predicate"); + return false; + } + + fx_queue_push_back(&cond_group->n_branches, &cond->n_base.n_entry); + + if (parse_keyword(parser, IVY_KW_ELSE)) { + struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND); + if (!parse_expr(parser, EXPR_PARSE_NORMAL, &cond->n_body)) { + parse_trace(parser, "invalid else body"); + return false; + } + + fx_queue_push_back(&cond_group->n_branches, &cond->n_base.n_entry); + } + + *out = generic_node(cond_group); + return true; +} diff --git a/lang/parse/index.c b/lang/parse/index.c new file mode 100644 index 0000000..e7c1b9d --- /dev/null +++ b/lang/parse/index.c @@ -0,0 +1,37 @@ +#include "ctx.h" + +#include + +bool parse_index( + struct ivy_parser *parser, struct ivy_ast_node *container, + struct ivy_ast_node **out) +{ + if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) { + parse_trace(parser, "expected `[` before subscript value"); + return false; + } + + struct ivy_ast_node *subscript = NULL; + if (!parse_expr(parser, EXPR_PARSE_NORMAL, &subscript)) { + parse_trace(parser, "invalid subscript value"); + return false; + } + + if (!parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) { + parse_trace(parser, "expected `]` after subscript value"); + return false; + } + + struct ivy_ast_op_node *op_node = create_node(IVY_AST_OP); + if (!op_node) { + return false; + } + + op_node->n_op = ivy_operator_get_by_id(IVY_OP_SUBSCRIPT); + op_node->n_left = container; + op_node->n_right = subscript; + + *out = generic_node(op_node); + + return true; +} diff --git a/lang/parse/keyword.c b/lang/parse/keyword.c new file mode 100644 index 0000000..965dacc --- /dev/null +++ b/lang/parse/keyword.c @@ -0,0 +1,31 @@ +#include "ctx.h" + +bool peek_keyword(struct ivy_parser *parser, enum ivy_keyword kw) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok || tok->t_type != IVY_TOK_KEYWORD) { + return false; + } + + if (tok->t_keyword != kw) { + return false; + } + + return true; +} + +bool parse_keyword(struct ivy_parser *parser, enum ivy_keyword kw) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok || tok->t_type != IVY_TOK_KEYWORD) { + return false; + } + + if (tok->t_keyword != kw) { + return false; + } + + parse_token(parser); + ivy_token_destroy(tok); + return true; +} diff --git a/lang/parse/label.c b/lang/parse/label.c new file mode 100644 index 0000000..b59f6be --- /dev/null +++ b/lang/parse/label.c @@ -0,0 +1,18 @@ +#include "ctx.h" + +bool peek_label(struct ivy_parser *parser) +{ + struct ivy_token *tok = peek_token(parser); + return (!tok || tok->t_type == IVY_TOK_LABEL); +} + +bool parse_label(struct ivy_parser *parser, struct ivy_token **out) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok || tok->t_type != IVY_TOK_LABEL) { + return false; + } + + *out = parse_token(parser); + return true; +} diff --git a/lang/parse/linefeed.c b/lang/parse/linefeed.c new file mode 100644 index 0000000..3cc0c44 --- /dev/null +++ b/lang/parse/linefeed.c @@ -0,0 +1,19 @@ +#include "ctx.h" + +bool peek_linefeed(struct ivy_parser *parser) +{ + struct ivy_token *tok = peek_token(parser); + return (tok && tok->t_type == IVY_TOK_LINEFEED); +} + +bool parse_linefeed(struct ivy_parser *parser) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok || tok->t_type != IVY_TOK_LINEFEED) { + return false; + } + + ivy_lexer_read(parser->p_src); + ivy_token_destroy(tok); + return true; +} diff --git a/lang/parse/match.c b/lang/parse/match.c new file mode 100644 index 0000000..c312cc7 --- /dev/null +++ b/lang/parse/match.c @@ -0,0 +1,75 @@ +#include "ctx.h" + +#include + +bool parse_match(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_MATCH)) { + parse_trace(parser, "expected `match` keyword"); + return false; + } + + struct ivy_ast_match_node *match = create_node(IVY_AST_MATCH); + + if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &match->n_cond)) { + parse_trace(parser, "invalid match predicate"); + return false; + } + + if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) { + parse_trace(parser, "expected `[` after match predicate"); + return false; + } + + bool ok = true; + while (1) { + if (parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) { + break; + } + + if (!fx_queue_empty(&match->n_branches) + && !parse_symbol(parser, IVY_SYM_COMMA)) { + parse_trace( + parser, + "expected `,` or `]` after match branch value"); + ok = false; + break; + } + + struct ivy_ast_node *branch_pred = NULL; + struct ivy_ast_node *branch_value = NULL; + if (!parse_expr(parser, EXPR_PARSE_NORMAL, &branch_pred)) { + parse_trace(parser, "invalid match branch predicate"); + ok = false; + break; + } + + if (!parse_symbol(parser, IVY_SYM_EQUAL_RIGHT_ANGLE)) { + parse_trace( + parser, + "expected `=>` after match branch predicate"); + ok = false; + break; + } + + if (peek_symbol(parser, IVY_SYM_LEFT_BRACKET)) { + ok = parse_block(parser, &branch_value); + } else { + ok = parse_expr( + parser, EXPR_PARSE_STOP_COMMA, &branch_value); + } + + if (!ok) { + parse_trace(parser, "invalid match branch value"); + break; + } + + struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND); + cond->n_cond = branch_pred; + cond->n_body = branch_value; + fx_queue_push_back(&match->n_branches, &cond->n_base.n_entry); + } + + *out = generic_node(match); + return true; +} diff --git a/lang/parse/msg.c b/lang/parse/msg.c new file mode 100644 index 0000000..c88a680 --- /dev/null +++ b/lang/parse/msg.c @@ -0,0 +1,143 @@ +#include "ctx.h" + +#include + +bool parse_unary_msg( + struct ivy_parser *parser, struct ivy_ast_node *recipient, + struct ivy_ast_node **out) +{ + struct ivy_token *selector_tok = NULL; + if (!parse_word(parser, &selector_tok)) { + parse_trace(parser, "expected unary message selector"); + return false; + } + + struct ivy_ast_selector_node *sel = create_node(IVY_AST_SELECTOR); + sel->n_msg_name = selector_tok; + + struct ivy_ast_msg_node *msg = create_node(IVY_AST_MSG); + msg->n_sel = sel; + msg->n_recipient = recipient; + + *out = generic_node(msg); + + return true; +} + +bool parse_keyword_msg( + struct ivy_parser *parser, struct ivy_ast_node *recipient, + enum expr_parse_flags flags, struct ivy_ast_node **out) +{ +#if 0 + if (!recipient) { + recipient = pop_operand(expr, IVY_PRECEDENCE_KEYWORD_MSG); + } + + if (!recipient) { + parse_trace(parser, "no valid recipient for keyword msg"); + return false; + } +#endif + + struct ivy_ast_selector_node *sel = create_node(IVY_AST_SELECTOR); + struct ivy_ast_msg_node *msg = create_node(IVY_AST_MSG); + msg->n_recipient = recipient; + msg->n_sel = sel; + + bool ok = true; + + while (1) { + struct ivy_token *label = NULL; + if (!parse_label(parser, &label)) { + break; + } + + struct ivy_ast_node *value = NULL; + flags |= EXPR_PARSE_STOP_LABEL; + flags |= EXPR_PARSE_STOP_SEMICOLON; + flags |= EXPR_PARSE_STOP_KW_CONTROL; + flags &= ~EXPR_PARSE_CONSUME_TERMINATOR; + + if (!parse_expr(parser, flags, &value)) { + parse_trace(parser, "invalid keyword msg arg value"); + ok = false; + break; + } + + fx_queue_push_back(&sel->n_arg_labels, &label->t_entry); + fx_queue_push_back(&msg->n_arg, &value->n_entry); + } + + *out = generic_node(msg); + return true; +} + +bool parse_complex_msg( + struct ivy_parser *parser, struct ivy_ast_node *msg_node, + struct ivy_ast_node **out) +{ + if (!parse_symbol(parser, IVY_SYM_LEFT_PAREN)) { + parse_trace(parser, "expected `(` before complex msg arg list"); + return false; + } + +#if 0 + if (!msg) { + fx_queue_entry *entry = fx_queue_pop_back(&expr->expr_out_queue); + if (!entry) { + parse_trace( + parser, "no valid recipient for complex msg"); + return false; + } + + msg = fx_unbox(struct ivy_ast_msg_node, entry, n_base.n_entry); + if (msg->n_base.n_type != IVY_AST_MSG) { + parse_trace( + parser, + "previous expression is not a unary message"); + return false; + } + } +#endif + + struct ivy_ast_msg_node *msg = (struct ivy_ast_msg_node *)msg_node; + struct ivy_ast_selector_node *sel = msg->n_sel; + msg->n_sel = sel; + + bool ok = true; + + while (1) { + struct ivy_token *label = NULL; + if (parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) { + break; + } + + if (!fx_queue_empty(&msg->n_arg) + && !parse_symbol(parser, IVY_SYM_COMMA)) { + parse_trace( + parser, "expected `,` after complex msg arg"); + ok = false; + break; + } + + if (parse_label(parser, &label)) { + fx_queue_push_back(&sel->n_arg_labels, &label->t_entry); + } else { + label = ivy_token_create_discard(); + fx_queue_push_back(&sel->n_arg_labels, &label->t_entry); + } + + struct ivy_ast_node *value = NULL; + if (!parse_expr(parser, EXPR_PARSE_STOP_COMMA, &value)) { + parse_trace(parser, "invalid complex msg arg value"); + ok = false; + break; + } + + fx_queue_push_back(&msg->n_arg, &value->n_entry); + } + + *out = generic_node(msg); + + return true; +} diff --git a/lang/parse/operator.c b/lang/parse/operator.c new file mode 100644 index 0000000..17b67af --- /dev/null +++ b/lang/parse/operator.c @@ -0,0 +1,43 @@ +#include "ctx.h" + +#include +#include + +const struct ivy_operator *get_operator_from_token(struct ivy_token *tok) +{ + switch (tok->t_type) { + case IVY_TOK_SYMBOL: + return ivy_operator_get_by_token(tok->t_symbol); + case IVY_TOK_KEYWORD: + return ivy_operator_get_by_token(tok->t_keyword); + default: + return ivy_operator_get_by_token(tok->t_type); + } +} + +struct ivy_ast_node *create_operator_node_from_token(struct ivy_token *tok) +{ + const struct ivy_operator *op = get_operator_from_token(tok); + if (!op) { + return NULL; + } + + struct ivy_ast_op_node *op_node = create_node(IVY_AST_OP); + op_node->n_op = op; + ivy_ast_node_set_bounds_from_token(generic_node(op_node), tok); + return generic_node(op_node); +} + +const struct ivy_operator *get_operator_from_node(struct ivy_ast_node *n) +{ + switch (n->n_type) { + case IVY_AST_OP: { + struct ivy_ast_op_node *op = (struct ivy_ast_op_node *)n; + return op->n_op; + } + case IVY_AST_MSG: + return ivy_operator_get_by_id(IVY_OP_MSG); + default: + return NULL; + } +} diff --git a/lang/parse/package-id.c b/lang/parse/package-id.c new file mode 100644 index 0000000..c8177fa --- /dev/null +++ b/lang/parse/package-id.c @@ -0,0 +1,49 @@ +#include "ctx.h" + +#include + +bool parse_package_id(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_PACKAGE)) { + parse_trace(NULL, "expected `package` before package statement"); + return false; + } + + struct ivy_ast_unit_package_node *unit_pkg + = create_node(IVY_AST_UNIT_PACKAGE); + + struct ivy_token *tok = NULL; + if (!parse_word(parser, &tok)) { + parse_trace(NULL, "expected word after `package` keyword"); + return false; + } + + fx_queue_push_back(&unit_pkg->n_ident, &tok->t_entry); + + while (1) { + if (parse_linefeed(parser)) { + break; + } + + if (!parse_symbol(parser, IVY_SYM_DOT)) { + parse_trace( + NULL, + "expected linefeed or `.` after package " + "identifier word"); + destroy_node(unit_pkg); + return false; + } + + if (!parse_word(parser, &tok)) { + parse_trace( + NULL, "expected word after `package` keyword"); + destroy_node(unit_pkg); + return false; + } + + fx_queue_push_back(&unit_pkg->n_ident, &tok->t_entry); + } + + *out = generic_node(unit_pkg); + return true; +} diff --git a/lang/parse/package-import.c b/lang/parse/package-import.c new file mode 100644 index 0000000..859c85b --- /dev/null +++ b/lang/parse/package-import.c @@ -0,0 +1,49 @@ +#include "ctx.h" + +#include + +bool parse_package_import(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_USE)) { + parse_trace( + NULL, "expected `use` before package import statement"); + return false; + } + + struct ivy_ast_unit_import_node *unit_import + = create_node(IVY_AST_UNIT_IMPORT); + + struct ivy_token *tok = NULL; + if (!parse_word(parser, &tok)) { + parse_trace(NULL, "expected word after `use` keyword"); + return false; + } + + fx_queue_push_back(&unit_import->n_ident, &tok->t_entry); + + while (1) { + if (parse_linefeed(parser)) { + break; + } + + if (!parse_symbol(parser, IVY_SYM_DOT)) { + parse_trace( + NULL, + "expected linefeed or `.` after package " + "identifier word"); + destroy_node(unit_import); + return false; + } + + if (!parse_word(parser, &tok)) { + parse_trace(NULL, "expected word after `use` keyword"); + destroy_node(unit_import); + return false; + } + + fx_queue_push_back(&unit_import->n_ident, &tok->t_entry); + } + + *out = generic_node(unit_import); + return true; +} diff --git a/lang/parse/package.c b/lang/parse/package.c new file mode 100644 index 0000000..754f00f --- /dev/null +++ b/lang/parse/package.c @@ -0,0 +1,101 @@ +#include "ctx.h" + +#include + +static bool parse_dynamic_package( + struct ivy_parser *parser, struct ivy_ast_node *expr, + struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_FOR)) { + parse_trace( + parser, + "expected `for` after package comprehension " + "expression"); + return false; + } + + struct ivy_ast_pkg_dynamic_node *pkg = create_node(IVY_AST_PKG_DYNAMIC); + pkg->n_transform = expr; + + if (!parse_expr(parser, EXPR_PARSE_STOP_KW_IN, &pkg->n_item)) { + parse_trace(parser, "invalid package comprehension item"); + return false; + } + + if (!parse_keyword(parser, IVY_KW_IN)) { + parse_trace( + parser, + "expected `in` after package comprehension item"); + return false; + } + + if (!parse_expr(parser, EXPR_PARSE_NORMAL, &pkg->n_item)) { + parse_trace(parser, "invalid package comprehension container"); + return false; + } + + if (!parse_symbol(parser, IVY_SYM_RIGHT_BRACE)) { + parse_trace( + parser, + "expected `}` after package comprehension container"); + return false; + } + + *out = generic_node(pkg); + return true; +} + +bool parse_package(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_symbol(parser, IVY_SYM_LEFT_BRACE)) { + parse_trace(parser, "expected `{`"); + return false; + } + + struct ivy_ast_node *item = NULL; + if (!parse_expr( + parser, EXPR_PARSE_STOP_COMMA | EXPR_PARSE_STOP_KW_CONTROL, + &item)) { + parse_trace(parser, "invalid package item"); + return false; + } + + if (peek_keyword(parser, IVY_KW_FOR)) { + return parse_dynamic_package(parser, item, out); + } + + struct ivy_ast_pkg_static_node *pkg = create_node(IVY_AST_PKG_STATIC); + if (item) { + fx_queue_push_back(&pkg->n_items, &item->n_entry); + } + + bool ok = true; + while (ok) { + parse_linefeed(parser); + + if (parse_symbol(parser, IVY_SYM_RIGHT_BRACE)) { + break; + } + + if (!parse_symbol(parser, IVY_SYM_COMMA)) { + parse_trace( + parser, + "expected `,` or `}` after package item"); + ok = false; + break; + } + + if (!parse_expr( + parser, + EXPR_PARSE_STOP_COMMA | EXPR_PARSE_STOP_KW_CONTROL, + &item)) { + parse_trace(parser, "invalid package item"); + return false; + } + + fx_queue_push_back(&pkg->n_items, &item->n_entry); + } + + *out = generic_node(pkg); + return true; +} diff --git a/lang/parse/string.c b/lang/parse/string.c new file mode 100644 index 0000000..981fd1d --- /dev/null +++ b/lang/parse/string.c @@ -0,0 +1,36 @@ +#include "ctx.h" + +bool parse_string(struct ivy_parser *parser, struct ivy_token **out) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok || tok->t_type != IVY_TOK_STRING) { + return false; + } + + *out = parse_token(parser); + return true; +} + +bool parse_str_start(struct ivy_parser *parser) +{ + struct ivy_token *tok = peek_token(parser); + if (tok->t_type != IVY_TOK_STR_START) { + return false; + } + + parse_token(parser); + ivy_token_destroy(tok); + return true; +} + +bool parse_str_end(struct ivy_parser *parser) +{ + struct ivy_token *tok = peek_token(parser); + if (tok->t_type != IVY_TOK_STR_END) { + return false; + } + + parse_token(parser); + ivy_token_destroy(tok); + return true; +} diff --git a/lang/parse/symbol.c b/lang/parse/symbol.c new file mode 100644 index 0000000..f92c428 --- /dev/null +++ b/lang/parse/symbol.c @@ -0,0 +1,31 @@ +#include "ctx.h" + +bool peek_symbol(struct ivy_parser *parser, enum ivy_symbol sym) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok || tok->t_type != IVY_TOK_SYMBOL) { + return false; + } + + if (tok->t_symbol != sym) { + return false; + } + + return true; +} + +bool parse_symbol(struct ivy_parser *parser, enum ivy_symbol sym) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok || tok->t_type != IVY_TOK_SYMBOL) { + return false; + } + + if (tok->t_symbol != sym) { + return false; + } + + parse_token(parser); + ivy_token_destroy(tok); + return true; +} diff --git a/lang/parse/try-catch.c b/lang/parse/try-catch.c new file mode 100644 index 0000000..d851849 --- /dev/null +++ b/lang/parse/try-catch.c @@ -0,0 +1,49 @@ +#include "ctx.h" + +#include + +bool parse_try(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_TRY)) { + parse_trace(parser, "expected `try` keyword"); + return false; + } + + struct ivy_ast_try_node *try = create_node(IVY_AST_TRY); + + if (!parse_expr(parser, EXPR_PARSE_STOP_KW_CONTROL, &try->n_try)) { + parse_trace(parser, "invalid try block"); + return false; + } + + bool ok = true; + while (1) { + if (!parse_keyword(parser, IVY_KW_CATCH)) { + break; + } + + struct ivy_ast_node *catch_guard = NULL; + struct ivy_ast_node *catch_block = NULL; + + if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &catch_guard)) { + parse_trace(parser, "invalid catch guard"); + ok = false; + break; + } + + if (!parse_block(parser, &catch_block)) { + parse_trace(parser, "invalid catch block"); + ok = false; + break; + } + + struct ivy_ast_try_catch_node *catch + = create_node(IVY_AST_TRY_CATCH); + catch->n_pattern = catch_guard; + catch->n_block = catch_block; + fx_queue_push_back(&try->n_catch, &catch->n_base.n_entry); + } + + *out = generic_node(try); + return true; +} diff --git a/lang/parse/tuple.c b/lang/parse/tuple.c new file mode 100644 index 0000000..8f24fdf --- /dev/null +++ b/lang/parse/tuple.c @@ -0,0 +1,75 @@ +#include "ctx.h" + +#include + +bool is_tuple_terminator(struct ivy_token *tok) +{ + const struct ivy_operator *op = get_operator_from_token(tok); + switch (tok->t_type) { + case IVY_TOK_SYMBOL: + switch (tok->t_symbol) { + case IVY_SYM_DOT: + case IVY_SYM_RIGHT_PAREN: + case IVY_SYM_RIGHT_BRACE: + case IVY_SYM_RIGHT_BRACKET: + return true; + default: + op = get_operator_from_token(tok); + break; + } + break; + default: + break; + } + + if (op && op->op_precedence < IVY_PRECEDENCE_KEYWORD_MSG) { + return true; + } + + return false; +} + +bool parse_tuple( + struct ivy_parser *parser, struct ivy_ast_node *first_item, + struct ivy_ast_node **out) +{ + struct ivy_ast_tuple_node *tuple = create_node(IVY_AST_TUPLE); + fx_queue_push_back(&tuple->n_members, &first_item->n_entry); + + bool ok = true; + bool done = false; + while (!done) { + struct ivy_token *tok = peek_token(parser); + if (!tok) { + parse_trace( + parser, "unexpected EOF while parsing tuple"); + ok = false; + break; + } + + if (is_tuple_terminator(tok)) { + break; + } + + if (!parse_symbol(parser, IVY_SYM_COMMA)) { + parse_trace(parser, "expected `,` after tuple item"); + ok = false; + break; + } + + struct ivy_ast_node *value = NULL; + if (!parse_expr( + parser, + EXPR_PARSE_STOP_COMMA | EXPR_PARSE_STOP_TUPLE_TERMINATOR, + &value)) { + parse_trace(parser, "invalid tuple item"); + ok = false; + break; + } + + fx_queue_push_back(&tuple->n_members, &value->n_entry); + } + + *out = generic_node(tuple); + return true; +} diff --git a/lang/parse/unit.c b/lang/parse/unit.c new file mode 100644 index 0000000..79dda06 --- /dev/null +++ b/lang/parse/unit.c @@ -0,0 +1,50 @@ +#include "ctx.h" + +#include + +bool parse_unit(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + struct ivy_ast_unit_node *unit + = (struct ivy_ast_unit_node *)ivy_ast_node_create(IVY_AST_UNIT); + if (!unit) { + parser->p_status = IVY_ERR_NO_MEMORY; + return false; + } + + bool result = true; + bool prev_was_expr = false; + while (1) { + struct ivy_ast_node *child = NULL; + + if (parse_eof(parser)) { + break; + } + + if (parse_linefeed(parser)) { + continue; + } + + if (peek_keyword(parser, IVY_KW_PACKAGE)) { + result = parse_package_id(parser, &child); + } else if (peek_keyword(parser, IVY_KW_USE)) { + result = parse_package_import(parser, &child); + } else if (peek_keyword(parser, IVY_KW_CLASS)) { + result = parse_class(parser, &child); + } else if (peek_expr_start(parser)) { + result = parse_expr( + parser, EXPR_PARSE_CONSUME_TERMINATOR, &child); + } else { + parse_trace(parser, "unexpected token"); + result = false; + } + + if (!result || !child) { + break; + } + + fx_queue_push_back(&unit->n_children, &child->n_entry); + } + + *out = generic_node(unit); + return result; +} diff --git a/lang/parse/while.c b/lang/parse/while.c new file mode 100644 index 0000000..b1936a1 --- /dev/null +++ b/lang/parse/while.c @@ -0,0 +1,49 @@ +#include "ctx.h" + +#include + +bool parse_while(struct ivy_parser *parser, struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_WHILE)) { + parse_trace(parser, "expected `while` keyword"); + return false; + } + + struct ivy_ast_while_loop_node *while_node + = create_node(IVY_AST_WHILE_LOOP); + + if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &while_node->n_cond)) { + parse_trace(parser, "invalid while condition"); + return false; + } + + if (!parse_block(parser, &while_node->n_body)) { + parse_trace(parser, "invalid while body"); + return false; + } + + *out = generic_node(while_node); + return true; +} + +bool parse_while_inline( + struct ivy_parser *parser, struct ivy_ast_node *body, + struct ivy_ast_node **out) +{ + if (!parse_keyword(parser, IVY_KW_WHILE)) { + parse_trace(parser, "expected `while` keyword"); + return false; + } + + struct ivy_ast_while_loop_node *while_node + = create_node(IVY_AST_WHILE_LOOP); + while_node->n_body = body; + + if (!parse_expr(parser, EXPR_PARSE_NORMAL, &while_node->n_cond)) { + parse_trace(parser, "invalid while condition"); + return false; + } + + *out = generic_node(while_node); + return true; +} diff --git a/lang/parse/word.c b/lang/parse/word.c new file mode 100644 index 0000000..d2829ff --- /dev/null +++ b/lang/parse/word.c @@ -0,0 +1,18 @@ +#include "ctx.h" + +bool peek_word(struct ivy_parser *parser) +{ + struct ivy_token *tok = peek_token(parser); + return (!tok || tok->t_type == IVY_TOK_IDENT); +} + +bool parse_word(struct ivy_parser *parser, struct ivy_token **out) +{ + struct ivy_token *tok = peek_token(parser); + if (!tok || tok->t_type != IVY_TOK_IDENT) { + return false; + } + + *out = parse_token(parser); + return true; +}