diff --git a/lang/ast/cascade.c b/lang/ast/cascade.c new file mode 100644 index 0000000..a5337a9 --- /dev/null +++ b/lang/ast/cascade.c @@ -0,0 +1,27 @@ +#include "ctx.h" +#include "node.h" + +#include + +static void collect_children( + struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator) +{ + struct ivy_ast_cascade_node *cascade = (struct ivy_ast_cascade_node *)node; + + if (cascade->n_recipient) { + ast_node_iterator_enqueue_node(iterator, node, cascade->n_recipient); + } + + b_queue_iterator it = {0}; + b_queue_foreach (&it, &cascade->n_msg) { + struct ivy_ast_node *arg + = b_unbox(struct ivy_ast_node, it.entry, n_entry); + ast_node_iterator_enqueue_node(iterator, node, arg); + } +} + +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/ctx.c b/lang/ast/ctx.c index b478523..b9a3239 100644 --- a/lang/ast/ctx.c +++ b/lang/ast/ctx.c @@ -94,6 +94,27 @@ struct parser_state *parser_get_state_generic(struct ivy_parser *parser) return state; } +struct parser_state *parser_get_parent_state_generic(struct ivy_parser *parser, enum ivy_ast_node_type type) +{ + b_queue_entry *entry = b_queue_last(&parser->p_state); + if (!entry) { + return NULL; + } + + entry = b_queue_prev(entry); + if (!entry) { + return NULL; + } + + struct parser_state *state = b_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) { diff --git a/lang/ast/ctx.h b/lang/ast/ctx.h index 2e008c9..ecd6bfa 100644 --- a/lang/ast/ctx.h +++ b/lang/ast/ctx.h @@ -8,6 +8,9 @@ #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 { b_queue_entry s_entry; struct ivy_ast_node *s_parent; @@ -29,6 +32,7 @@ extern struct parser_state *parser_push_state( struct ivy_parser *parser, enum ivy_ast_node_type node_type); 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); diff --git a/lang/ast/expr/arith.c b/lang/ast/expr/arith.c index 858e979..4a770da 100644 --- a/lang/ast/expr/arith.c +++ b/lang/ast/expr/arith.c @@ -456,6 +456,17 @@ struct token_parse_result arith_parse_ident( 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); @@ -497,8 +508,9 @@ struct token_parse_result arith_parse_left_paren( ctx, IVY_AST_EXPR); msg_expr->s_msg = (struct ivy_ast_msg_node *)msg; - msg_expr->s_subexpr = EXPR_SUBTYPE_COMPLEX_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; return PARSE_RESULT(IVY_OK, 0); } @@ -508,6 +520,7 @@ struct token_parse_result arith_parse_left_paren( struct expr_parser_state *sub_expr = (struct expr_parser_state *)parser_push_state(ctx, IVY_AST_EXPR); sub_expr->s_paren_depth = state->s_paren_depth + 1; + sub_expr->s_subexpr_depth = state->s_subexpr_depth + 1; return PARSE_RESULT(IVY_OK, 0); } @@ -530,6 +543,25 @@ 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) +{ + struct ivy_ast_cascade_node *cascade + = (struct ivy_ast_cascade_node *)ast_node_create(IVY_AST_CASCADE); + + cascade->n_recipient = state->s_recipient; + + b_queue_iterator it = {0}; + b_queue_iterator_begin(&state->s_cascade_msg, &it); + while (b_queue_iterator_is_valid(&it)) { + struct ivy_ast_node *msg + = b_unbox(struct ivy_ast_node, it.entry, n_entry); + b_queue_iterator_erase(&it); + b_queue_push_back(&cascade->n_msg, &msg->n_entry); + } + + return cascade; +} + static struct ivy_ast_msg_node *finalise_keyword_msg(struct expr_parser_state *state) { struct ivy_ast_msg_node *msg @@ -592,11 +624,11 @@ struct token_parse_result arith_parse_right_paren( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - if (state->s_paren_depth == 0 && state->s_subexpr == EXPR_SUBTYPE_NONE) { + if (state->s_paren_depth == 0 && state->s_sub_type == EXPR_SUBTYPE_NONE) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG) { + 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); @@ -604,14 +636,22 @@ struct token_parse_result arith_parse_right_paren( return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); } - if (state->s_subexpr == EXPR_SUBTYPE_COMPLEX_MSG) { - /* this is the end of a keyword-message */ + 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 @@ -623,7 +663,7 @@ struct token_parse_result arith_parse_right_paren( parser_replace_current_node(ctx, expr); int flags = 0; - if (state->s_paren_depth == 0 && state->s_subexpr != EXPR_SUBTYPE_NONE) { + if (state->s_paren_depth == 0 && state->s_sub_type != EXPR_SUBTYPE_NONE) { flags = PARSE_REPEAT_TOKEN; } @@ -631,6 +671,129 @@ struct token_parse_result arith_parse_right_paren( return PARSE_RESULT(IVY_OK, flags); } +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 = 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); + if (status != IVY_OK) { + return status; + } + + if (expr->n_type != IVY_AST_MSG) { + 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); + + 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; + + 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); + 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_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 + = 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, 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); + + 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 = 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); +} + struct token_parse_result arith_parse_dot( struct ivy_parser *ctx, struct ivy_token *tok) { @@ -645,13 +808,40 @@ struct token_parse_result arith_parse_dot( /* end-of-expression with mismatched parentheses */ return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } + + int flags = 0; + if (state->s_subexpr_depth > 0) { + flags = PARSE_REPEAT_TOKEN; + } - if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG) { + 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, PARSE_REPEAT_TOKEN); + return PARSE_RESULT(IVY_OK, flags); } /* this is the end of a regular expression or sub-expression */ @@ -663,16 +853,6 @@ struct token_parse_result arith_parse_dot( } parser_replace_current_node(ctx, expr); - - int flags = 0; - if (state->s_subexpr != EXPR_SUBTYPE_NONE) { - /* if we are currently parsing a subexpression (such as a - * keyword-message argument), the dot needs to be propagated to - * the parent expression context so that it can be terminated - * too. */ - flags = PARSE_REPEAT_TOKEN; - } - parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); return PARSE_RESULT(IVY_OK, flags); } @@ -704,8 +884,8 @@ struct token_parse_result arith_parse_label( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, PARSE_REPEAT_TOKEN); } - if (state->s_subexpr != EXPR_SUBTYPE_KEYWORD_MSG - && state->s_subexpr != EXPR_SUBTYPE_COMPLEX_MSG) { + 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( @@ -716,20 +896,24 @@ struct token_parse_result arith_parse_label( * expression, up to but not including any un-parenthesised * assignments, is the recipient of the message. */ struct ivy_ast_node *expr = NULL; - enum ivy_status status - = finalise_expr(state, &expr, IVY_PRECEDENCE_KEYWORD_MSG); - if (status != IVY_OK) { - return PARSE_RESULT(status, 0); + + if (state->s_sub_type != EXPR_SUBTYPE_MSG) { + enum ivy_status status + = finalise_expr(state, &expr, IVY_PRECEDENCE_KEYWORD_MSG); + if (status != IVY_OK) { + return PARSE_RESULT(status, 0); + } } msg_expr->s_recipient = expr; - msg_expr->s_subexpr = EXPR_SUBTYPE_KEYWORD_MSG; + 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; state = msg_expr; } - if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG - || state->s_subexpr == EXPR_SUBTYPE_COMPLEX_MSG) { + if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG + || state->s_sub_type == EXPR_SUBTYPE_COMPLEX_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. */ @@ -739,7 +923,8 @@ struct token_parse_result arith_parse_label( = (struct expr_parser_state *)parser_push_state( ctx, IVY_AST_EXPR); arg_expr->s_terminator = IVY_TOK_LABEL; - arg_expr->s_subexpr = EXPR_SUBTYPE_KEYWORD_ARG; + 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); @@ -750,11 +935,14 @@ enum ivy_status arith_add_child( { struct expr_parser_state *state = (struct expr_parser_state *)parent; - if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG - || state->s_subexpr == EXPR_SUBTYPE_COMPLEX_MSG) { + if (state->s_sub_type == EXPR_SUBTYPE_CASCADE) { + /* treat the child node as a cascaded message */ + b_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 */ b_queue_push_back(&state->s_args, &child->n_entry); - } else if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_ARG) { + } 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). */ b_queue_push_back(&state->s_output_queue, &child->n_entry); diff --git a/lang/ast/expr/expr.c b/lang/ast/expr/expr.c index 0b18ff0..b28aa75 100644 --- a/lang/ast/expr/expr.c +++ b/lang/ast/expr/expr.c @@ -31,6 +31,7 @@ struct ast_node_type expr_node_ops = { .n_symbol_parsers = { SYM_PARSER(LEFT_PAREN, arith_parse_left_paren), SYM_PARSER(RIGHT_PAREN, arith_parse_right_paren), + SYM_PARSER(SEMICOLON, arith_parse_semicolon), SYM_PARSER(DOT, arith_parse_dot), }, }; diff --git a/lang/ast/expr/expr.h b/lang/ast/expr/expr.h index e98f3dd..8c66642 100644 --- a/lang/ast/expr/expr.h +++ b/lang/ast/expr/expr.h @@ -23,12 +23,16 @@ 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, + /* message cascade operation */ + EXPR_SUBTYPE_CASCADE, }; enum expr_component { @@ -41,6 +45,8 @@ enum expr_component { struct expr_parser_state { struct parser_state s_base; enum expr_type s_type; + enum expr_subtype s_sub_type; + /* for arithmetic expressions, this records whether the previous * component (either a token or parenthesised group of tokens) is an * operator, operand, or message */ @@ -52,14 +58,15 @@ struct expr_parser_state { * 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; + /* when this is set, the expression will be terminated when the * specified token is encountered. the token that terminated the * expression will not be consumed. */ unsigned int s_terminator; - /* all sub-expressions (i.e. those conatained within brackets, - * keyword-messages and keyword-message args, etc) will have this set/ */ - enum expr_subtype s_subexpr; b_queue s_output_queue; b_queue s_operator_stack; @@ -68,7 +75,13 @@ struct expr_parser_state { struct ivy_ast_node *s_recipient; struct ivy_ast_msg_node *s_msg; b_queue s_labels; - b_queue s_args; + + union { + /* for keyword-messages, this is a list of arg values. */ + b_queue s_args; + /* for cascade operators, this is a list of messages to send to the recipient. */ + b_queue s_cascade_msg; + }; }; extern void arith_push_operator( @@ -91,6 +104,8 @@ 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_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); diff --git a/lang/ast/node.c b/lang/ast/node.c index a134525..09d694b 100644 --- a/lang/ast/node.c +++ b/lang/ast/node.c @@ -19,6 +19,7 @@ extern struct ast_node_type ident_node_ops; 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; static const struct ast_node_type *node_ops[] = { [IVY_AST_UNIT] = &unit_node_ops, @@ -35,6 +36,7 @@ static const struct ast_node_type *node_ops[] = { [IVY_AST_INT] = &int_node_ops, [IVY_AST_DOUBLE] = &double_node_ops, [IVY_AST_STRING] = &string_node_ops, + [IVY_AST_CASCADE] = &cascade_node_ops, }; static const size_t nr_node_ops = sizeof node_ops / sizeof node_ops[0]; @@ -224,6 +226,7 @@ const char *ivy_ast_node_type_to_string(enum ivy_ast_node_type v) ENUM_STR(IVY_AST_IDENT); ENUM_STR(IVY_AST_FOR_LOOP); ENUM_STR(IVY_AST_WHILE_LOOP); + ENUM_STR(IVY_AST_CASCADE); ENUM_STR(IVY_AST_COND_GROUP); ENUM_STR(IVY_AST_COND); ENUM_STR(IVY_AST_TUPLE);