From 5ec3e8fcd43322b1a3212de3e18ad2b49811cb55 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Mon, 2 Dec 2024 10:48:16 +0000 Subject: [PATCH] lang: ast: implement parsing of complex messages --- lang/ast/expr.c | 195 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 155 insertions(+), 40 deletions(-) diff --git a/lang/ast/expr.c b/lang/ast/expr.c index 4b8f6e2..76d0444 100644 --- a/lang/ast/expr.c +++ b/lang/ast/expr.c @@ -16,6 +16,18 @@ enum expr_type { EXPR_TYPE_ARITH, }; +enum expr_subtype { + EXPR_SUBTYPE_NONE = 0, + /* generic parenthesis-enclosed arithmetic expressions */ + EXPR_SUBTYPE_PAREN, + /* keyword messages */ + EXPR_SUBTYPE_KEYWORD_MSG, + /* expression delimited by labels */ + EXPR_SUBTYPE_KEYWORD_ARG, + /* complex messages */ + EXPR_SUBTYPE_COMPLEX_MSG, +}; + enum expr_component { EXPR_CMP_NONE = 0, EXPR_CMP_OPERATOR, @@ -43,15 +55,15 @@ struct expr_parser_state { unsigned int s_terminator; /* all sub-expressions (i.e. those conatained within brackets, - * keyword-messages and keyword-message args, etc) will have this set - * to true */ - bool s_subexpr; + * 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; /* these variables are for keyword-message expressions */ struct ivy_ast_node *s_recipient; + struct ivy_ast_msg_node *s_msg; b_queue s_labels; b_queue s_args; }; @@ -139,7 +151,7 @@ static void push_operand(struct expr_parser_state *state, struct ivy_token *tok) } } -static const struct ivy_operator *get_operator(struct ivy_token *tok) +static const struct ivy_operator *get_operator_from_token(struct ivy_token *tok) { switch (tok->t_type) { case IVY_TOK_SYMBOL: @@ -151,6 +163,20 @@ static const struct ivy_operator *get_operator(struct ivy_token *tok) } } +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 @@ -159,9 +185,32 @@ static struct ivy_ast_selector_node *unary_selector_from_token(struct ivy_token return sel; } -static void push_operator(struct expr_parser_state *state, struct ivy_token *tok) +static struct ivy_ast_node *create_operator_node_from_token(struct ivy_token *tok) { - const struct ivy_operator *op = get_operator(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); + 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; + return (struct ivy_ast_node *)new_op_node; +} + +static void 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) { b_queue_entry *top = b_queue_last(&state->s_operator_stack); @@ -200,19 +249,7 @@ static void push_operator(struct expr_parser_state *state, struct ivy_token *tok b_queue_push_back(&state->s_output_queue, top); } - 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); - b_queue_push_back( - &state->s_operator_stack, &new_msg_node->n_base.n_entry); - } else { - 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; - b_queue_push_back( - &state->s_operator_stack, &new_op_node->n_base.n_entry); - } + b_queue_push_back(&state->s_operator_stack, &node->n_entry); } static void print_expr_queues(struct expr_parser_state *state) @@ -433,6 +470,7 @@ static struct token_parse_result parse_operand( 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); } @@ -455,15 +493,16 @@ static struct token_parse_result parse_operator( state->s_prev_token = tok->t_keyword; break; default: + state->s_prev_token = tok->t_type; break; } - const struct ivy_operator *op = get_operator(tok); + struct ivy_ast_node *op = create_operator_node_from_token(tok); if (!op) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - push_operator(state, tok); + push_operator(state, op); state->s_prev_component = EXPR_CMP_OPERATOR; print_expr_queues(state); @@ -502,6 +541,28 @@ static struct token_parse_result parse_left_paren( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } + if (state->s_prev_token == IVY_TOK_IDENT) { + /* this is the opening parenthesis for a complex message. */ + b_queue_entry *msg_entry + = b_queue_pop_back(&state->s_operator_stack); + struct ivy_ast_node *msg + = b_unbox(struct ivy_ast_node, msg_entry, n_entry); + + if (msg->n_type != IVY_AST_MSG) { + return PARSE_RESULT(IVY_ERR_INTERNAL_FAILURE, 0); + } + + struct expr_parser_state *msg_expr + = (struct expr_parser_state *)parser_push_state( + 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_type = EXPR_TYPE_ARITH; + + return PARSE_RESULT(IVY_OK, 0); + } + /* a sub-expression surrounded by parentheses is parsed by creating * a sub-expression parser state */ struct expr_parser_state *sub_expr @@ -551,6 +612,36 @@ 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) +{ + struct ivy_ast_msg_node *msg = state->s_msg; + if (!msg) { + return NULL; + } + + state->s_msg = NULL; + + b_queue_iterator it = {0}; + b_queue_iterator_begin(&state->s_labels, &it); + while (b_queue_iterator_is_valid(&it)) { + struct ivy_token *label + = b_unbox(struct ivy_token, it.entry, t_entry); + b_queue_iterator_erase(&it); + b_queue_push_back(&msg->n_sel->n_arg_labels, &label->t_entry); + } + + b_queue_iterator_begin(&state->s_args, &it); + while (b_queue_iterator_is_valid(&it)) { + struct ivy_ast_node *arg + = b_unbox(struct ivy_ast_node, it.entry, n_entry); + b_queue_iterator_erase(&it); + + b_queue_push_back(&msg->n_arg, &arg->n_entry); + } + + return msg; +} + static struct token_parse_result parse_right_paren( struct ivy_parser *ctx, struct ivy_token *tok) { @@ -561,11 +652,11 @@ static struct token_parse_result parse_right_paren( return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - if (state->s_paren_depth == 0 && !state->s_subexpr) { + if (state->s_paren_depth == 0 && state->s_subexpr == EXPR_SUBTYPE_NONE) { return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); } - if (state->s_recipient) { + if (state->s_subexpr == 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); @@ -573,6 +664,14 @@ static struct token_parse_result 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 */ + 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); + } + /* this is the end of a regular parentheses-surrounded sub-expression. */ struct ivy_ast_node *expr = NULL; enum ivy_status status @@ -584,7 +683,7 @@ static struct token_parse_result parse_right_paren( parser_replace_current_node(ctx, expr); int flags = 0; - if (state->s_paren_depth == 0 && state->s_subexpr) { + if (state->s_paren_depth == 0 && state->s_subexpr != EXPR_SUBTYPE_NONE) { flags = PARSE_REPEAT_TOKEN; } @@ -626,7 +725,7 @@ static struct token_parse_result parse_dot( parser_replace_current_node(ctx, expr); int flags = 0; - if (state->s_subexpr) { + 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 @@ -649,15 +748,24 @@ static struct token_parse_result parse_label( } if (state->s_terminator == IVY_TOK_LABEL) { - /* we are currently parsing a keyword-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. */ + /* 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; + 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_ERR_BAD_SYNTAX, PARSE_REPEAT_TOKEN); } - if (!state->s_recipient) { + if (state->s_subexpr != EXPR_SUBTYPE_KEYWORD_MSG + && state->s_subexpr != 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( @@ -675,20 +783,24 @@ static struct token_parse_result parse_label( } msg_expr->s_recipient = expr; - msg_expr->s_subexpr = true; + msg_expr->s_subexpr = EXPR_SUBTYPE_KEYWORD_MSG; msg_expr->s_type = EXPR_TYPE_ARITH; state = msg_expr; } - /* we 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. */ - b_queue_push_back(&state->s_labels, &tok->t_entry); + if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG + || state->s_subexpr == 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. */ + b_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); - arg_expr->s_terminator = IVY_TOK_LABEL; - arg_expr->s_subexpr = true; + struct expr_parser_state *arg_expr + = (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; + } return PARSE_RESULT(IVY_OK, 0); } @@ -701,9 +813,12 @@ static enum ivy_status add_child( return IVY_ERR_NOT_SUPPORTED; } - if (state->s_recipient) { + if (state->s_subexpr == EXPR_SUBTYPE_KEYWORD_MSG + || state->s_subexpr == 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 (child->n_type == IVY_AST_MSG) { + push_operator(state, child); } else { /* treat the child node as a sub-expression enclosed in * parentheses (i.e. an operand). */