lang: ast: implement cascade operator parsing

This commit is contained in:
2024-12-03 21:57:44 +00:00
parent 16ab13d738
commit 051cb1d2c2
7 changed files with 294 additions and 35 deletions

View File

@@ -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);