Interval expressions for match statements

This commit is contained in:
Ginger Bill
2017-04-21 00:13:20 +01:00
parent a713e33007
commit 9a1566d665
4 changed files with 149 additions and 54 deletions
+1 -1
View File
@@ -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);
+62 -1
View File
@@ -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,8 +964,61 @@ 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};
if (expr->kind == AstNode_IntervalExpr) {
ast_node(ie, IntervalExpr, expr);
Operand lhs = {0};
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;
}
if (!is_type_ordered(x.type)) {
gbString str = type_to_string(x.type);
error_node(x.expr, "Unordered type `%s`, is invalid for an interval expression", str);
gb_string_free(str);
continue;
}
TokenKind op = {0};
Operand a = lhs;
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;
}
check_comparison(c, &b, &x, op);
if (b.mode == Addressing_Invalid) {
continue;
}
switch (ie->op.kind) {
case Token_Ellipsis: op = Token_LtEq; break;
case Token_HalfClosed: op = Token_Lt; break;
default: error(ie->op, "Invalid interval operator"); continue;
}
Operand a1 = lhs;
Operand b1 = rhs;
check_comparison(c, &a1, &b1, op);
} else {
Operand y = {0};
check_expr(c, &y, expr); check_expr(c, &y, expr);
if (x.mode == Addressing_Invalid || if (x.mode == Addressing_Invalid ||
y.mode == Addressing_Invalid) { y.mode == Addressing_Invalid) {
@@ -1018,6 +1078,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
map_type_and_token_multi_insert(&seen, key, tap); map_type_and_token_multi_insert(&seen, key, tap);
} }
} }
}
check_open_scope(c, stmt); check_open_scope(c, stmt);
u32 ft_flags = mod_flags; u32 ft_flags = mod_flags;
+18 -2
View File
@@ -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
View File
@@ -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);
} }