Browse Source

Support for named indices for array-like compound literals `{3 = a, 1 = b}`

gingerBill 5 years ago
parent
commit
f12ded54f2
4 changed files with 213 additions and 63 deletions
  1. 81 22
      src/check_expr.cpp
  2. 84 28
      src/ir.cpp
  3. 47 13
      src/ir_print.cpp
  4. 1 0
      src/parser.hpp

+ 81 - 22
src/check_expr.cpp

@@ -7066,7 +7066,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 
 
 
 
 			i64 max = 0;
 			i64 max = 0;
-			isize index = 0;
 
 
 			Type *bet = base_type(elem_type);
 			Type *bet = base_type(elem_type);
 			if (!elem_type_can_be_constant(bet)) {
 			if (!elem_type_can_be_constant(bet)) {
@@ -7077,40 +7076,100 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 				break;
 				break;
 			}
 			}
 
 
-			for (; index < cl->elems.count; index++) {
-				Ast *e = cl->elems[index];
-				if (e == nullptr) {
-					error(node, "Invalid literal element");
-					continue;
-				}
+			if (cl->elems[0]->kind == Ast_FieldValue) {
+				if (is_type_simd_vector(t)) {
+					error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals");
+				} else {
+					Map<bool> seen = {};
+					map_init(&seen, heap_allocator());
+					defer (map_destroy(&seen));
 
 
-				if (e->kind == Ast_FieldValue) {
-					error(e, "'field = value' is only allowed in struct literals");
-					continue;
-				}
+					for_array(i, cl->elems) {
+						Ast *elem = cl->elems[i];
+						if (elem->kind != Ast_FieldValue) {
+							error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
+							continue;
+						}
+						ast_node(fv, FieldValue, elem);
+
+						Operand op_index = {};
+						check_expr(c, &op_index, fv->field);
+
+						if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) {
+							error(elem, "Expected a constant integer as an array field");
+							continue;
+						}
+
+						i64 index = exact_value_to_i64(op_index.value);
+
+						if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) {
+							error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name));
+							continue;
+						}
+
+						if (map_get(&seen, hash_integer(u64(index))) != nullptr) {
+							error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name));
+							continue;
+						}
+						map_set(&seen, hash_integer(u64(index)), true);
+
+						if (max < index) {
+							max = index;
+						}
+
+						Operand operand = {};
+						check_expr_with_type_hint(c, &operand, fv->value, elem_type);
+						check_assignment(c, &operand, elem_type, context_name);
+
+						is_constant = is_constant && operand.mode == Addressing_Constant;
+					}
 
 
-				if (0 <= max_type_count && max_type_count <= index) {
-					error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name));
+					cl->max_index = max;
 				}
 				}
 
 
-				Operand operand = {};
-				check_expr_with_type_hint(c, &operand, e, elem_type);
-				check_assignment(c, &operand, elem_type, context_name);
 
 
-				is_constant = is_constant && operand.mode == Addressing_Constant;
-			}
-			if (max < index) {
-				max = index;
+			} else {
+				isize index = 0;
+				for (; index < cl->elems.count; index++) {
+					Ast *e = cl->elems[index];
+					if (e == nullptr) {
+						error(node, "Invalid literal element");
+						continue;
+					}
+
+					if (e->kind == Ast_FieldValue) {
+						error(e, "Mixture of 'field = value' and value elements in a literal is not allowed");
+						continue;
+					}
+
+					if (0 <= max_type_count && max_type_count <= index) {
+						error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name));
+					}
+
+					Operand operand = {};
+					check_expr_with_type_hint(c, &operand, e, elem_type);
+					check_assignment(c, &operand, elem_type, context_name);
+
+					is_constant = is_constant && operand.mode == Addressing_Constant;
+				}
+
+				if (max < index) {
+					max = index;
+				}
 			}
 			}
 
 
