aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2018-12-27 12:12:14 +0000
committergingerBill <bill@gingerbill.org>2018-12-27 12:12:14 +0000
commit7c982b6e109d9e9b4b99c728eea0a3aa5b0849d7 (patch)
tree22b90486b58ad57dae0f22d4f1313dc27603e4a3 /src
parentcc14180e9d37a397f9a3d7b028397f222ffa565b (diff)
min & max for types
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp128
-rw-r--r--src/check_type.cpp2
-rw-r--r--src/checker.hpp4
-rw-r--r--src/types.cpp2
4 files changed, 132 insertions, 4 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);
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<Entity *> variables; /* Entity_Variable */ \