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.cpp128
1 files changed, 126 insertions, 2 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 932f9c061..60ae9bc7a 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -51,6 +51,7 @@ typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
void check_expr (CheckerContext *c, Operand *operand, Ast *expression);
void check_multi_expr (CheckerContext *c, Operand *operand, Ast *expression);
+void check_multi_expr_or_type (CheckerContext *c, Operand *operand, Ast *expression);
void check_expr_or_type (CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint = nullptr);
ExprKind check_expr_base (CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint);
void check_expr_with_type_hint (CheckerContext *c, Operand *o, Ast *e, Type *t);
@@ -3029,6 +3030,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case BuiltinProc_type_info_of:
case BuiltinProc_typeid_of:
case BuiltinProc_len:
+ case BuiltinProc_min:
+ case BuiltinProc_max:
// NOTE(bill): The first arg may be a Type, this will be checked case by case
break;
@@ -3602,7 +3605,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
case BuiltinProc_min: {
- // min :: proc(a, b: ordered) -> ordered
+ // min :: proc($T: typeid) -> ordered
+ // min :: proc(a: ..ordered) -> ordered
+
+ check_multi_expr_or_type(c, operand, ce->args[0]);
+
Type *original_type = operand->type;
Type *type = base_type(operand->type);
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
@@ -3612,6 +3619,55 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
+ if (operand->mode == Addressing_Type) {
+ if (is_type_boolean(type)) {
+ operand->mode = Addressing_Constant;
+ operand->type = original_type;
+ operand->value = exact_value_bool(false);
+ return true;
+ } else if (is_type_integer(type)) {
+ operand->mode = Addressing_Constant;
+ operand->type = original_type;
+ if (is_type_unsigned(type)) {
+ operand->value = exact_value_u64(0);
+ return true;
+ } else {
+ i64 sz = 8*type_size_of(type);
+ ExactValue a = exact_value_i64(1);
+ ExactValue b = exact_value_i64(sz-1);
+ ExactValue v = exact_binary_operator_value(Token_Shl, a, b);
+ v = exact_unary_operator_value(Token_Sub, v, cast(i32)sz, false);
+ operand->value = v;
+ return true;
+ }
+ } else if (is_type_float(type)) {
+ operand->mode = Addressing_Constant;
+ operand->type = original_type;
+ switch (type_size_of(type)) {
+ case 4:
+ operand->value = exact_value_float(-3.402823466e+38f);
+ break;
+ case 8:
+ operand->value = exact_value_float(-1.7976931348623158e+308);
+ break;
+ default:
+ GB_PANIC("Unhandled float type");
+ break;
+ }
+ return true;
+ } else if (is_type_enum(type)) {
+ operand->mode = Addressing_Constant;
+ operand->type = original_type;
+ operand->value = type->Enum.min_value;
+ return true;
+ }
+ gbString type_str = type_to_string(original_type);
+ error(call, "Invalid type for 'min', got %s", type_str);
+ gb_string_free(type_str);
+ return false;
+ }
+
+
bool all_constant = operand->mode == Addressing_Constant;
auto operands = array_make<Operand>(heap_allocator(), 0, ce->args.count);
@@ -3705,7 +3761,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
case BuiltinProc_max: {
- // max :: proc(a, b: ordered) -> ordered
+ // max :: proc($T: typeid) -> ordered
+ // max :: proc(a: ..ordered) -> ordered
+
+ check_multi_expr_or_type(c, operand, ce->args[0]);
+
Type *original_type = operand->type;
Type *type = base_type(operand->type);
if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) {
@@ -3715,6 +3775,59 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
+ if (operand->mode == Addressing_Type) {
+ if (is_type_boolean(type)) {
+ operand->mode = Addressing_Constant;
+ operand->type = original_type;
+ operand->value = exact_value_bool(true);
+ return true;
+ } else if (is_type_integer(type)) {
+ operand->mode = Addressing_Constant;
+ operand->type = original_type;
+ if (is_type_unsigned(type)) {
+ i64 sz = 8*type_size_of(type);
+ ExactValue a = exact_value_i64(1);
+ ExactValue b = exact_value_i64(sz);
+ ExactValue v = exact_binary_operator_value(Token_Shl, a, b);
+ v = exact_binary_operator_value(Token_Sub, v, a);
+ operand->value = v;
+ return true;
+ } else {
+ i64 sz = 8*type_size_of(type);
+ ExactValue a = exact_value_i64(1);
+ ExactValue b = exact_value_i64(sz-1);
+ ExactValue v = exact_binary_operator_value(Token_Shl, a, b);
+ v = exact_binary_operator_value(Token_Sub, v, a);
+ operand->value = v;
+ return true;
+ }
+ } else if (is_type_float(type)) {
+ operand->mode = Addressing_Constant;
+ operand->type = original_type;
+ switch (type_size_of(type)) {
+ case 4:
+ operand->value = exact_value_float(3.402823466e+38f);
+ break;
+ case 8:
+ operand->value = exact_value_float(1.7976931348623158e+308);
+ break;
+ default:
+ GB_PANIC("Unhandled float type");
+ break;
+ }
+ return true;
+ } else if (is_type_enum(type)) {
+ operand->mode = Addressing_Constant;
+ operand->type = original_type;
+ operand->value = type->Enum.max_value;
+ return true;
+ }
+ gbString type_str = type_to_string(original_type);
+ error(call, "Invalid type for 'max', got %s", type_str);
+ gb_string_free(type_str);
+ return false;
+ }
+
bool all_constant = operand->mode == Addressing_Constant;
auto operands = array_make<Operand>(heap_allocator(), 0, ce->args.count);
@@ -6464,6 +6577,17 @@ ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hi
}
+void check_multi_expr_or_type(CheckerContext *c, Operand *o, Ast *e) {
+ check_expr_base(c, o, e, nullptr);
+ switch (o->mode) {
+ default:
+ return; // NOTE(bill): Valid
+ case Addressing_NoValue:
+ error_operand_no_value(o);
+ break;
+ }
+ o->mode = Addressing_Invalid;
+}
void check_multi_expr(CheckerContext *c, Operand *o, Ast *e) {
check_expr_base(c, o, e, nullptr);