diff --git a/lang/ast/block.c b/lang/ast/block.c index ae66747..b6cc522 100644 --- a/lang/ast/block.c +++ b/lang/ast/block.c @@ -16,8 +16,26 @@ static struct token_parse_result parse_end( struct ivy_ast_block_node *node = (struct ivy_ast_block_node *)(state->s_base.s_node); + int flags = 0; + if (state->s_terminator == IVY_KW_END) { + flags = PARSE_REPEAT_TOKEN; + } + parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); + 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_bang( @@ -46,7 +64,7 @@ static struct token_parse_result parse_expr_begin( struct ivy_ast_block_node *node = (struct ivy_ast_block_node *)(state->s_base.s_node); - parser_push_state(ctx, IVY_AST_EXPR); + parser_push_state(ctx, IVY_AST_EXPR, 0); return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } @@ -61,7 +79,7 @@ static enum ivy_status add_child( return IVY_OK; } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp) +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; } @@ -86,6 +104,7 @@ struct ast_node_type block_node_ops = { .n_node_size = sizeof(struct ivy_ast_block_node), .n_keyword_parsers = { KW_PARSER(END, parse_end), + KW_PARSER(ELSE, parse_else), }, .n_symbol_parsers = { SYM_PARSER(BANG, parse_bang), diff --git a/lang/ast/class.c b/lang/ast/class.c index c44e6be..fa4d5da 100644 --- a/lang/ast/class.c +++ b/lang/ast/class.c @@ -25,7 +25,7 @@ static struct token_parse_result parse_dollar( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - parser_push_state(ctx, IVY_AST_PROPERTY); + parser_push_state(ctx, IVY_AST_PROPERTY, 0); return PARSE_RESULT(IVY_OK, 0); } @@ -39,7 +39,7 @@ static struct token_parse_result parse_plus( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - parser_push_state(ctx, IVY_AST_MSGH); + 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; @@ -57,7 +57,7 @@ static struct token_parse_result parse_hyphen( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - parser_push_state(ctx, IVY_AST_MSGH); + 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; @@ -150,7 +150,7 @@ static void print(struct ivy_ast_node *node) c->n_ident->t_str); } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp) +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; diff --git a/lang/ast/cond.c b/lang/ast/cond.c new file mode 100644 index 0000000..f8711f8 --- /dev/null +++ b/lang/ast/cond.c @@ -0,0 +1,343 @@ +#include "cond.h" +#include "block.h" +#include "expr/expr.h" + +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; +} + +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_type = COND_GROUP_INLINE_IF_ELSE; + state->s_cur_branch->n_body = state->s_prev_node; + state->s_prev_node = NULL; + } else { + state->s_type = COND_GROUP_IF_ELSE; + } + + 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); +} + +static enum ivy_status flush_current_branch(struct cond_group_parser_state *state) +{ + if (!state->s_cur_branch) { + return IVY_ERR_INTERNAL_FAILURE; + } + + b_queue_push_back(&state->s_branches, &state->s_cur_branch->n_base.n_entry); + + state->s_cur_branch + = (struct ivy_ast_cond_node *)ast_node_create(IVY_AST_COND); + + if (!state->s_cur_branch) { + return IVY_ERR_NO_MEMORY; + } + + return IVY_OK; +} + +struct token_parse_result parse_then(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_type != COND_GROUP_IF_ELSE) { + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); + } + + if (state->s_prev_token != IVY_KW_IF) { + 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 expr_parser_state *)parser_push_state( + ctx, IVY_AST_BLOCK, 0); + /* set the sub-expression depth to be non-zero so the expression parser doesn't consume the expression separator. */ + block->s_terminator = IVY_KW_END; + + state->s_prev_token = IVY_KW_THEN; + return PARSE_RESULT(IVY_OK, 0); +} + +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); + } + + switch (state->s_type) { + case COND_GROUP_IF_ELSE: + /* 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 either be an if keyword or a block. */ + break; + case COND_GROUP_INLINE_IF_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; + break; + default: + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); + } + + state->s_prev_token = IVY_KW_ELSE; + return PARSE_RESULT(IVY_OK, 0); +} + +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->s_terminator = 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; + + switch (state->s_type) { + case COND_GROUP_INLINE_IF_ELSE: + /* 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 = B_QUEUE_INIT; + return IVY_OK; + case COND_GROUP_IF_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 = B_QUEUE_INIT; + return IVY_OK; + default: + return IVY_ERR_NOT_SUPPORTED; + } +} + +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_type != COND_GROUP_INLINE_IF_ELSE) { + /* 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); +} + +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); + + if (state->s_type == COND_GROUP_INLINE_IF_ELSE) { + /* inline if-else must be terminateed 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, 0); +} + +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; +} + +static void cond_group_collect_children( + struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) +{ + struct ivy_ast_cond_group_node *group + = (struct ivy_ast_cond_group_node *)node; + + b_queue_iterator it = {0}; + b_queue_foreach (&it, &group->n_branches) { + struct ivy_ast_node *branch = b_unbox(struct ivy_ast_node, it.entry, n_entry); + ast_node_iterator_enqueue_node(iterator, node, branch); + } +} + +static void cond_collect_children( + struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) +{ + struct ivy_ast_cond_node *cond = (struct ivy_ast_cond_node *)node; + + if (cond->n_cond) { + ast_node_iterator_enqueue_node(iterator, node, cond->n_cond); + } + + if (cond->n_body) { + ast_node_iterator_enqueue_node(iterator, node, cond->n_body); + } +} + +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(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/cond.h b/lang/ast/cond.h new file mode 100644 index 0000000..bb49068 --- /dev/null +++ b/lang/ast/cond.h @@ -0,0 +1,25 @@ +#ifndef _AST_COND_H_ +#define _AST_COND_H_ + +#include "ctx.h" +#include "node.h" + +enum cond_group_type { + COND_GROUP_NONE = 0, + COND_GROUP_IF_ELSE, + COND_GROUP_INLINE_IF_ELSE, + COND_GROUP_MATCH, +}; + +struct cond_group_parser_state { + struct parser_state s_base; + enum cond_group_type s_type; + unsigned int s_prev_token; + + struct ivy_ast_cond_node *s_cur_branch; + b_queue s_branches; + + struct ivy_ast_node *s_prev_node; +}; + +#endif \ No newline at end of file diff --git a/lang/ast/ctx.c b/lang/ast/ctx.c index b9a3239..11d0100 100644 --- a/lang/ast/ctx.c +++ b/lang/ast/ctx.c @@ -29,7 +29,7 @@ enum ivy_status ivy_parser_create(struct ivy_parser **parser) memset(out, 0x0, sizeof *out); - parser_push_state(out, IVY_AST_UNIT); + parser_push_state(out, IVY_AST_UNIT, 0); *parser = out; return IVY_OK; @@ -116,7 +116,7 @@ struct parser_state *parser_get_parent_state_generic(struct ivy_parser *parser, } struct parser_state *parser_push_state( - struct ivy_parser *parser, enum ivy_ast_node_type type) + 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) { @@ -141,7 +141,7 @@ struct parser_state *parser_push_state( b_queue_push_back(&parser->p_state, &state->s_entry); if (node_type->n_init_state) { - node_type->n_init_state(parser, state); + node_type->n_init_state(parser, state, arg); } printf("states (after push)\n"); @@ -159,7 +159,7 @@ void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags) struct parser_state *state = b_unbox(struct parser_state, entry, s_entry); b_queue_pop_back(&parser->p_state); - if (state && (flags & STATE_ADD_NODE_TO_PARENT)) { + if (state && state->s_node && (flags & STATE_ADD_NODE_TO_PARENT)) { parser_add_child(parser, state->s_node); } diff --git a/lang/ast/ctx.h b/lang/ast/ctx.h index ecd6bfa..ecb46f9 100644 --- a/lang/ast/ctx.h +++ b/lang/ast/ctx.h @@ -29,7 +29,7 @@ enum pop_state_flags { }; extern struct parser_state *parser_push_state( - struct ivy_parser *parser, enum ivy_ast_node_type node_type); + 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); diff --git a/lang/ast/expr/arith.c b/lang/ast/expr/arith.c index 4a770da..2c20225 100644 --- a/lang/ast/expr/arith.c +++ b/lang/ast/expr/arith.c @@ -230,7 +230,7 @@ static bool op_node_is_complete(struct ivy_ast_op_node *node) } } -static enum ivy_status finalise_expr( +enum ivy_status expr_finalise_arith( struct expr_parser_state *state, struct ivy_ast_node **expr_tree, enum ivy_operator_precedence minimum_precedence) { @@ -505,7 +505,7 @@ struct token_parse_result arith_parse_left_paren( struct expr_parser_state *msg_expr = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR); + ctx, IVY_AST_EXPR, 0); msg_expr->s_msg = (struct ivy_ast_msg_node *)msg; msg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_MSG; @@ -518,7 +518,8 @@ struct token_parse_result arith_parse_left_paren( /* a sub-expression surrounded by parentheses is parsed by creating * a sub-expression parser state */ struct expr_parser_state *sub_expr - = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR); + = (struct expr_parser_state *)parser_push_state( + ctx, IVY_AST_EXPR, 0); sub_expr->s_paren_depth = state->s_paren_depth + 1; sub_expr->s_subexpr_depth = state->s_subexpr_depth + 1; @@ -543,7 +544,7 @@ static struct ivy_ast_selector_node *keyword_selector_from_label_list(b_queue *l return sel; } -static struct ivy_ast_cascade_node *finalise_cascade(struct expr_parser_state *state) +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); @@ -562,7 +563,7 @@ static struct ivy_ast_cascade_node *finalise_cascade(struct expr_parser_state *s return cascade; } -static struct ivy_ast_msg_node *finalise_keyword_msg(struct expr_parser_state *state) +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); @@ -584,7 +585,7 @@ static struct ivy_ast_msg_node *finalise_keyword_msg(struct expr_parser_state *s return msg; } -static struct ivy_ast_msg_node *finalise_complex_msg(struct expr_parser_state *state) +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) { @@ -628,47 +629,7 @@ struct token_parse_result arith_parse_right_paren( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { - /* this is the end of a keyword-message */ - struct ivy_ast_msg_node *msg = finalise_keyword_msg(state); - 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); - } - - if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { - /* this is the end of a complex message */ - struct ivy_ast_msg_node *msg = finalise_complex_msg(state); - parser_replace_current_node(ctx, (struct ivy_ast_node *)msg); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, 0); - } - - if (state->s_sub_type == EXPR_SUBTYPE_CASCADE) { - /* this is the end of a cascade operation */ - struct ivy_ast_cascade_node *cascade = finalise_cascade(state); - parser_replace_current_node(ctx, (struct ivy_ast_node *)cascade); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); - } - - /* this is the end of a regular parentheses-surrounded sub-expression. */ - struct ivy_ast_node *expr = NULL; - enum ivy_status status - = finalise_expr(state, &expr, IVY_PRECEDENCE_ASSIGN); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); - } - - parser_replace_current_node(ctx, expr); - - int flags = 0; - if (state->s_paren_depth == 0 && state->s_sub_type != EXPR_SUBTYPE_NONE) { - flags = PARSE_REPEAT_TOKEN; - } - - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, flags); + return expr_finalise_and_return(ctx, state); } static enum ivy_status begin_cascade_operation(struct ivy_parser *ctx) @@ -680,12 +641,12 @@ static enum ivy_status begin_cascade_operation(struct ivy_parser *ctx) struct ivy_ast_msg_node *first_msg = NULL; if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { - first_msg = finalise_keyword_msg(state); + first_msg = expr_finalise_keyword_msg(state); parser_pop_state(ctx, 0); } else { struct ivy_ast_node *expr = NULL; enum ivy_status status - = finalise_expr(state, &expr, IVY_PRECEDENCE_CASCADE); + = expr_finalise_arith(state, &expr, IVY_PRECEDENCE_CASCADE); if (status != IVY_OK) { return status; } @@ -698,7 +659,8 @@ static enum ivy_status begin_cascade_operation(struct ivy_parser *ctx) } struct expr_parser_state *cascade_expr - = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR); + = (struct expr_parser_state *)parser_push_state( + ctx, IVY_AST_EXPR, 0); if (!first_msg) { return IVY_ERR_BAD_SYNTAX; @@ -714,7 +676,8 @@ static enum ivy_status begin_cascade_operation(struct ivy_parser *ctx) b_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); + = (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; @@ -752,7 +715,7 @@ struct token_parse_result arith_parse_semicolon( /* finish parsing this expression and let the parent context handle the semicolon. */ struct ivy_ast_node *expr = NULL; enum ivy_status status - = finalise_expr(state, &expr, IVY_PRECEDENCE_ASSIGN); + = expr_finalise_arith(state, &expr, IVY_PRECEDENCE_ASSIGN); if (status != IVY_OK) { return PARSE_RESULT(status, 0); } @@ -768,7 +731,7 @@ struct token_parse_result arith_parse_semicolon( /* 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); + ctx, IVY_AST_EXPR, 0); msg_expr->s_recipient = NULL; msg_expr->s_sub_type = EXPR_SUBTYPE_MSG; @@ -779,7 +742,7 @@ struct token_parse_result arith_parse_semicolon( } if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG && !state->s_recipient) { - struct ivy_ast_msg_node *msg = finalise_keyword_msg(state); + struct ivy_ast_msg_node *msg = expr_finalise_keyword_msg(state); if (!msg) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } @@ -794,6 +757,76 @@ struct token_parse_result arith_parse_semicolon( return PARSE_RESULT(status, 0); } +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_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); + } + + *result = expr; + return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 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); + + *result = cascade; + return PARSE_RESULT(IVY_OK, flags); + } + + 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); + *result = 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); + } + + *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) +{ + int flags = 0; + if (state->s_subexpr_depth > 0) { + flags = PARSE_REPEAT_TOKEN; + } + + 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) { @@ -809,52 +842,7 @@ struct token_parse_result arith_parse_dot( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - int flags = 0; - if (state->s_subexpr_depth > 0) { - flags = PARSE_REPEAT_TOKEN; - } - - 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 - = finalise_expr(state, &expr, IVY_PRECEDENCE_CASCADE); - 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_ERR_BAD_SYNTAX, 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 = finalise_cascade(state); - parser_replace_current_node(ctx, (struct ivy_ast_node *)cascade); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - return PARSE_RESULT(IVY_OK, flags); - } - - if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) { - /* this is the end of a keyword-message */ - struct ivy_ast_msg_node *msg = finalise_keyword_msg(state); - parser_replace_current_node(ctx, (struct ivy_ast_node *)msg); - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); - 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 - = finalise_expr(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, flags); + return expr_finalise_and_return(ctx, state); } struct token_parse_result arith_parse_label( @@ -874,7 +862,7 @@ struct token_parse_result arith_parse_label( * parent keyword-message parser context. */ struct ivy_ast_node *expr = NULL; enum ivy_status status - = finalise_expr(state, &expr, IVY_PRECEDENCE_ASSIGN); + = expr_finalise_arith(state, &expr, IVY_PRECEDENCE_ASSIGN); if (status != IVY_OK) { return PARSE_RESULT(status, 0); } @@ -887,9 +875,20 @@ struct token_parse_result arith_parse_label( 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 - = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR); + struct expr_parser_state *msg_expr; + bool new_parser = true; + + if (b_queue_empty(&state->s_operator_stack) + && b_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); + } else { + msg_expr = state; + } /* the only operator with a lower precedence than * keyword-messages is assignment. everything in the preceding @@ -899,7 +898,7 @@ struct token_parse_result arith_parse_label( if (state->s_sub_type != EXPR_SUBTYPE_MSG) { enum ivy_status status - = finalise_expr(state, &expr, IVY_PRECEDENCE_KEYWORD_MSG); + = expr_finalise_arith(state, &expr, IVY_PRECEDENCE_KEYWORD_MSG); if (status != IVY_OK) { return PARSE_RESULT(status, 0); } @@ -908,7 +907,7 @@ struct token_parse_result arith_parse_label( 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 + 1; + msg_expr->s_subexpr_depth = new_parser ? state->s_subexpr_depth + 1 : 0; state = msg_expr; } @@ -921,7 +920,7 @@ struct token_parse_result arith_parse_label( struct expr_parser_state *arg_expr = (struct expr_parser_state *)parser_push_state( - ctx, IVY_AST_EXPR); + ctx, IVY_AST_EXPR, 0); arg_expr->s_terminator = IVY_TOK_LABEL; arg_expr->s_sub_type = EXPR_SUBTYPE_KEYWORD_ARG; arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; @@ -958,4 +957,4 @@ enum ivy_status arith_add_child( } return IVY_OK; -} +} \ No newline at end of file diff --git a/lang/ast/expr/expr.c b/lang/ast/expr/expr.c index b28aa75..2e05820 100644 --- a/lang/ast/expr/expr.c +++ b/lang/ast/expr/expr.c @@ -34,4 +34,10 @@ struct ast_node_type expr_node_ops = { SYM_PARSER(SEMICOLON, arith_parse_semicolon), SYM_PARSER(DOT, arith_parse_dot), }, + .n_keyword_parsers = { + KW_PARSER(IF, stmt_parse_if), + KW_PARSER(THEN, stmt_parse_then), + KW_PARSER(ELSE, stmt_parse_else), + KW_PARSER(END, stmt_parse_end), + } }; diff --git a/lang/ast/expr/expr.h b/lang/ast/expr/expr.h index 8c66642..c59b2bc 100644 --- a/lang/ast/expr/expr.h +++ b/lang/ast/expr/expr.h @@ -67,7 +67,6 @@ struct expr_parser_state { * expression will not be consumed. */ unsigned int s_terminator; - b_queue s_output_queue; b_queue s_operator_stack; @@ -84,6 +83,16 @@ struct expr_parser_state { }; }; +/* general functions */ + +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 void arith_push_operand( @@ -109,4 +118,15 @@ extern struct token_parse_result arith_parse_semicolon( extern struct token_parse_result arith_parse_dot( struct ivy_parser *ctx, struct ivy_token *tok); +/* statement parser callbacks */ + +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); + #endif diff --git a/lang/ast/expr/stmt.c b/lang/ast/expr/stmt.c index e69de29..7f305d2 100644 --- a/lang/ast/expr/stmt.c +++ b/lang/ast/expr/stmt.c @@ -0,0 +1,79 @@ +#include "../node.h" +#include "expr.h" +#include "../cond.h" + +#include +#include +#include +#include + +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 (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 (b_queue_empty(&state->s_operator_stack) && b_queue_empty(&state->s_output_queue)) { + parser_pop_state(ctx, 0); + } + + struct cond_group_parser_state *cond + = (struct cond_group_parser_state *)parser_push_state( + ctx, IVY_AST_COND_GROUP, 0); + + /* if expr is NULL, this is an if-then-else-end statement, + * otherwise, this is an expr-if-else-expr. */ + cond->s_prev_node = 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; +} \ No newline at end of file diff --git a/lang/ast/msgh.c b/lang/ast/msgh.c index c4456f9..30a3dce 100644 --- a/lang/ast/msgh.c +++ b/lang/ast/msgh.c @@ -38,7 +38,8 @@ static struct token_parse_result parse_linefeed( } struct block_parser_state *block_state - = (struct block_parser_state *)parser_push_state(ctx, IVY_AST_BLOCK); + = (struct block_parser_state *)parser_push_state( + ctx, IVY_AST_BLOCK, 0); block_state->s_terminator = IVY_SYM_BANG; return PARSE_RESULT(IVY_OK, 0); @@ -75,7 +76,7 @@ static struct token_parse_result parse_pipe( } state->s_oneline = true; - parser_push_state(ctx, IVY_AST_EXPR); + parser_push_state(ctx, IVY_AST_EXPR, 0); return PARSE_RESULT(IVY_OK, 0); } @@ -104,7 +105,7 @@ static void init_state(struct ivy_parser *ctx, struct parser_state *sp) state->s_i = 0; state->s_prev = IVY_SYM_HYPHEN; - parser_push_state(ctx, IVY_AST_SELECTOR); + parser_push_state(ctx, IVY_AST_SELECTOR, 0); } static void collect_children( diff --git a/lang/ast/node.c b/lang/ast/node.c index 09d694b..9fd182f 100644 --- a/lang/ast/node.c +++ b/lang/ast/node.c @@ -20,6 +20,8 @@ extern struct ast_node_type int_node_ops; extern struct ast_node_type double_node_ops; extern struct ast_node_type string_node_ops; extern struct ast_node_type cascade_node_ops; +extern struct ast_node_type cond_group_node_ops; +extern struct ast_node_type cond_node_ops; static const struct ast_node_type *node_ops[] = { [IVY_AST_UNIT] = &unit_node_ops, @@ -37,6 +39,8 @@ static const struct ast_node_type *node_ops[] = { [IVY_AST_DOUBLE] = &double_node_ops, [IVY_AST_STRING] = &string_node_ops, [IVY_AST_CASCADE] = &cascade_node_ops, + [IVY_AST_COND_GROUP] = &cond_group_node_ops, + [IVY_AST_COND] = &cond_node_ops, }; static const size_t nr_node_ops = sizeof node_ops / sizeof node_ops[0]; diff --git a/lang/ast/node.h b/lang/ast/node.h index 3ff108b..abd98b4 100644 --- a/lang/ast/node.h +++ b/lang/ast/node.h @@ -47,7 +47,7 @@ struct ast_node_type { enum ivy_status (*n_add_child)( struct parser_state*, struct ivy_ast_node*); void (*n_print)(struct ivy_ast_node*); - void (*n_init_state)(struct ivy_parser*, struct parser_state*); + 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*); diff --git a/lang/ast/selector.c b/lang/ast/selector.c index 54e60c8..f80a59e 100644 --- a/lang/ast/selector.c +++ b/lang/ast/selector.c @@ -263,7 +263,7 @@ static void print(struct ivy_ast_node *node) fputs("]\n", stdout); } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp) +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; diff --git a/lang/ast/unit-import.c b/lang/ast/unit-import.c index 49779ac..6452131 100644 --- a/lang/ast/unit-import.c +++ b/lang/ast/unit-import.c @@ -80,7 +80,7 @@ static void print(struct ivy_ast_node *node) b_string_release(str); } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp) +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; diff --git a/lang/ast/unit-package.c b/lang/ast/unit-package.c index 1071aa7..1e4ba79 100644 --- a/lang/ast/unit-package.c +++ b/lang/ast/unit-package.c @@ -80,7 +80,7 @@ static void print(struct ivy_ast_node *node) b_string_release(str); } -static void init_state(struct ivy_parser *ctx, struct parser_state *sp) +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; diff --git a/lang/ast/unit.c b/lang/ast/unit.c index 8895c9d..ae10887 100644 --- a/lang/ast/unit.c +++ b/lang/ast/unit.c @@ -7,31 +7,38 @@ static struct token_parse_result parse_package_keyword( struct ivy_parser *ctx, struct ivy_token *tok) { - parser_push_state(ctx, IVY_AST_UNIT_PACKAGE); + 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); + parser_push_state(ctx, IVY_AST_UNIT_IMPORT, 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); + 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); + 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) +{ + printf("unneeded dot\n"); + return PARSE_RESULT(IVY_OK, 0); +} + static enum ivy_status add_child( struct parser_state *parent, struct ivy_ast_node *child) { @@ -62,6 +69,9 @@ struct ast_node_type unit_node_ops = { KW_PARSER(CLASS, parse_class_keyword), KW_PARSER(USE, parse_use_keyword), }, + .n_symbol_parsers = { + SYM_PARSER(DOT, parse_dot), + }, .n_expr_parser = { .expr_begin = parse_expr_begin, }, diff --git a/lang/include/ivy/lang/ast.h b/lang/include/ivy/lang/ast.h index ff111d5..41ffd0e 100644 --- a/lang/include/ivy/lang/ast.h +++ b/lang/include/ivy/lang/ast.h @@ -217,8 +217,8 @@ struct ivy_ast_cond_node { struct ivy_ast_node n_base; /* expression. must evaluate to true for the condition body to be evaluated. NULL for unconditional (else). */ struct ivy_ast_node *n_cond; - /* queue of struct ivy_ast_node. expressions to evaluate if the condition is true. */ - b_queue n_body; + /* expression/block to evaluate if the condition is true. */ + struct ivy_ast_node *n_body; }; struct ivy_ast_tuple_node { diff --git a/lang/include/ivy/lang/lex.h b/lang/include/ivy/lang/lex.h index f576e70..c14067f 100644 --- a/lang/include/ivy/lang/lex.h +++ b/lang/include/ivy/lang/lex.h @@ -34,6 +34,7 @@ enum ivy_keyword { IVY_KW_THROW, IVY_KW_CATCH, IVY_KW_IF, + IVY_KW_THEN, IVY_KW_AND, IVY_KW_OR, IVY_KW_UNDERSTANDS,