diff options
| author | gingerBill <bill@gingerbill.org> | 2023-08-07 14:53:31 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2023-08-07 14:53:31 +0100 |
| commit | 8201a9ce6ea1d2a89d51f891305d27f5196dc6c9 (patch) | |
| tree | c2709ebebbc952ad15ca625b808cdf949b443d10 /src/tilde_stmt.cpp | |
| parent | 561a94cc50d2957bc82cecbf4ccd1f6f1a99f1a3 (diff) | |
Tilde: `for in` for `enum` types
Diffstat (limited to 'src/tilde_stmt.cpp')
| -rw-r--r-- | src/tilde_stmt.cpp | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index c3673fb58..26faab442 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1598,6 +1598,58 @@ gb_internal void cg_build_range_stmt_indexed(cgProcedure *p, cgValue expr, Type } +gb_internal void cg_build_range_stmt_enum(cgProcedure *p, Type *enum_type, Type *val_type, cgValue *val_, cgValue *idx_, TB_Node **loop_, TB_Node **done_) { + Type *t = enum_type; + GB_ASSERT(is_type_enum(t)); + t = base_type(t); + Type *core_elem = core_type(t); + GB_ASSERT(t->kind == Type_Enum); + i64 enum_count = t->Enum.fields.count; + cgValue max_count = cg_const_int(p, t_int, enum_count); + + cgValue ti = cg_type_info(p, t); + cgValue variant = cg_emit_struct_ep(p, ti, 4); + cgValue eti_ptr = cg_emit_conv(p, variant, t_type_info_enum_ptr); + cgValue values = cg_emit_load(p, cg_emit_struct_ep(p, eti_ptr, 2)); + cgValue values_data = cg_builtin_raw_data(p, values); + + cgAddr offset_ = cg_add_local(p, t_int, nullptr, false); + cg_addr_store(p, offset_, cg_const_int(p, t_int, 0)); + + TB_Node *loop = cg_control_region(p, "for_enum_loop"); + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, loop); + + TB_Node *body = cg_control_region(p, "for_enum_body"); + TB_Node *done = cg_control_region(p, "for_enum_done"); + + cgValue offset = cg_addr_load(p, offset_); + cgValue cond = cg_emit_comp(p, Token_Lt, offset, max_count); + cg_emit_if(p, cond, body, done); + tb_inst_set_control(p->func, body); + + cgValue val_ptr = cg_emit_ptr_offset(p, values_data, offset); + cg_emit_increment(p, offset_.addr); + + cgValue val = {}; + if (val_type != nullptr) { + GB_ASSERT(are_types_identical(enum_type, val_type)); + + if (is_type_integer(core_elem)) { + cgValue i = cg_emit_load(p, cg_emit_conv(p, val_ptr, t_i64_ptr)); + val = cg_emit_conv(p, i, t); + } else { + GB_PANIC("TODO(bill): enum core type %s", type_to_string(core_elem)); + } + } + + if (val_) *val_ = val; + if (idx_) *idx_ = offset; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + + gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { ast_node(rs, RangeStmt, node); @@ -1640,7 +1692,7 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { TypeAndValue tav = type_and_value_of_expr(expr); if (tav.mode == Addressing_Type) { - GB_PANIC("TODO(bill): range statement over enum type"); + cg_build_range_stmt_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done); } else { Type *expr_type = type_of_expr(expr); Type *et = base_type(type_deref(expr_type)); |