mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-18 08:58:23 +00:00
Add compress_values
This commit is contained in:
@@ -119,7 +119,8 @@ jmag :: proc(value: Quaternion) -> Float ---
|
||||
kmag :: proc(value: Quaternion) -> Float ---
|
||||
conj :: proc(value: Complex_Or_Quaternion) -> Complex_Or_Quaternion ---
|
||||
|
||||
expand_values :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
|
||||
expand_values :: proc(value: Struct_Or_Array) -> (A, B, C, ...) ---
|
||||
compress_values :: proc(values: ...) -> Struct_Or_Array_Like_Type ---
|
||||
|
||||
min :: proc(values: ..T) -> T ---
|
||||
max :: proc(values: ..T) -> T ---
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,6 +26,7 @@ enum BuiltinProcId {
|
||||
BuiltinProc_conj,
|
||||
|
||||
BuiltinProc_expand_values,
|
||||
BuiltinProc_compress_values,
|
||||
|
||||
BuiltinProc_min,
|
||||
BuiltinProc_max,
|
||||
@@ -376,6 +377,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("expand_values"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("compress_values"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
{STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
{STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin},
|
||||
|
||||
@@ -2246,6 +2246,68 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
return lb_emit_load(p, tuple);
|
||||
}
|
||||
|
||||
case BuiltinProc_compress_values: {
|
||||
isize value_count = 0;
|
||||
for (Ast *arg : ce->args) {
|
||||
Type *t = arg->tav.type;
|
||||
if (is_type_tuple(t)) {
|
||||
value_count += t->Tuple.variables.count;
|
||||
} else {
|
||||
value_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (value_count == 1) {
|
||||
lbValue x = lb_build_expr(p, ce->args[0]);
|
||||
x = lb_emit_conv(p, x, tv.type);
|
||||
return x;
|
||||
}
|
||||
|
||||
Type *dt = base_type(tv.type);
|
||||
lbAddr addr = lb_add_local_generated(p, tv.type, true);
|
||||
if (is_type_struct(dt) || is_type_tuple(dt)) {
|
||||
i32 index = 0;
|
||||
for (Ast *arg : ce->args) {
|
||||
lbValue x = lb_build_expr(p, arg);
|
||||
if (is_type_tuple(x.type)) {
|
||||
for (isize i = 0; i < x.type->Tuple.variables.count; i++) {
|
||||
lbValue y = lb_emit_tuple_ev(p, x, cast(i32)i);
|
||||
lbValue ptr = lb_emit_struct_ep(p, addr.addr, index++);
|
||||
y = lb_emit_conv(p, y, type_deref(ptr.type));
|
||||
lb_emit_store(p, ptr, y);
|
||||
}
|
||||
} else {
|
||||
lbValue ptr = lb_emit_struct_ep(p, addr.addr, index++);
|
||||
x = lb_emit_conv(p, x, type_deref(ptr.type));
|
||||
lb_emit_store(p, ptr, x);
|
||||
}
|
||||
}
|
||||
GB_ASSERT(index == value_count);
|
||||
} else if (is_type_array_like(dt)) {
|
||||
i32 index = 0;
|
||||
for (Ast *arg : ce->args) {
|
||||
lbValue x = lb_build_expr(p, arg);
|
||||
if (is_type_tuple(x.type)) {
|
||||
for (isize i = 0; i < x.type->Tuple.variables.count; i++) {
|
||||
lbValue y = lb_emit_tuple_ev(p, x, cast(i32)i);
|
||||
lbValue ptr = lb_emit_array_epi(p, addr.addr, index++);
|
||||
y = lb_emit_conv(p, y, type_deref(ptr.type));
|
||||
lb_emit_store(p, ptr, y);
|
||||
}
|
||||
} else {
|
||||
lbValue ptr = lb_emit_array_epi(p, addr.addr, index++);
|
||||
x = lb_emit_conv(p, x, type_deref(ptr.type));
|
||||
lb_emit_store(p, ptr, x);
|
||||
}
|
||||
}
|
||||
GB_ASSERT(index == value_count);
|
||||
} else {
|
||||
GB_PANIC("TODO(bill): compress_values -> %s", type_to_string(tv.type));
|
||||
}
|
||||
|
||||
return lb_addr_load(p, addr);
|
||||
}
|
||||
|
||||
case BuiltinProc_min: {
|
||||
Type *t = type_of_expr(expr);
|
||||
if (ce->args.count == 2) {
|
||||
|
||||
Reference in New Issue
Block a user