diff --git a/code/demo.odin b/code/demo.odin index 90ac11858..d91d1d5c7 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -11,20 +11,40 @@ main :: proc() { - m: map[string]u32; - reserve(^m, 16); - defer free(m); + { + m := map[f32]int{}; + reserve(^m, 16); + defer free(m); - m["a"] = 56; - m["b"] = 13453; - m["c"] = 7654; - c := m["c"]; - _, ok := m["c"]; - assert(ok && c == 7654); + m[1.0] = 1278; + m[2.0] = 7643; + m[3.0] = 564; + c := m[3.0]; + _, ok := m[3.0]; + assert(ok && c == 564); - for val, key in m { - fmt.printf("m[\"%s\"] == %v\n", key, val); + for val, key in m { + fmt.printf("m[%f] == %v\n", key, val); + } } + { + m := map[string]u32{ + "a" = 56, + "b" = 13453, + "c" = 7654, + }; + defer free(m); + + c := m["c"]; + _, ok := m["c"]; + assert(ok && c == 7654); + + for val, key in m { + fmt.printf("m[\"%s\"] == %v\n", key, val); + } + } + + // fm: map[128, int]f32; diff --git a/src/check_expr.c b/src/check_expr.c index b271a62f9..13f66d060 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -2885,14 +2885,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id Type *type = operand->type; if (!is_type_pointer(type)) { gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str); + error_node(operand->expr, "Expected a pointer, got `%s`", str); gb_string_free(str); return false; } type = type_deref(type); - if (!is_type_dynamic_array(type)) { + if (!is_type_dynamic_array(type) && !is_type_map(type)) { gbString str = type_to_string(type); - error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str); + error_node(operand->expr, "Expected a pointer to a map or dynamic array, got `%s`", str); gb_string_free(str); return false; } @@ -4750,6 +4750,31 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } } break; + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + is_constant = false; + { // Checker values + for_array(i, cl->elems) { + AstNode *elem = cl->elems.e[i]; + if (elem->kind != AstNode_FieldValue) { + error_node(elem, "Only `field = value` elements are allowed in a map literal"); + continue; + } + ast_node(fv, FieldValue, elem); + check_expr_with_type_hint(c, o, fv->field, t->Map.key); + check_assignment(c, o, t->Map.key, str_lit("map literal")); + if (o->mode == Addressing_Invalid) { + continue; + } + + check_expr_with_type_hint(c, o, fv->value, t->Map.value); + check_assignment(c, o, t->Map.value, str_lit("map literal")); + } + } + } break; + default: { gbString str = type_to_string(type); error_node(node, "Invalid compound literal type `%s`", str); diff --git a/src/ir.c b/src/ir.c index 7d04a0dd4..c7d97fd15 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1386,6 +1386,10 @@ void ir_emit_startup_runtime(irProcedure *proc) { ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime)); } +irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { + return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); +} + irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right); @@ -1419,15 +1423,26 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type) return ir_emit_load(proc, h); } -irValue *ir_gen_map_key(irProcedure *proc, irValue *key) { +irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { irValue *v = ir_add_local_generated(proc, t_map_key); Type *t = base_type(ir_type(key)); + key = ir_emit_conv(proc, key, key_type); if (is_type_integer(t)) { ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, t_u64)); } else if (is_type_pointer(t)) { irValue *p = ir_emit_conv(proc, key, t_uint); ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, t_u64)); - } else { + } else if (is_type_float(t)) { + irValue *bits = NULL; + i64 size = type_size_of(proc->module->sizes, proc->module->allocator, t); + switch (8*size) { + case 32: bits = ir_emit_bitcast(proc, key, t_u32); break; + case 64: bits = ir_emit_bitcast(proc, key, t_u64); break; + default: GB_PANIC("Unhandled float size: %lld bits", size); break; + } + + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, bits, t_u64)); + } else if (is_type_string(t)) { irValue *str = ir_emit_conv(proc, key, t_string); irValue *hashed_str = NULL; @@ -1443,6 +1458,8 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key) { } ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), str); + } else { + GB_PANIC("Unhandled map key type"); } return ir_emit_load(proc, v); @@ -1478,37 +1495,35 @@ Type *ir_addr_type(irAddr addr) { return type_deref(t); } +irValue *ir_insert_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type, + irValue *map_key, irValue *map_value) { + map_type = base_type(map_type); + + irValue *h = ir_gen_map_header(proc, addr, map_type); + irValue *key = ir_gen_map_key(proc, map_key, map_type->Map.key); + irValue *v = ir_emit_conv(proc, map_value, map_type->Map.value); + irValue *ptr = ir_address_from_load_or_generate_local(proc, v); + ptr = ir_emit_conv(proc, ptr, t_rawptr); + + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); + args[0] = h; + args[1] = key; + args[2] = ptr; + + return ir_emit_global_call(proc, "__dynamic_map_set", args, 3); +} + irValue *ir_addr_store(irProcedure *proc, irAddr addr, irValue *value) { if (addr.addr == NULL) { return NULL; } if (addr.kind == irAddr_Map) { - Type *map_type = base_type(addr.map_type); - irValue *h = ir_gen_map_header(proc, addr.addr, map_type); - irValue *key = ir_gen_map_key(proc, addr.map_key); - irValue *v = ir_emit_conv(proc, value, map_type->Map.value); - irValue *ptr = ir_address_from_load_or_generate_local(proc, v); - ptr = ir_emit_conv(proc, ptr, t_rawptr); - - irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3); - args[0] = h; - args[1] = key; - args[2] = ptr; - - return ir_emit_global_call(proc, "__dynamic_map_set", args, 3); + return ir_insert_map_key_and_value(proc, addr.addr, addr.map_type, addr.map_key, value); } - // if (addr.kind == irAddr_Vector) { - // irValue *v = ir_emit_load(proc, addr.addr); - // Type *elem_type = base_type(ir_type(v))->Vector.elem; - // irValue *elem = ir_emit_conv(proc, value, elem_type); - // irValue *out = ir_emit(proc, ir_make_instr_insert_element(proc, v, elem, addr.Vector.index)); - // return ir_emit_store(proc, addr.addr, out); - // } else { - irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); - return ir_emit_store(proc, addr.addr, v); - // } + irValue *v = ir_emit_conv(proc, value, ir_addr_type(addr)); + return ir_emit_store(proc, addr.addr, v); } irValue *ir_addr_load(irProcedure *proc, irAddr addr) { @@ -1522,7 +1537,7 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) { Type *map_type = base_type(addr.map_type); irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type); irValue *h = ir_gen_map_header(proc, addr.addr, map_type); - irValue *key = ir_gen_map_key(proc, addr.map_key); + irValue *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key); irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2); args[0] = h; @@ -2092,9 +2107,6 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { return str_lit(""); } -irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) { - return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type)); -} irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { @@ -3183,9 +3195,19 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv case BuiltinProc_clear: { ir_emit_comment(proc, str_lit("reserve")); - irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]); - irValue *count_ptr = ir_emit_struct_ep(proc, array_ptr, 1); - ir_emit_store(proc, count_ptr, v_zero); + irValue *ptr = ir_build_expr(proc, ce->args.e[0]); + Type *t = base_type(type_deref(ir_type(ptr))); + if (is_type_dynamic_array(t)) { + irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, count_ptr, v_zero); + } else if (is_type_dynamic_map(t)) { + irValue *ha = ir_emit_struct_ep(proc, ptr, 0); + irValue *ea = ir_emit_struct_ep(proc, ptr, 1); + ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero); + ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero); + } else { + GB_PANIC("TODO(bill): ir clear for `%s`", type_to_string(t)); + } return NULL; } break; @@ -4152,6 +4174,28 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { } } } break; + + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + gbAllocator a = proc->module->allocator; + { + irValue **args = gb_alloc_array(a, irValue *, 4); + args[0] = ir_gen_map_header(proc, v, type); + args[1] = ir_make_const_int(a, 2*cl->elems.count); + ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2); + } + for_array(field_index, cl->elems) { + AstNode *elem = cl->elems.e[field_index]; + ast_node(fv, FieldValue, elem); + + irValue *key = ir_build_expr(proc, fv->field); + irValue *value = ir_build_expr(proc, fv->value); + ir_insert_map_key_and_value(proc, v, type, key, value); + } + } break; + case Type_Array: { if (cl->elems.count > 0) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr))); diff --git a/src/parser.c b/src/parser.c index 652181c90..079e39c2f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1854,6 +1854,7 @@ bool is_literal_type(AstNode *node) { case AstNode_ArrayType: case AstNode_VectorType: case AstNode_StructType: + case AstNode_MapType: return true; } return false;