min & max for types

This commit is contained in:
gingerBill
2018-12-27 12:12:14 +00:00
parent cc14180e9d
commit 7c982b6e10
4 changed files with 132 additions and 4 deletions

View File

@@ -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);