76 lines
1.7 KiB
C
76 lines
1.7 KiB
C
|
|
#include "ctx.h"
|
||
|
|
|
||
|
|
#include <ivy/lang/ast.h>
|
||
|
|
|
||
|
|
bool parse_match(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||
|
|
{
|
||
|
|
if (!parse_keyword(parser, IVY_KW_MATCH)) {
|
||
|
|
parse_trace(parser, "expected `match` keyword");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct ivy_ast_match_node *match = create_node(IVY_AST_MATCH);
|
||
|
|
|
||
|
|
if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &match->n_cond)) {
|
||
|
|
parse_trace(parser, "invalid match predicate");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||
|
|
parse_trace(parser, "expected `[` after match predicate");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ok = true;
|
||
|
|
while (1) {
|
||
|
|
if (parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!fx_queue_empty(&match->n_branches)
|
||
|
|
&& !parse_symbol(parser, IVY_SYM_COMMA)) {
|
||
|
|
parse_trace(
|
||
|
|
parser,
|
||
|
|
"expected `,` or `]` after match branch value");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct ivy_ast_node *branch_pred = NULL;
|
||
|
|
struct ivy_ast_node *branch_value = NULL;
|
||
|
|
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &branch_pred)) {
|
||
|
|
parse_trace(parser, "invalid match branch predicate");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!parse_symbol(parser, IVY_SYM_EQUAL_RIGHT_ANGLE)) {
|
||
|
|
parse_trace(
|
||
|
|
parser,
|
||
|
|
"expected `=>` after match branch predicate");
|
||
|
|
ok = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (peek_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||
|
|
ok = parse_block(parser, &branch_value);
|
||
|
|
} else {
|
||
|
|
ok = parse_expr(
|
||
|
|
parser, EXPR_PARSE_STOP_COMMA, &branch_value);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!ok) {
|
||
|
|
parse_trace(parser, "invalid match branch value");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND);
|
||
|
|
cond->n_cond = branch_pred;
|
||
|
|
cond->n_body = branch_value;
|
||
|
|
fx_queue_push_back(&match->n_branches, &cond->n_base.n_entry);
|
||
|
|
}
|
||
|
|
|
||
|
|
*out = generic_node(match);
|
||
|
|
return true;
|
||
|
|
}
|