lang: ast: implement cascade operator parsing
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user