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(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(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); diff --git a/src/check_type.cpp b/src/check_type.cpp index 63835dd76..eb1496bdc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -833,6 +833,8 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast enum_type->Enum.fields = fields; enum_type->Enum.names = make_names_field_for_struct(ctx, ctx->scope); + enum_type->Enum.min_value = min_value; + enum_type->Enum.max_value = max_value; } diff --git a/src/checker.hpp b/src/checker.hpp index e7b689b17..e5a4dd0aa 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -185,8 +185,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("min"), 2, true, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("max"), 2, true, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin}, diff --git a/src/types.cpp b/src/types.cpp index 512505007..839c237c5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -171,6 +171,8 @@ struct TypeUnion { Scope * scope; \ Entity * names; \ Type * base_type; \ + ExactValue min_value; \ + ExactValue max_value; \ }) \ TYPE_KIND(Tuple, struct { \ Array variables; /* Entity_Variable */ \