+
 			if (t->kind == Type_Array) {
 			if (t->kind == Type_Array) {
 				if (is_to_be_determined_array_count) {
 				if (is_to_be_determined_array_count) {
 					t->Array.count = max;
 					t->Array.count = max;
-				} else if (0 < max && max < t->Array.count) {
-					error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
+				} else if (cl->elems[0]->kind != Ast_FieldValue) {
+					if (0 < max && max < t->Array.count) {
+						error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
+					}
 				}
 				}
 			}
 			}
 
 
+
 			if (t->kind == Type_SimdVector) {
 			if (t->kind == Type_SimdVector) {
 				if (!is_constant) {
 				if (!is_constant) {
 					error(node, "Expected all constant elements for a simd vector");
 					error(node, "Expected all constant elements for a simd vector");

+ 84 - 28
src/ir.cpp

@@ -1552,6 +1552,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
 			if (count == 0) {
 			if (count == 0) {
 				return ir_value_nil(type);
 				return ir_value_nil(type);
 			}
 			}
+			count = gb_max(cl->max_index+1, count);
 			Type *elem = base_type(type)->Slice.elem;
 			Type *elem = base_type(type)->Slice.elem;
 			Type *t = alloc_type_array(elem, count);
 			Type *t = alloc_type_array(elem, count);
 			irValue *backing_array = ir_add_module_constant(m, t, value);
 			irValue *backing_array = ir_add_module_constant(m, t, value);
@@ -7859,13 +7860,29 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 				// NOTE(bill): Separate value, gep, store into their own chunks
 				// NOTE(bill): Separate value, gep, store into their own chunks
 				for_array(i, cl->elems) {
 				for_array(i, cl->elems) {
 					Ast *elem = cl->elems[i];
 					Ast *elem = cl->elems[i];
-					if (ir_is_elem_const(proc->module, elem, et)) {
-						continue;
+					if (elem->kind == Ast_FieldValue) {
+						ast_node(fv, FieldValue, elem);
+						if (ir_is_elem_const(proc->module, fv->value, et)) {
+							continue;
+						}
+						auto tav = fv->field->tav;
+						GB_ASSERT(tav.mode == Addressing_Constant);
+						i64 index = exact_value_to_i64(tav.value);
+
+						irCompoundLitElemTempData data = {};
+						data.expr = fv->value;
+						data.elem_index = cast(i32)index;
+						array_add(&temp_data, data);
+
+					} else {
+						if (ir_is_elem_const(proc->module, elem, et)) {
+							continue;
+						}
+						irCompoundLitElemTempData data = {};
+						data.expr = elem;
+						data.elem_index = cast(i32)i;
+						array_add(&temp_data, data);
 					}
 					}
-					irCompoundLitElemTempData data = {};
-					data.expr = elem;
-					data.elem_index = cast(i32)i;
-					array_add(&temp_data, data);
 				}
 				}
 
 
 				for_array(i, temp_data) {
 				for_array(i, temp_data) {
@@ -7881,6 +7898,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 					defer (proc->return_ptr_hint_used  = return_ptr_hint_used);
 					defer (proc->return_ptr_hint_used  = return_ptr_hint_used);
 
 
 					Ast *expr = temp_data[i].expr;
 					Ast *expr = temp_data[i].expr;
+					if (expr == nullptr) {
+						continue;
+					}
 
 
 					proc->return_ptr_hint_value = temp_data[i].gep;
 					proc->return_ptr_hint_value = temp_data[i].gep;
 					proc->return_ptr_hint_ast = unparen_expr(expr);
 					proc->return_ptr_hint_ast = unparen_expr(expr);
@@ -7918,18 +7938,40 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 
 
 				for_array(i, cl->elems) {
 				for_array(i, cl->elems) {
 					Ast *elem = cl->elems[i];
 					Ast *elem = cl->elems[i];
-					if (ir_is_elem_const(proc->module, elem, et)) {
-						continue;
-					}
-					irValue *field_expr = ir_build_expr(proc, elem);
-					Type *t = ir_type(field_expr);
-					GB_ASSERT(t->kind != Type_Tuple);
-					irValue *ev = ir_emit_conv(proc, field_expr, et);
+					if (elem->kind == Ast_FieldValue) {
+						ast_node(fv, FieldValue, elem);
 
 
-					irCompoundLitElemTempData data = {};
-					data.value = ev;
-					data.elem_index = cast(i32)i;
-					array_add(&temp_data, data);
+						if (ir_is_elem_const(proc->module, fv->value, et)) {
+							continue;
+						}
+
+
+						GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
+						i64 index = exact_value_to_i64(fv->field->tav.value);
+
+						irValue *field_expr = ir_build_expr(proc, fv->value);
+						GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
+
+						irValue *ev = ir_emit_conv(proc, field_expr, et);
+
+						irCompoundLitElemTempData data = {};
+						data.value = ev;
+						data.elem_index = cast(i32)index;
+						array_add(&temp_data, data);
+					} else {
+						if (ir_is_elem_const(proc->module, elem, et)) {
+							continue;
+						}
+						irValue *field_expr = ir_build_expr(proc, elem);
+						GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
+
+						irValue *ev = ir_emit_conv(proc, field_expr, et);
+
+						irCompoundLitElemTempData data = {};
+						data.value = ev;
+						data.elem_index = cast(i32)i;
+						array_add(&temp_data, data);
+					}
 				}
 				}
 
 
 				for_array(i, temp_data) {
 				for_array(i, temp_data) {
@@ -7950,28 +7992,42 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 			if (cl->elems.count == 0) {
 			if (cl->elems.count == 0) {
 				break;
 				break;
 			}
 			}
-			Type *elem = bt->DynamicArray.elem;
+			Type *et = bt->DynamicArray.elem;
 			gbAllocator a = ir_allocator();
 			gbAllocator a = ir_allocator();
-			irValue *size  = ir_const_int(type_size_of(elem));
-			irValue *align = ir_const_int(type_align_of(elem));
+			irValue *size  = ir_const_int(type_size_of(et));
+			irValue *align = ir_const_int(type_align_of(et));
+
+			i64 item_count = gb_max(cl->max_index+1, cl->elems.count);
 			{
 			{
+
 				auto args = array_make<irValue *>(a, 5);
 				auto args = array_make<irValue *>(a, 5);
 				args[0] = ir_emit_conv(proc, v, t_rawptr);
 				args[0] = ir_emit_conv(proc, v, t_rawptr);
 				args[1] = size;
 				args[1] = size;
 				args[2] = align;
 				args[2] = align;
-				args[3] = ir_const_int(2*cl->elems.count);
+				args[3] = ir_const_int(2*item_count); // TODO(bill): Is this too much waste?
 				args[4] = ir_emit_source_code_location(proc, proc_name, pos);
 				args[4] = ir_emit_source_code_location(proc, proc_name, pos);
 				ir_emit_runtime_call(proc, "__dynamic_array_reserve", args);
 				ir_emit_runtime_call(proc, "__dynamic_array_reserve", args);
 			}
 			}
 
 
-			i64 item_count = cl->elems.count;
-			irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr);
+			irValue *items = ir_generate_array(proc->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr);
 
 
-			for_array(field_index, cl->elems) {
-				Ast *f = cl->elems[field_index];
-				irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem);
-				irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index);
-				ir_emit_store(proc, ep, value);
+			for_array(i, cl->elems) {
+				Ast *elem = cl->elems[i];
+				if (elem->kind == Ast_FieldValue) {
+					ast_node(fv, FieldValue, elem);
+					GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
+
+					i64 field_index = exact_value_to_i64(fv->field->tav.value);
+
+					irValue *ev = ir_build_expr(proc, fv->value);
+					irValue *value = ir_emit_conv(proc, ev, et);
+					irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index);
+					ir_emit_store(proc, ep, value);
+				} else {
+					irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et);
+					irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i);
+					ir_emit_store(proc, ep, value);
+				}
 			}
 			}
 
 
 			{
 			{

+ 47 - 13
src/ir_print.cpp

@@ -876,22 +876,56 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 				ir_write_str_lit(f, "zeroinitializer");
 				ir_write_str_lit(f, "zeroinitializer");
 				break;
 				break;
 			}
 			}
-			GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
+			if (cl->elems[0]->kind == Ast_FieldValue) {
+				// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
+				ir_write_byte(f, '[');
+				for (i64 i = 0; i < type->Array.count; i++) {
+					if (i > 0) ir_write_str_lit(f, ", ");
+
+					bool found = false;
+
+					for (isize j = 0; j < elem_count; j++) {
+						Ast *elem = cl->elems[j];
+						ast_node(fv, FieldValue, elem);
+						TypeAndValue index_tav = fv->field->tav;
+						GB_ASSERT(index_tav.mode == Addressing_Constant);
+						i64 index = exact_value_to_i64(index_tav.value);
+						if (index == i) {
+							TypeAndValue tav = fv->value->tav;
+							if (tav.mode != Addressing_Constant) {
+								break;
+							}
+							ir_print_compound_element(f, m, tav.value, elem_type);
+							found = true;
+							break;
+						}
+					}
 
 
-			ir_write_byte(f, '[');
+					if (!found) {
+						ir_print_type(f, m, elem_type);
+						ir_write_byte(f, ' ');
+						ir_write_str_lit(f, "zeroinitializer");
+					}
+				}
+				ir_write_byte(f, ']');
+			} else {
+				GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
 
 
-			for (isize i = 0; i < elem_count; i++) {
-				if (i > 0) ir_write_str_lit(f, ", ");
-				TypeAndValue tav = cl->elems[i]->tav;
-				GB_ASSERT(tav.mode != Addressing_Invalid);
-				ir_print_compound_element(f, m, tav.value, elem_type);
-			}
-			for (isize i = elem_count; i < type->Array.count; i++) {
-				if (i >= elem_count) ir_write_str_lit(f, ", ");
-				ir_print_compound_element(f, m, empty_exact_value, elem_type);
-			}
+				ir_write_byte(f, '[');
 
 
-			ir_write_byte(f, ']');
+				for (isize i = 0; i < elem_count; i++) {
+					if (i > 0) ir_write_str_lit(f, ", ");
+					TypeAndValue tav = cl->elems[i]->tav;
+					GB_ASSERT(tav.mode != Addressing_Invalid);
+					ir_print_compound_element(f, m, tav.value, elem_type);
+				}
+				for (isize i = elem_count; i < type->Array.count; i++) {
+					if (i >= elem_count) ir_write_str_lit(f, ", ");
+					ir_print_compound_element(f, m, empty_exact_value, elem_type);
+				}
+
+				ir_write_byte(f, ']');
+			}
 		} else if (is_type_simd_vector(type)) {
 		} else if (is_type_simd_vector(type)) {
 			ast_node(cl, CompoundLit, value.value_compound);
 			ast_node(cl, CompoundLit, value.value_compound);
 
 

+ 1 - 0
src/parser.hpp

@@ -249,6 +249,7 @@ enum StmtAllowFlag {
 		Ast *type; \
 		Ast *type; \
 		Array<Ast *> elems; \
 		Array<Ast *> elems; \
 		Token open, close; \
 		Token open, close; \
+		i64 max_index; \
 	}) \
 	}) \
 AST_KIND(_ExprBegin,  "",  bool) \
 AST_KIND(_ExprBegin,  "",  bool) \
 	AST_KIND(BadExpr,      "bad expression",         struct { Token begin, end; }) \
 	AST_KIND(BadExpr,      "bad expression",         struct { Token begin, end; }) \