Add compress_values

This commit is contained in:
gingerBill
2025-05-12 15:29:43 +01:00
parent 8e17ccfd98
commit d2d4ac8120
4 changed files with 246 additions and 1 deletions

View File

@@ -3243,6 +3243,186 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
break;
}
case BuiltinProc_compress_values: {
Operand *ops = gb_alloc_array(temporary_allocator(), Operand, ce->args.count);
isize value_count = 0;
for_array(i, ce->args) {
Ast *arg = ce->args[i];
Operand *op = &ops[i];
check_multi_expr(c, op, arg);
if (op->mode == Addressing_Invalid) {
return false;
}
if (op->type == nullptr || op->type == t_invalid) {
gbString s = expr_to_string(op->expr);
error(op->expr, "Invalid expression to '%.*s', got %s", LIT(builtin_name), s);
gb_string_free(s);
}
if (is_type_tuple(op->type)) {
value_count += op->type->Tuple.variables.count;
} else {
value_count += 1;
}
}
GB_ASSERT(value_count >= 1);
if (value_count == 1) {
*operand = ops[0];
break;
}
if (type_hint != nullptr) {
Type *th = base_type(type_hint);
if (th->kind == Type_Struct) {
if (value_count == th->Struct.fields.count) {
isize index = 0;
for_array(i, ce->args) {
Operand *op = &ops[i];
if (is_type_tuple(op->type)) {
for (Entity *v : op->type->Tuple.variables) {
Operand x = {};
x.mode = Addressing_Value;
x.type = v->type;
check_assignment(c, &x, th->Struct.fields[index++]->type, builtin_name);
if (x.mode == Addressing_Invalid) {
return false;
}
}
} else {
check_assignment(c, op, th->Struct.fields[index++]->type, builtin_name);
if (op->mode == Addressing_Invalid) {
return false;
}
}
}
operand->type = type_hint;
operand->mode = Addressing_Value;
break;
}
} else if (is_type_array_like(th)) {
if (cast(i64)value_count == get_array_type_count(th)) {
Type *elem = base_array_type(th);
for_array(i, ce->args) {
Operand *op = &ops[i];
if (is_type_tuple(op->type)) {
for (Entity *v : op->type->Tuple.variables) {
Operand x = {};
x.mode = Addressing_Value;
x.type = v->type;
check_assignment(c, &x, elem, builtin_name);
if (x.mode == Addressing_Invalid) {
return false;
}
}
} else {
check_assignment(c, op, elem, builtin_name);
if (op->mode == Addressing_Invalid) {
return false;
}
}
}
operand->type = type_hint;
operand->mode = Addressing_Value;
break;
}
}
}
bool all_types_the_same = true;
Type *last_type = nullptr;
for_array(i, ce->args) {
Operand *op = &ops[i];
if (is_type_tuple(op->type)) {
if (last_type == nullptr) {
op->type->Tuple.variables[0]->type;
}
for (Entity *v : op->type->Tuple.variables) {
if (!are_types_identical(last_type, v->type)) {
all_types_the_same = false;
break;
}
last_type = v->type;
}
} else {
if (last_type == nullptr) {
last_type = op->type;
} else {
if (!are_types_identical(last_type, op->type)) {
all_types_the_same = false;
break;
}
last_type = op->type;
}
}
}
if (all_types_the_same) {
operand->type = alloc_type_array(last_type, value_count);
operand->mode = Addressing_Value;
} else {
Type *st = alloc_type_struct_complete();
st->Struct.fields = slice_make<Entity *>(permanent_allocator(), value_count);
st->Struct.tags = gb_alloc_array(permanent_allocator(), String, value_count);
st->Struct.offsets = gb_alloc_array(permanent_allocator(), i64, value_count);
Scope *scope = create_scope(c->info, nullptr);
Token token = {};
token.kind = Token_Ident;
token.pos = ast_token(call).pos;
isize index = 0;
for_array(i, ce->args) {
Operand *op = &ops[i];
if (is_type_tuple(op->type)) {
for (Entity *v : op->type->Tuple.variables) {
Type *t = default_type(v->type);
if (is_type_untyped(t)) {
gbString s = expr_to_string(op->expr);
error(op->expr, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name));
gb_string_free(s);
return false;
}
gbString s = gb_string_make_reserve(permanent_allocator(), 32);
s = gb_string_append_fmt(s, "v%lld", cast(long long)index);
token.string = make_string_c(s);
Entity *e = alloc_entity_field(scope, token, t, false, cast(i32)index, EntityState_Resolved);
st->Struct.fields[index++] = e;
}
} else {
Type *t = default_type(op->type);
if (is_type_untyped(t)) {
gbString s = expr_to_string(op->expr);
error(op->expr, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name));
gb_string_free(s);
return false;
}
gbString s = gb_string_make_reserve(permanent_allocator(), 32);
s = gb_string_append_fmt(s, "v%lld", cast(long long)index);
token.string = make_string_c(s);
Entity *e = alloc_entity_field(scope, token, t, false, cast(i32)index, EntityState_Resolved);
st->Struct.fields[index++] = e;
}
}
gb_unused(type_size_of(st));
operand->type = st;
operand->mode = Addressing_Value;
}
break;
}
case BuiltinProc_min: {
// min :: proc($T: typeid) -> ordered
// min :: proc(a: ..ordered) -> ordered