lang: ast: complex-msg args are now separated by commas

additionally, unnamed complex-msg args no longer need to be prefixed
with a colon. this allows complex-msgs to more closely emulate
traditional function calls. this also applies to the call-operator.

for example, take the following lambda:

	var f = [ :x :y | ^x * 2 + y ].

before, this lambda would be invoked using the following syntax:

	f(:2 :4).

now, this syntax is used instead:

	f(2, 4).
This commit is contained in:
2025-04-23 10:53:34 +01:00
parent 2673f29447
commit 279b387b69
2 changed files with 59 additions and 2 deletions

View File

@@ -7,6 +7,7 @@
#include <ivy/lang/lex.h> #include <ivy/lang/lex.h>
#include <ivy/lang/operator.h> #include <ivy/lang/operator.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
static void print_operand(struct ivy_ast_node *node) static void print_operand(struct ivy_ast_node *node)
{ {
@@ -448,6 +449,33 @@ struct token_parse_result arith_parse_operand(
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
} }
if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) {
/* this is an unlabeled complex message arg */
if (state->s_prev_token != IVY_SYM_COMMA
&& state->s_prev_token != IVY_SYM_LEFT_PAREN) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct ivy_token *empty_label = malloc(sizeof *empty_label);
if (!empty_label) {
return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0);
}
memset(empty_label, 0x0, sizeof *empty_label);
empty_label->t_type = IVY_TOK_LABEL;
b_queue_push_back(&state->s_labels, &empty_label->t_entry);
struct expr_parser_state *arg_expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_copy_terminators(state, arg_expr);
expr_add_terminator(arg_expr, IVY_SYM_COMMA);
arg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_ARG;
arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1;
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
if (state->s_prev_component == EXPR_CMP_OPERAND) { if (state->s_prev_component == EXPR_CMP_OPERAND) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0); return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
} }
@@ -623,11 +651,14 @@ struct token_parse_result arith_parse_left_paren(
= (struct expr_parser_state *)parser_push_state( = (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0); ctx, IVY_AST_EXPR, 0);
expr_add_terminator(msg_expr, IVY_SYM_COMMA);
msg_expr->s_msg = (struct ivy_ast_msg_node *)msg; msg_expr->s_msg = (struct ivy_ast_msg_node *)msg;
msg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_MSG; msg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_MSG;
msg_expr->s_type = EXPR_TYPE_ARITH; msg_expr->s_type = EXPR_TYPE_ARITH;
msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1;
msg_expr->s_prev_token = state->s_prev_token = IVY_SYM_LEFT_PAREN;
return PARSE_RESULT(IVY_OK, 0); return PARSE_RESULT(IVY_OK, 0);
} }
@@ -648,6 +679,8 @@ not_complex_msg:
msg_expr->s_type = EXPR_TYPE_ARITH; msg_expr->s_type = EXPR_TYPE_ARITH;
msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1; msg_expr->s_subexpr_depth = state->s_subexpr_depth + 1;
msg_expr->s_prev_token = state->s_prev_token = IVY_SYM_LEFT_PAREN;
return PARSE_RESULT(IVY_OK, 0); return PARSE_RESULT(IVY_OK, 0);
} }
@@ -974,6 +1007,7 @@ struct token_parse_result arith_parse_semicolon(
break; break;
case EXPR_SUBTYPE_KEYWORD_MSG: case EXPR_SUBTYPE_KEYWORD_MSG:
case EXPR_SUBTYPE_CASCADE: case EXPR_SUBTYPE_CASCADE:
case EXPR_SUBTYPE_COMPLEX_ARG:
case EXPR_SUBTYPE_NONE: case EXPR_SUBTYPE_NONE:
break; break;
default: default:
@@ -1217,6 +1251,12 @@ struct token_parse_result arith_parse_comma(
struct expr_parser_state *state struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state); = parser_get_state(ctx, struct expr_parser_state);
if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) {
/* this is a comma separator between two complex message args */
state->s_prev_token = IVY_SYM_COMMA;
return PARSE_RESULT(IVY_OK, 0);
}
if (expr_terminates_at_token(state, IVY_SYM_COMMA)) { if (expr_terminates_at_token(state, IVY_SYM_COMMA)) {
struct token_parse_result result struct token_parse_result result
= expr_finalise_and_return(ctx, state); = expr_finalise_and_return(ctx, state);
@@ -1348,8 +1388,23 @@ struct token_parse_result arith_parse_label(
state = msg_expr; state = msg_expr;
} }
if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG if (state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) {
|| state->s_sub_type == EXPR_SUBTYPE_COMPLEX_MSG) { /* this label denotes the start of a complex message arg */
if (state->s_prev_token != IVY_SYM_COMMA
&& state->s_prev_token != IVY_SYM_LEFT_PAREN) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
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, 0);
expr_copy_terminators(state, arg_expr);
expr_add_terminator(arg_expr, IVY_SYM_COMMA);
arg_expr->s_sub_type = EXPR_SUBTYPE_COMPLEX_ARG;
arg_expr->s_subexpr_depth = state->s_subexpr_depth + 1;
} else if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_MSG) {
/* we may have just finished parsing a keyword-message argument, /* we may have just finished parsing a keyword-message argument,
* and this label marks the start of a new one. store the label * and this label marks the start of a new one. store the label
* and create a new argument parsing context. */ * and create a new argument parsing context. */

View File

@@ -33,6 +33,8 @@ enum expr_subtype {
EXPR_SUBTYPE_KEYWORD_ARG, EXPR_SUBTYPE_KEYWORD_ARG,
/* complex messages */ /* complex messages */
EXPR_SUBTYPE_COMPLEX_MSG, EXPR_SUBTYPE_COMPLEX_MSG,
/* expression delimited by commas */
EXPR_SUBTYPE_COMPLEX_ARG,
/* message cascade operation */ /* message cascade operation */
EXPR_SUBTYPE_CASCADE, EXPR_SUBTYPE_CASCADE,
}; };