mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
Interval expressions for match statements
This commit is contained in:
+1
-1
@@ -250,7 +250,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
target_type = default_type(operand->type);
|
target_type = default_type(operand->type);
|
||||||
if (!is_type_any(type)) {
|
if (type != NULL && !is_type_any(type)) {
|
||||||
GB_ASSERT_MSG(is_type_typed(target_type), "%s", type_to_string(type));
|
GB_ASSERT_MSG(is_type_typed(target_type), "%s", type_to_string(type));
|
||||||
}
|
}
|
||||||
add_type_info_type(c, type);
|
add_type_info_type(c, type);
|
||||||
|
|||||||
+111
-50
@@ -915,6 +915,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
token.string = str_lit("true");
|
token.string = str_lit("true");
|
||||||
x.expr = ast_ident(c->curr_ast_file, token);
|
x.expr = ast_ident(c->curr_ast_file, token);
|
||||||
}
|
}
|
||||||
|
if (is_type_vector(x.type)) {
|
||||||
|
gbString str = type_to_string(x.type);
|
||||||
|
error_node(x.expr, "Invalid match expression type: %s", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): Check for multiple defaults
|
// NOTE(bill): Check for multiple defaults
|
||||||
AstNode *first_default = NULL;
|
AstNode *first_default = NULL;
|
||||||
@@ -957,65 +964,119 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
for_array(j, cc->list) {
|
for_array(j, cc->list) {
|
||||||
AstNode *expr = cc->list.e[j];
|
AstNode *expr = cc->list.e[j];
|
||||||
Operand y = {0};
|
|
||||||
|
|
||||||
check_expr(c, &y, expr);
|
if (expr->kind == AstNode_IntervalExpr) {
|
||||||
if (x.mode == Addressing_Invalid ||
|
ast_node(ie, IntervalExpr, expr);
|
||||||
y.mode == Addressing_Invalid) {
|
Operand lhs = {0};
|
||||||
continue;
|
Operand rhs = {0};
|
||||||
}
|
check_expr(c, &lhs, ie->left);
|
||||||
|
if (x.mode == Addressing_Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lhs.mode == Addressing_Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
check_expr(c, &rhs, ie->right);
|
||||||
|
if (rhs.mode == Addressing_Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
convert_to_typed(c, &y, x.type, 0);
|
if (!is_type_ordered(x.type)) {
|
||||||
if (y.mode == Addressing_Invalid) {
|
gbString str = type_to_string(x.type);
|
||||||
continue;
|
error_node(x.expr, "Unordered type `%s`, is invalid for an interval expression", str);
|
||||||
}
|
gb_string_free(str);
|
||||||
|
continue;
|
||||||
// NOTE(bill): the ordering here matters
|
}
|
||||||
Operand z = y;
|
|
||||||
check_comparison(c, &z, &x, Token_CmpEq);
|
|
||||||
if (z.mode == Addressing_Invalid) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (y.mode != Addressing_Constant) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (y.value.kind != ExactValue_Invalid) {
|
TokenKind op = {0};
|
||||||
HashKey key = hash_exact_value(y.value);
|
|
||||||
TypeAndToken *found = map_type_and_token_get(&seen, key);
|
|
||||||
if (found != NULL) {
|
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
|
||||||
isize count = map_type_and_token_multi_count(&seen, key);
|
|
||||||
TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
|
|
||||||
|
|
||||||
map_type_and_token_multi_get_all(&seen, key, taps);
|
Operand a = lhs;
|
||||||
bool continue_outer = false;
|
Operand b = rhs;
|
||||||
|
check_comparison(c, &a, &x, Token_LtEq);
|
||||||
|
if (a.mode == Addressing_Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (ie->op.kind) {
|
||||||
|
case Token_Ellipsis: op = Token_GtEq; break;
|
||||||
|
case Token_HalfClosed: op = Token_Gt; break;
|
||||||
|
default: error(ie->op, "Invalid interval operator"); continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (isize i = 0; i < count; i++) {
|
check_comparison(c, &b, &x, op);
|
||||||
TypeAndToken tap = taps[i];
|
if (b.mode == Addressing_Invalid) {
|
||||||
if (are_types_identical(y.type, tap.type)) {
|
continue;
|
||||||
TokenPos pos = tap.token.pos;
|
}
|
||||||
gbString expr_str = expr_to_string(y.expr);
|
|
||||||
error_node(y.expr,
|
switch (ie->op.kind) {
|
||||||
"Duplicate case `%s`\n"
|
case Token_Ellipsis: op = Token_LtEq; break;
|
||||||
"\tprevious case at %.*s(%td:%td)",
|
case Token_HalfClosed: op = Token_Lt; break;
|
||||||
expr_str,
|
default: error(ie->op, "Invalid interval operator"); continue;
|
||||||
LIT(pos.file), pos.line, pos.column);
|
}
|
||||||
gb_string_free(expr_str);
|
|
||||||
continue_outer = true;
|
Operand a1 = lhs;
|
||||||
break;
|
Operand b1 = rhs;
|
||||||
|
check_comparison(c, &a1, &b1, op);
|
||||||
|
} else {
|
||||||
|
Operand y = {0};
|
||||||
|
check_expr(c, &y, expr);
|
||||||
|
if (x.mode == Addressing_Invalid ||
|
||||||
|
y.mode == Addressing_Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_to_typed(c, &y, x.type, 0);
|
||||||
|
if (y.mode == Addressing_Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): the ordering here matters
|
||||||
|
Operand z = y;
|
||||||
|
check_comparison(c, &z, &x, Token_CmpEq);
|
||||||
|
if (z.mode == Addressing_Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (y.mode != Addressing_Constant) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (y.value.kind != ExactValue_Invalid) {
|
||||||
|
HashKey key = hash_exact_value(y.value);
|
||||||
|
TypeAndToken *found = map_type_and_token_get(&seen, key);
|
||||||
|
if (found != NULL) {
|
||||||
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||||
|
isize count = map_type_and_token_multi_count(&seen, key);
|
||||||
|
TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
|
||||||
|
|
||||||
|
map_type_and_token_multi_get_all(&seen, key, taps);
|
||||||
|
bool continue_outer = false;
|
||||||
|
|
||||||
|
for (isize i = 0; i < count; i++) {
|
||||||
|
TypeAndToken tap = taps[i];
|
||||||
|
if (are_types_identical(y.type, tap.type)) {
|
||||||
|
TokenPos pos = tap.token.pos;
|
||||||
|
gbString expr_str = expr_to_string(y.expr);
|
||||||
|
error_node(y.expr,
|
||||||
|
"Duplicate case `%s`\n"
|
||||||
|
"\tprevious case at %.*s(%td:%td)",
|
||||||
|
expr_str,
|
||||||
|
LIT(pos.file), pos.line, pos.column);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
continue_outer = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_temp_arena_memory_end(tmp);
|
||||||
|
|
||||||
|
if (continue_outer) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TypeAndToken tap = {y.type, ast_node_token(y.expr)};
|
||||||
gb_temp_arena_memory_end(tmp);
|
map_type_and_token_multi_insert(&seen, key, tap);
|
||||||
|
|
||||||
if (continue_outer) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TypeAndToken tap = {y.type, ast_node_token(y.expr)};
|
|
||||||
map_type_and_token_multi_insert(&seen, key, tap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6191,8 +6191,24 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
|||||||
for_array(j, cc->list) {
|
for_array(j, cc->list) {
|
||||||
AstNode *expr = cc->list.e[j];
|
AstNode *expr = cc->list.e[j];
|
||||||
next_cond = ir_new_block(proc, clause, "match.case.next");
|
next_cond = ir_new_block(proc, clause, "match.case.next");
|
||||||
|
irValue *cond = v_false;
|
||||||
irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, ir_build_expr(proc, expr));
|
if (expr->kind == AstNode_IntervalExpr) {
|
||||||
|
ast_node(ie, IntervalExpr, expr);
|
||||||
|
TokenKind op = {0};
|
||||||
|
switch (ie->op.kind) {
|
||||||
|
case Token_Ellipsis: op = Token_LtEq; break;
|
||||||
|
case Token_HalfClosed: op = Token_Lt; break;
|
||||||
|
default: GB_PANIC("Invalid interval operator"); break;
|
||||||
|
}
|
||||||
|
irValue *lhs = ir_build_expr(proc, ie->left);
|
||||||
|
irValue *rhs = ir_build_expr(proc, ie->right);
|
||||||
|
// TODO(bill): do short circuit here
|
||||||
|
irValue *cond_lhs = ir_emit_comp(proc, Token_LtEq, lhs, tag);
|
||||||
|
irValue *cond_rhs = ir_emit_comp(proc, op, tag, rhs);
|
||||||
|
cond = ir_emit_arith(proc, Token_And, cond_lhs, cond_rhs, t_bool);
|
||||||
|
} else {
|
||||||
|
cond = ir_emit_comp(proc, Token_CmpEq, tag, ir_build_expr(proc, expr));
|
||||||
|
}
|
||||||
ir_emit_if(proc, cond, body, next_cond);
|
ir_emit_if(proc, cond, body, next_cond);
|
||||||
ir_start_block(proc, next_cond);
|
ir_start_block(proc, next_cond);
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-1
@@ -3088,7 +3088,25 @@ AstNode *parse_case_clause(AstFile *f) {
|
|||||||
Token token = f->curr_token;
|
Token token = f->curr_token;
|
||||||
AstNodeArray list = make_ast_node_array(f);
|
AstNodeArray list = make_ast_node_array(f);
|
||||||
if (allow_token(f, Token_case)) {
|
if (allow_token(f, Token_case)) {
|
||||||
list = parse_rhs_expr_list(f);
|
list = make_ast_node_array(f);
|
||||||
|
for (;;) {
|
||||||
|
AstNode *e = parse_expr(f, false);
|
||||||
|
if (f->curr_token.kind == Token_Ellipsis ||
|
||||||
|
f->curr_token.kind == Token_HalfClosed) {
|
||||||
|
Token op = f->curr_token;
|
||||||
|
next_token(f);
|
||||||
|
AstNode *lhs = e;
|
||||||
|
AstNode *rhs = parse_expr(f, false);
|
||||||
|
e = ast_interval_expr(f, op, lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
array_add(&list, e);
|
||||||
|
if (f->curr_token.kind != Token_Comma ||
|
||||||
|
f->curr_token.kind == Token_EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_token(f);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
expect_token(f, Token_default);
|
expect_token(f, Token_default);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user