aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2019-10-20 13:11:28 +0100
committergingerBill <bill@gingerbill.org>2019-10-20 13:11:28 +0100
commitf12ded54f2b1a390f556e67a17ff0bf4c301a8e3 (patch)
tree4ca38be0a35200857424ab0f1956ecb2a657393d /src
parentb4951c9b399801ca056db972eec9bd9064f25412 (diff)
Support for named indices for array-like compound literals `{3 = a, 1 = b}`
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp103
-rw-r--r--src/ir.cpp112
-rw-r--r--src/ir_print.cpp60
-rw-r--r--src/parser.hpp1
4 files changed, 213 insertions, 63 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index b2a2528dd..60c057ae9 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -7066,7 +7066,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
i64 max = 0;
- isize index = 0;
Type *bet = base_type(elem_type);
if (!elem_type_can_be_constant(bet)) {
@@ -7077,40 +7076,100 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
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 (is_to_be_determined_array_count) {
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 (!is_constant) {
error(node, "Expected all constant elements for a simd vector");
diff --git a/src/ir.cpp b/src/ir.cpp
index 0bf706f67..bea9ee8b3 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -1552,6 +1552,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
if (count == 0) {
return ir_value_nil(type);
}
+ count = gb_max(cl->max_index+1, count);
Type *elem = base_type(type)->Slice.elem;
Type *t = alloc_type_array(elem, count);
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
for_array(i, cl->elems) {
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) {
@@ -7881,6 +7898,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
defer (proc->return_ptr_hint_used = return_ptr_hint_used);
Ast *expr = temp_data[i].expr;
+ if (expr == nullptr) {
+ continue;
+ }
proc->return_ptr_hint_value = temp_data[i].gep;
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) {
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) {
@@ -7950,28 +7992,42 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
if (cl->elems.count == 0) {
break;
}
- Type *elem = bt->DynamicArray.elem;
+ Type *et = bt->DynamicArray.elem;
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);
args[0] = ir_emit_conv(proc, v, t_rawptr);
args[1] = size;
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);
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);
+ }
}
{
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index f76539fd6..cece0c1db 100644
--- a/src/ir_print.cpp
+++ b/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");
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)) {
ast_node(cl, CompoundLit, value.value_compound);
diff --git a/src/parser.hpp b/src/parser.hpp
index 419cf9da3..9c3f733e5 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -249,6 +249,7 @@ enum StmtAllowFlag {
Ast *type; \
Array<Ast *> elems; \
Token open, close; \
+ i64 max_index; \
}) \
AST_KIND(_ExprBegin, "", bool) \
AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \