diff options
Diffstat (limited to 'src/checker/expr.cpp')
| -rw-r--r-- | src/checker/expr.cpp | 167 |
1 files changed, 160 insertions, 7 deletions
diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 39fa66e3d..36f3f50fc 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -878,10 +878,11 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac } else if (is_type_string(type)) { return in_value.kind == ExactValue_String; } else if (is_type_integer(type)) { - if (in_value.kind != ExactValue_Integer) + ExactValue v = exact_value_to_integer(in_value); + if (v.kind != ExactValue_Integer) return false; - if (out_value) *out_value = in_value; - i64 i = in_value.value_integer; + if (out_value) *out_value = v; + i64 i = v.value_integer; i64 s = 8*type_size_of(c->sizes, c->allocator, type); u64 umax = ~0ull; if (s < 64) { @@ -1282,7 +1283,6 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { Type *base_type = get_base_type(type); if (is_const_expr && is_type_constant_type(base_type)) { - if (base_type->kind == Type_Basic) { if (check_value_is_expressible(c, x->value, base_type, &x->value)) { can_convert = true; @@ -1295,10 +1295,12 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { if (!can_convert) { gbString expr_str = expr_to_string(x->expr); - gbString type_str = type_to_string(type); + gbString to_type = type_to_string(type); + gbString from_type = type_to_string(x->type); defer (gb_string_free(expr_str)); - defer (gb_string_free(type_str)); - error(&c->error_collector, ast_node_token(x->expr), "Cannot cast `%s` as `%s`", expr_str, type_str); + defer (gb_string_free(to_type)); + defer (gb_string_free(from_type)); + error(&c->error_collector, ast_node_token(x->expr), "Cannot cast `%s` as `%s` from `%s`", expr_str, to_type, from_type); x->mode = Addressing_Invalid; return; @@ -2342,6 +2344,157 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->mode = Addressing_Value; } break; + case BuiltinProc_min: { + // min :: proc(a, b: comparable) -> comparable + Type *type = get_base_type(operand->type); + if (!is_type_comparable(type) || !is_type_numeric(type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a comparable numeric type to `min`, got `%s`", + type_str); + return false; + } + + AstNode *other_arg = ce->arg_list->next; + Operand a = *operand; + Operand b = {}; + check_expr(c, &b, other_arg); + if (b.mode == Addressing_Invalid) + return false; + if (!is_type_comparable(b.type) || !is_type_numeric(type)) { + gbString type_str = type_to_string(b.type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a comparable numeric type to `min`, got `%s`", + type_str); + return false; + } + + + if (a.mode == Addressing_Constant && + b.mode == Addressing_Constant) { + ExactValue x = a.value; + ExactValue y = b.value; + Token lt = {Token_Lt}; + + operand->mode = Addressing_Constant; + if (compare_exact_values(lt, x, y)) { + operand->value = x; + operand->type = a.type; + } else { + operand->value = y; + operand->type = b.type; + } + } else { + operand->mode = Addressing_Value; + operand->type = type; + + if (!are_types_identical(operand->type, b.type)) { + gbString type_a = type_to_string(a.type); + gbString type_b = type_to_string(b.type); + defer (gb_string_free(type_a)); + defer (gb_string_free(type_b)); + error(&c->error_collector, ast_node_token(call), + "Mismatched types to `min`, `%s` vs `%s`", + type_a, type_b); + return false; + } + } + + } break; + + case BuiltinProc_max: { + // min :: proc(a, b: comparable) -> comparable + Type *type = get_base_type(operand->type); + if (!is_type_comparable(type) || !is_type_numeric(type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a comparable numeric type to `max`, got `%s`", + type_str); + return false; + } + + AstNode *other_arg = ce->arg_list->next; + Operand a = *operand; + Operand b = {}; + check_expr(c, &b, other_arg); + if (b.mode == Addressing_Invalid) + return false; + if (!is_type_comparable(b.type) || !is_type_numeric(type)) { + gbString type_str = type_to_string(b.type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a comparable numeric type to `max`, got `%s`", + type_str); + return false; + } + + + if (a.mode == Addressing_Constant && + b.mode == Addressing_Constant) { + ExactValue x = a.value; + ExactValue y = b.value; + Token gt = {Token_Gt}; + + operand->mode = Addressing_Constant; + if (compare_exact_values(gt, x, y)) { + operand->value = x; + operand->type = a.type; + } else { + operand->value = y; + operand->type = b.type; + } + } else { + operand->mode = Addressing_Value; + operand->type = type; + + if (!are_types_identical(operand->type, b.type)) { + gbString type_a = type_to_string(a.type); + gbString type_b = type_to_string(b.type); + defer (gb_string_free(type_a)); + defer (gb_string_free(type_b)); + error(&c->error_collector, ast_node_token(call), + "Mismatched types to `max`, `%s` vs `%s`", + type_a, type_b); + return false; + } + } + + } break; + + case BuiltinProc_abs: { + // abs :: proc(n: numeric) -> numeric + Type *type = get_base_type(operand->type); + if (!is_type_numeric(type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(&c->error_collector, ast_node_token(call), + "Expected a numeric type to `abs`, got `%s`", + type_str); + return false; + } + + if (operand->mode == Addressing_Constant) { + switch (operand->value.kind) { + case ExactValue_Integer: + operand->value.value_integer = gb_abs(operand->value.value_integer); + break; + case ExactValue_Float: + operand->value.value_float = gb_abs(operand->value.value_float); + break; + default: + GB_PANIC("Invalid numeric constant"); + break; + } + } else { + operand->mode = Addressing_Value; + } + + operand->type = type; + } break; + } return true; |