aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp257
1 files changed, 156 insertions, 101 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 60d31c70c..6e743e3ca 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -3435,152 +3435,207 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case BuiltinProc_min: {
// min :: proc(a, b: ordered) -> ordered
+ Type *original_type = operand->type;
Type *type = base_type(operand->type);
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
- gbString type_str = type_to_string(operand->type);
+ gbString type_str = type_to_string(original_type);
error(call, "Expected a ordered numeric type to 'min', got '%s'", type_str);
gb_string_free(type_str);
return false;
}
- Ast *other_arg = ce->args[1];
- Operand a = *operand;
- Operand b = {};
- check_expr(c, &b, other_arg);
- if (b.mode == Addressing_Invalid) {
- return false;
- }
- if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
- gbString type_str = type_to_string(b.type);
- error(call,
- "Expected a ordered numeric type to 'min', got '%s'",
- type_str);
- gb_string_free(type_str);
- return false;
- }
+ bool all_constant = operand->mode == Addressing_Constant;
- if (a.mode == Addressing_Constant &&
- b.mode == Addressing_Constant) {
- ExactValue x = a.value;
- ExactValue y = b.value;
+ auto operands = array_make<Operand>(heap_allocator(), 0, ce->args.count);
+ defer (array_free(&operands));
- operand->mode = Addressing_Constant;
- if (compare_exact_values(Token_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;
+ array_add(&operands, *operand);
- convert_to_typed(c, &a, b.type);
- if (a.mode == Addressing_Invalid) {
- return false;
- }
- convert_to_typed(c, &b, a.type);
+ for (isize i = 1; i < ce->args.count; i++) {
+ Ast *other_arg = ce->args[i];
+ Operand b = {};
+ check_expr(c, &b, other_arg);
if (b.mode == Addressing_Invalid) {
return false;
}
-
- if (!are_types_identical(a.type, b.type)) {
- gbString type_a = type_to_string(a.type);
- gbString type_b = type_to_string(b.type);
+ if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
+ gbString type_str = type_to_string(b.type);
error(call,
- "Mismatched types to 'min', '%s' vs '%s'",
- type_a, type_b);
- gb_string_free(type_b);
- gb_string_free(type_a);
+ "Expected a ordered numeric type to 'min', got '%s'",
+ type_str);
+ gb_string_free(type_str);
return false;
}
+ array_add(&operands, b);
+
+ if (all_constant) {
+ all_constant = b.mode == Addressing_Constant;
+ }
+ }
+
+ if (all_constant) {
+ ExactValue value = operands[0].value;
+ Type *type = operands[0].type;
+ for (isize i = 1; i < operands.count; i++) {
+ Operand y = operands[i];
+ if (compare_exact_values(Token_Lt, value, y.value)) {
+ // okay
+ } else {
+ value = y.value;
+ type = y.type;
+ }
+ }
+ operand->value = value;
+ operand->type = type;
+ } else {
+ operand->mode = Addressing_Value;
+ operand->type = original_type;
+
+ for_array(i, operands) {
+ Operand *a = &operands[i];
+ for_array(j, operands) {
+ if (i == j) {
+ continue;
+ }
+ Operand *b = &operands[j];
+
+ convert_to_typed(c, a, b->type);
+ if (a->mode == Addressing_Invalid) {
+ return false;
+ }
+ convert_to_typed(c, b, a->type);
+ if (b->mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ }
+
+ for (isize i = 0; i < operands.count-1; i++) {
+ Operand *a = &operands[i];
+ Operand *b = &operands[i+1];
+
+ if (!are_types_identical(a->type, b->type)) {
+ gbString type_a = type_to_string(a->type);
+ gbString type_b = type_to_string(b->type);
+ error(a->expr,
+ "Mismatched types to 'min', '%s' vs '%s'",
+ type_a, type_b);
+ gb_string_free(type_b);
+ gb_string_free(type_a);
+ return false;
+ }
+ }
+
{
- Type *bt = base_type(a.type);
+ Type *bt = base_type(operands[0].type);
if (are_types_identical(bt, t_f32)) add_package_dependency(c, "runtime", "__min_f32");
if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "__min_f64");
}
-
}
-
-
break;
}
case BuiltinProc_max: {
- // min :: proc(a, b: ordered) -> ordered
+ // max :: proc(a, b: ordered) -> ordered
+ Type *original_type = operand->type;
Type *type = base_type(operand->type);
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
- gbString type_str = type_to_string(operand->type);
- error(call,
- "Expected a ordered numeric or string type to 'max', got '%s'",
- type_str);
+ gbString type_str = type_to_string(original_type);
+ error(call, "Expected a ordered numeric type to 'max', got '%s'", type_str);
gb_string_free(type_str);
return false;
}
- Ast *other_arg = ce->args[1];
- Operand a = *operand;
- Operand b = {};
- check_expr(c, &b, other_arg);
- if (b.mode == Addressing_Invalid) {
- return false;
- }
- if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
- gbString type_str = type_to_string(b.type);
- error(call,
- "Expected a ordered numeric or string type to 'max', got '%s'",
- type_str);
- gb_string_free(type_str);
- return false;
- }
+ bool all_constant = operand->mode == Addressing_Constant;
- if (a.mode == Addressing_Constant &&
- b.mode == Addressing_Constant) {
- ExactValue x = a.value;
- ExactValue y = b.value;
+ auto operands = array_make<Operand>(heap_allocator(), 0, ce->args.count);
+ defer (array_free(&operands));
- operand->mode = Addressing_Constant;
- if (compare_exact_values(Token_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;
+ array_add(&operands, *operand);
- convert_to_typed(c, &a, b.type);
- if (a.mode == Addressing_Invalid) {
- return false;
- }
- convert_to_typed(c, &b, a.type);
+
+ for (isize i = 1; i < ce->args.count; i++) {
+ Ast *arg = ce->args[i];
+ Operand b = {};
+ check_expr(c, &b, arg);
if (b.mode == Addressing_Invalid) {
return false;
}
-
- if (!are_types_identical(a.type, b.type)) {
- gbString type_a = type_to_string(a.type);
- gbString type_b = type_to_string(b.type);
- error(call,
- "Mismatched types to 'max', '%s' vs '%s'",
- type_a, type_b);
- gb_string_free(type_b);
- gb_string_free(type_a);
+ if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) {
+ gbString type_str = type_to_string(b.type);
+ error(arg,
+ "Expected a ordered numeric type to 'max', got '%s'",
+ type_str);
+ gb_string_free(type_str);
return false;
}
+ array_add(&operands, b);
- {
- Type *bt = base_type(a.type);
- if (bt == t_f32) add_package_dependency(c, "runtime", "__max_f32");
- if (bt == t_f64) add_package_dependency(c, "runtime", "__max_f64");
+ if (all_constant) {
+ all_constant = b.mode == Addressing_Constant;
}
}
+ if (all_constant) {
+ ExactValue value = operands[0].value;
+ Type *type = operands[0].type;
+ for (isize i = 1; i < operands.count; i++) {
+ Operand y = operands[i];
+ if (compare_exact_values(Token_Gt, value, y.value)) {
+ // okay
+ } else {
+ type = y.type;
+ value = y.value;
+ }
+ }
+ operand->value = value;
+ operand->type = type;
+ } else {
+ operand->mode = Addressing_Value;
+ operand->type = original_type;
+
+ for_array(i, operands) {
+ Operand *a = &operands[i];
+ for_array(j, operands) {
+ if (i == j) {
+ continue;
+ }
+ Operand *b = &operands[j];
+
+ convert_to_typed(c, a, b->type);
+ if (a->mode == Addressing_Invalid) {
+ return false;
+ }
+ convert_to_typed(c, b, a->type);
+ if (b->mode == Addressing_Invalid) {
+ return false;
+ }
+ }
+ }
+
+ for (isize i = 0; i < operands.count-1; i++) {
+ Operand *a = &operands[i];
+ Operand *b = &operands[i+1];
+
+ if (!are_types_identical(a->type, b->type)) {
+ gbString type_a = type_to_string(a->type);
+ gbString type_b = type_to_string(b->type);
+ error(a->expr,
+ "Mismatched types to 'max', '%s' vs '%s'",
+ type_a, type_b);
+ gb_string_free(type_b);
+ gb_string_free(type_a);
+ return false;
+ }
+ }
+ {
+ Type *bt = base_type(operands[0].type);
+ if (are_types_identical(bt, t_f32)) add_package_dependency(c, "runtime", "__max_f32");
+ if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "__max_f64");
+ }
+ }
break;
}