Browse Source

Allow ranges for array-like compound literals

gingerBill 5 years ago
parent
commit
7fae890ef9
9 changed files with 340 additions and 165 deletions
  1. 3 0
      core/odin/parser/parser.odin
  2. 182 47
      src/check_expr.cpp
  3. 5 79
      src/check_stmt.cpp
  4. 3 0
      src/common.cpp
  5. 1 1
      src/exact_value.cpp
  6. 98 26
      src/ir.cpp
  7. 39 9
      src/ir_print.cpp
  8. 8 3
      src/parser.cpp
  9. 1 0
      src/parser.hpp

+ 3 - 0
core/odin/parser/parser.odin

@@ -2391,6 +2391,9 @@ parse_value :: proc(p: ^Parser) -> ^ast.Expr {
 	if p.curr_tok.kind == .Open_Brace {
 	if p.curr_tok.kind == .Open_Brace {
 		return parse_literal_value(p, nil);
 		return parse_literal_value(p, nil);
 	}
 	}
+	prev_allow_range = p.allow_range;
+	defer p.allow_range = prev_allow_range;
+	p.allow_range = true;
 	return parse_expr(p, false);
 	return parse_expr(p, false);
 }
 }
 
 

+ 182 - 47
src/check_expr.cpp

@@ -6635,6 +6635,98 @@ bool ternary_compare_types(Type *x, Type *y) {
 }
 }
 
 
 
 
+bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_) {
+	if (!is_ast_range(node)) {
+		return false;
+	}
+
+	ast_node(ie, BinaryExpr, node);
+
+	check_expr(c, x, ie->left);
+	if (x->mode == Addressing_Invalid) {
+		return false;
+	}
+	check_expr(c, y, ie->right);
+	if (y->mode == Addressing_Invalid) {
+		return false;
+	}
+
+	convert_to_typed(c, x, y->type);
+	if (x->mode == Addressing_Invalid) {
+		return false;
+	}
+	convert_to_typed(c, y, x->type);
+	if (y->mode == Addressing_Invalid) {
+		return false;
+	}
+
+	convert_to_typed(c, x, default_type(y->type));
+	if (x->mode == Addressing_Invalid) {
+		return false;
+	}
+	convert_to_typed(c, y, default_type(x->type));
+	if (y->mode == Addressing_Invalid) {
+		return false;
+	}
+
+	if (!are_types_identical(x->type, y->type)) {
+		if (x->type != t_invalid &&
+		    y->type != t_invalid) {
+			gbString xt = type_to_string(x->type);
+			gbString yt = type_to_string(y->type);
+			gbString expr_str = expr_to_string(x->expr);
+			error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt);
+			gb_string_free(expr_str);
+			gb_string_free(yt);
+			gb_string_free(xt);
+		}
+		return false;
+	}
+
+	Type *type = x->type;
+	if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
+		error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
+		return false;
+	}
+
+	if (x->mode == Addressing_Constant &&
+	    y->mode == Addressing_Constant) {
+		ExactValue a = x->value;
+		ExactValue b = y->value;
+
+		GB_ASSERT(are_types_identical(x->type, y->type));
+
+		TokenKind op = Token_Lt;
+		switch (ie->op.kind) {
+		case Token_Ellipsis:  op = Token_LtEq; break;
+		case Token_RangeHalf: op = Token_Lt; break;
+		default: error(ie->op, "Invalid range operator"); break;
+		}
+		bool ok = compare_exact_values(op, a, b);
+		if (!ok) {
+			// TODO(bill): Better error message
+			error(ie->op, "Invalid interval range");
+			return false;
+		}
+
+		ExactValue inline_for_depth = exact_value_sub(b, a);
+		if (ie->op.kind == Token_Ellipsis) {
+			inline_for_depth = exact_value_increment_one(inline_for_depth);
+		}
+
+		if (inline_for_depth_) *inline_for_depth_ = inline_for_depth;
+	} else {
+		error(ie->op, "Interval expressions must be constant");
+		return false;
+	}
+
+	add_type_and_value(&c->checker->info, ie->left,  x->mode, x->type, x->value);
+	add_type_and_value(&c->checker->info, ie->right, y->mode, y->type, y->value);
+
+	return true;
+}
+
+
 
 
 ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
 ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
 	ExprKind kind = Expr_Stmt;
 	ExprKind kind = Expr_Stmt;
@@ -6697,35 +6789,26 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 
 
 
 
 	case_ast_node(bl, BasicLit, node);
 	case_ast_node(bl, BasicLit, node);
-		// NOTE(bill, 2018-06-17): Placing this in the parser is slower than
-		// placing it here for some reason. So don't move it to the parsing
-		// stage if you _think_ it will be faster, only do it if you _know_ it
-		// will be faster.
 		Type *t = t_invalid;
 		Type *t = t_invalid;
-		switch (bl->token.kind) {
-		case Token_Integer: t = t_untyped_integer; break;
-		case Token_Float:   t = t_untyped_float;   break;
-		case Token_String:  t = t_untyped_string;  break;
-		case Token_Rune:    t = t_untyped_rune;    break;
-		case Token_Imag: {
-			String s = bl->token.string;
-			Rune r = s[s.len-1];
-			// NOTE(bill, 2019-08-25): Allow for quaternions by having j and k imaginary numbers
-			switch (r) {
-			case 'i': t = t_untyped_complex;    break;
-			case 'j': t = t_untyped_quaternion; break;
-			case 'k': t = t_untyped_quaternion; break;
+		switch (bl->value.kind) {
+		case ExactValue_String:     t = t_untyped_string;     break;
+		case ExactValue_Float:      t = t_untyped_float;      break;
+		case ExactValue_Complex:    t = t_untyped_complex;    break;
+		case ExactValue_Quaternion: t = t_untyped_quaternion; break;
+		case ExactValue_Integer:
+			t = t_untyped_integer;
+			if (bl->token.kind == Token_Rune) {
+				t = t_untyped_rune;
 			}
 			}
-
 			break;
 			break;
-		}
 		default:
 		default:
-			GB_PANIC("Unknown literal");
+			GB_PANIC("Unhandled value type for basic literal");
 			break;
 			break;
 		}
 		}
+
 		o->mode  = Addressing_Constant;
 		o->mode  = Addressing_Constant;
 		o->type  = t;
 		o->type  = t;
-		o->value = exact_value_from_basic_literal(bl->token);
+		o->value = bl->value;
 	case_end;
 	case_end;
 
 
 	case_ast_node(bd, BasicDirective, node);
 	case_ast_node(bd, BasicDirective, node);
@@ -7090,9 +7173,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 				if (is_type_simd_vector(t)) {
 				if (is_type_simd_vector(t)) {
 					error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals");
 					error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals");
 				} else {
 				} else {
-					Map<bool> seen = {};
-					map_init(&seen, heap_allocator());
-					defer (map_destroy(&seen));
+					RangeCache rc = range_cache_make(heap_allocator());
+					defer (range_cache_destroy(&rc));
 
 
 					for_array(i, cl->elems) {
 					for_array(i, cl->elems) {
 						Ast *elem = cl->elems[i];
 						Ast *elem = cl->elems[i];
@@ -7102,36 +7184,89 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 						}
 						}
 						ast_node(fv, FieldValue, elem);
 						ast_node(fv, FieldValue, elem);
 
 
-						Operand op_index = {};
-						check_expr(c, &op_index, fv->field);
+						if (is_ast_range(fv->field)) {
+							Token op = fv->field->BinaryExpr.op;
 
 
-						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;
-						}
+							Operand x = {};
+							Operand y = {};
+							bool ok = check_range(c, fv->field, &x, &y, nullptr);
+							if (!ok) {
+								continue;
+							}
+							if (x.mode != Addressing_Constant || !is_type_integer(core_type(x.type))) {
+								error(x.expr, "Expected a constant integer as an array field");
+								continue;
+							}
 
 
-						i64 index = exact_value_to_i64(op_index.value);
+							if (y.mode != Addressing_Constant || !is_type_integer(core_type(y.type))) {
+								error(y.expr, "Expected a constant integer as an array field");
+								continue;
+							}
 
 
-						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;
-						}
+							i64 lo = exact_value_to_i64(x.value);
+							i64 hi = exact_value_to_i64(y.value);
+							if (op.kind == Token_RangeHalf) {
+								hi -= 1;
+							}
+							i64 max_index = hi;
 
 
-						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);
+							bool new_range = range_cache_add_range(&rc, lo, hi);
+							if (!new_range) {
+								error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", lo, LIT(op.string), hi, LIT(context_name));
+								continue;
+							}
 
 
-						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);
+							if (max_type_count >= 0 && (lo < 0 || lo >= max_type_count)) {
+								error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", lo, max_type_count, LIT(context_name));
+								continue;
+							}
+							if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) {
+								error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", hi, max_type_count, LIT(context_name));
+								continue;
+							}
+
+							if (max < max_index) {
+								max = 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;
+						} else {
+							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;
+							}
 
 
-						is_constant = is_constant && operand.mode == Addressing_Constant;
+							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;
+							}
+
+							bool new_index = range_cache_add_index(&rc, index);
+							if (!new_index) {
+								error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name));
+								continue;
+							}
+
+							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;
+						}
 					}
 					}
 
 
 					cl->max_index = max;
 					cl->max_index = max;

+ 5 - 79
src/check_stmt.cpp

@@ -605,89 +605,15 @@ void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
 
 
 	if (is_ast_range(expr)) {
 	if (is_ast_range(expr)) {
 		ast_node(ie, BinaryExpr, expr);
 		ast_node(ie, BinaryExpr, expr);
-		Operand x = {Addressing_Invalid};
-		Operand y = {Addressing_Invalid};
+		Operand x = {};
+		Operand y = {};
 
 
-		check_expr(ctx, &x, ie->left);
-		if (x.mode == Addressing_Invalid) {
-			goto skip_expr;
-		}
-		check_expr(ctx, &y, ie->right);
-		if (y.mode == Addressing_Invalid) {
-			goto skip_expr;
-		}
-
-		convert_to_typed(ctx, &x, y.type);
-		if (x.mode == Addressing_Invalid) {
-			goto skip_expr;
-		}
-		convert_to_typed(ctx, &y, x.type);
-		if (y.mode == Addressing_Invalid) {
-			goto skip_expr;
-		}
-
-		convert_to_typed(ctx, &x, default_type(y.type));
-		if (x.mode == Addressing_Invalid) {
-			goto skip_expr;
-		}
-		convert_to_typed(ctx, &y, default_type(x.type));
-		if (y.mode == Addressing_Invalid) {
-			goto skip_expr;
-		}
-
-		if (!are_types_identical(x.type, y.type)) {
-			if (x.type != t_invalid &&
-			    y.type != t_invalid) {
-				gbString xt = type_to_string(x.type);
-				gbString yt = type_to_string(y.type);
-				gbString expr_str = expr_to_string(x.expr);
-				error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt);
-				gb_string_free(expr_str);
-				gb_string_free(yt);
-				gb_string_free(xt);
-			}
-			goto skip_expr;
-		}
-
-		Type *type = x.type;
-		if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) {
-			error(ie->op, "Only numerical and pointer types are allowed within interval expressions");
-			goto skip_expr;
-		}
-
-		if (x.mode == Addressing_Constant &&
-		    y.mode == Addressing_Constant) {
-			ExactValue a = x.value;
-			ExactValue b = y.value;
-
-			GB_ASSERT(are_types_identical(x.type, y.type));
-
-			TokenKind op = Token_Lt;
-			switch (ie->op.kind) {
-			case Token_Ellipsis:  op = Token_LtEq; break;
-			case Token_RangeHalf: op = Token_Lt; break;
-			default: error(ie->op, "Invalid range operator"); break;
-			}
-			bool ok = compare_exact_values(op, a, b);
-			if (!ok) {
-				// TODO(bill): Better error message
-				error(ie->op, "Invalid interval range");
-				goto skip_expr;
-			}
-
-			inline_for_depth = exact_value_sub(b, a);
-			if (ie->op.kind == Token_Ellipsis) {
-				inline_for_depth = exact_value_increment_one(inline_for_depth);
-			}
-
-		} else {
-			error(ie->op, "Interval expressions must be constant");
+		bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth);
+		if (!ok) {
 			goto skip_expr;
 			goto skip_expr;
 		}
 		}
 
 
-		add_type_and_value(&ctx->checker->info, ie->left,  x.mode, x.type, x.value);
-		add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
-		val0 = type;
+		val0 = x.type;
 		val1 = t_int;
 		val1 = t_int;
 	} else {
 	} else {
 		Operand operand = {Addressing_Invalid};
 		Operand operand = {Addressing_Invalid};

+ 3 - 0
src/common.cpp

@@ -143,6 +143,9 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
 
 
 #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
 #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
 
 
+#include "range_cache.cpp"
+
+
 
 
 u64 fnv64a(void const *data, isize len) {
 u64 fnv64a(void const *data, isize len) {
 	u8 const *bytes = cast(u8 const *)data;
 	u8 const *bytes = cast(u8 const *)data;

+ 1 - 1
src/exact_value.cpp

@@ -293,12 +293,12 @@ ExactValue exact_value_from_basic_literal(Token token) {
 		case 'i': return exact_value_complex(0, imag);
 		case 'i': return exact_value_complex(0, imag);
 		case 'j': return exact_value_quaternion(0, 0, imag, 0);
 		case 'j': return exact_value_quaternion(0, 0, imag, 0);
 		case 'k': return exact_value_quaternion(0, 0, 0, imag);
 		case 'k': return exact_value_quaternion(0, 0, 0, imag);
+		default: GB_PANIC("Invalid imaginary basic literal");
 		}
 		}
 	}
 	}
 	case Token_Rune: {
 	case Token_Rune: {
 		Rune r = GB_RUNE_INVALID;
 		Rune r = GB_RUNE_INVALID;
 		gb_utf8_decode(token.string.text, token.string.len, &r);
 		gb_utf8_decode(token.string.text, token.string.len, &r);
-		// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
 		return exact_value_i64(r);
 		return exact_value_i64(r);
 	}
 	}
 	default:
 	default:

+ 98 - 26
src/ir.cpp

@@ -7865,14 +7865,40 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 						if (ir_is_elem_const(proc->module, fv->value, et)) {
 						if (ir_is_elem_const(proc->module, fv->value, et)) {
 							continue;
 							continue;
 						}
 						}
-						auto tav = fv->field->tav;
-						GB_ASSERT(tav.mode == Addressing_Constant);
-						i64 index = exact_value_to_i64(tav.value);
+						if (is_ast_range(fv->field)) {
+							ast_node(ie, BinaryExpr, fv->field);
+							TypeAndValue lo_tav = ie->left->tav;
+							TypeAndValue hi_tav = ie->right->tav;
+							GB_ASSERT(lo_tav.mode == Addressing_Constant);
+							GB_ASSERT(hi_tav.mode == Addressing_Constant);
+
+							TokenKind op = ie->op.kind;
+							i64 lo = exact_value_to_i64(lo_tav.value);
+							i64 hi = exact_value_to_i64(hi_tav.value);
+							if (op == Token_Ellipsis) {
+								hi += 1;
+							}
 
 
-						irCompoundLitElemTempData data = {};
-						data.expr = fv->value;
-						data.elem_index = cast(i32)index;
-						array_add(&temp_data, data);
+							irValue *value = ir_build_expr(proc, fv->value);
+
+							for (i64 k = lo; k < hi; k++) {
+								irCompoundLitElemTempData data = {};
+								data.value = value;
+								data.elem_index = cast(i32)k;
+								array_add(&temp_data, data);
+							}
+
+						} else {
+							auto tav = fv->field->tav;
+							GB_ASSERT(tav.mode == Addressing_Constant);
+							i64 index = exact_value_to_i64(tav.value);
+
+							irCompoundLitElemTempData data = {};
+							data.value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
+							data.expr = fv->value;
+							data.elem_index = cast(i32)index;
+							array_add(&temp_data, data);
+						}
 
 
 					} else {
 					} else {
 						if (ir_is_elem_const(proc->module, elem, et)) {
 						if (ir_is_elem_const(proc->module, elem, et)) {
@@ -7897,15 +7923,15 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 					defer (proc->return_ptr_hint_value = return_ptr_hint_value);
 					defer (proc->return_ptr_hint_value = return_ptr_hint_value);
 					defer (proc->return_ptr_hint_used  = return_ptr_hint_used);
 					defer (proc->return_ptr_hint_used  = return_ptr_hint_used);
 
 
+					irValue *field_expr = temp_data[i].value;
 					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);
 
 
-					irValue *field_expr = ir_build_expr(proc, expr);
+					if (field_expr == nullptr) {
+						field_expr = ir_build_expr(proc, expr);
+					}
 					Type *t = ir_type(field_expr);
 					Type *t = ir_type(field_expr);
 					GB_ASSERT(t->kind != Type_Tuple);
 					GB_ASSERT(t->kind != Type_Tuple);
 					irValue *ev = ir_emit_conv(proc, field_expr, et);
 					irValue *ev = ir_emit_conv(proc, field_expr, et);
@@ -7945,19 +7971,43 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 							continue;
 							continue;
 						}
 						}
 
 
+						if (is_ast_range(fv->field)) {
+							ast_node(ie, BinaryExpr, fv->field);
+							TypeAndValue lo_tav = ie->left->tav;
+							TypeAndValue hi_tav = ie->right->tav;
+							GB_ASSERT(lo_tav.mode == Addressing_Constant);
+							GB_ASSERT(hi_tav.mode == Addressing_Constant);
+
+							TokenKind op = ie->op.kind;
+							i64 lo = exact_value_to_i64(lo_tav.value);
+							i64 hi = exact_value_to_i64(hi_tav.value);
+							if (op == Token_Ellipsis) {
+								hi += 1;
+							}
 
 
-						GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
-						i64 index = exact_value_to_i64(fv->field->tav.value);
+							irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
 
 
-						irValue *field_expr = ir_build_expr(proc, fv->value);
-						GB_ASSERT(!is_type_tuple(ir_type(field_expr)));
+							for (i64 k = lo; k < hi; k++) {
+								irCompoundLitElemTempData data = {};
+								data.value = value;
+								data.elem_index = cast(i32)k;
+								array_add(&temp_data, data);
+							}
 
 
-						irValue *ev = ir_emit_conv(proc, field_expr, et);
+						} else {
+							GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
+							i64 index = exact_value_to_i64(fv->field->tav.value);
 
 
-						irCompoundLitElemTempData data = {};
-						data.value = ev;
-						data.elem_index = cast(i32)index;
-						array_add(&temp_data, data);
+							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 {
 					} else {
 						if (ir_is_elem_const(proc->module, elem, et)) {
 						if (ir_is_elem_const(proc->module, elem, et)) {
 							continue;
 							continue;
@@ -8015,14 +8065,36 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 				Ast *elem = cl->elems[i];
 				Ast *elem = cl->elems[i];
 				if (elem->kind == Ast_FieldValue) {
 				if (elem->kind == Ast_FieldValue) {
 					ast_node(fv, FieldValue, elem);
 					ast_node(fv, FieldValue, elem);
-					GB_ASSERT(fv->field->tav.mode == Addressing_Constant);
+					if (is_ast_range(fv->field)) {
+						ast_node(ie, BinaryExpr, fv->field);
+						TypeAndValue lo_tav = ie->left->tav;
+						TypeAndValue hi_tav = ie->right->tav;
+						GB_ASSERT(lo_tav.mode == Addressing_Constant);
+						GB_ASSERT(hi_tav.mode == Addressing_Constant);
+
+						TokenKind op = ie->op.kind;
+						i64 lo = exact_value_to_i64(lo_tav.value);
+						i64 hi = exact_value_to_i64(hi_tav.value);
+						if (op == Token_Ellipsis) {
+							hi += 1;
+						}
 
 
-					i64 field_index = exact_value_to_i64(fv->field->tav.value);
+						irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et);
 
 
-					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);
+						for (i64 k = lo; k < hi; k++) {
+							irValue *ep = ir_emit_array_epi(proc, items, cast(i32)k);
+							ir_emit_store(proc, ep, value);
+						}
+					} else {
+						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 {
 				} else {
 					irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et);
 					irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et);
 					irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i);
 					irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i);

+ 39 - 9
src/ir_print.cpp

@@ -887,17 +887,47 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 					for (isize j = 0; j < elem_count; j++) {
 					for (isize j = 0; j < elem_count; j++) {
 						Ast *elem = cl->elems[j];
 						Ast *elem = cl->elems[j];
 						ast_node(fv, FieldValue, elem);
 						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) {
+						if (is_ast_range(fv->field)) {
+							ast_node(ie, BinaryExpr, fv->field);
+							TypeAndValue lo_tav = ie->left->tav;
+							TypeAndValue hi_tav = ie->right->tav;
+							GB_ASSERT(lo_tav.mode == Addressing_Constant);
+							GB_ASSERT(hi_tav.mode == Addressing_Constant);
+
+							TokenKind op = ie->op.kind;
+							i64 lo = exact_value_to_i64(lo_tav.value);
+							i64 hi = exact_value_to_i64(hi_tav.value);
+							if (op == Token_Ellipsis) {
+								hi += 1;
+							}
+							if (lo == i) {
+								TypeAndValue tav = fv->value->tav;
+								if (tav.mode != Addressing_Constant) {
+									break;
+								}
+								for (i64 k = lo; k < hi; k++) {
+									if (k > lo) ir_write_str_lit(f, ", ");
+
+									ir_print_compound_element(f, m, tav.value, elem_type);
+								}
+
+								found = true;
+								i += (hi-lo-1);
+								break;
+							}
+						} else {
+							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;
 								break;
 							}
 							}
-							ir_print_compound_element(f, m, tav.value, elem_type);
-							found = true;
-							break;
 						}
 						}
 					}
 					}
 
 

+ 8 - 3
src/parser.cpp

@@ -588,6 +588,7 @@ Ast *ast_undef(AstFile *f, Token token) {
 Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
 Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
 	Ast *result = alloc_ast_node(f, Ast_BasicLit);
 	Ast *result = alloc_ast_node(f, Ast_BasicLit);
 	result->BasicLit.token = basic_lit;
 	result->BasicLit.token = basic_lit;
+	result->BasicLit.value = exact_value_from_basic_literal(basic_lit);
 	return result;
 	return result;
 }
 }
 
 
@@ -1509,8 +1510,11 @@ Ast *parse_value(AstFile *f) {
 	if (f->curr_token.kind == Token_OpenBrace) {
 	if (f->curr_token.kind == Token_OpenBrace) {
 		return parse_literal_value(f, nullptr);
 		return parse_literal_value(f, nullptr);
 	}
 	}
-
-	Ast *value = parse_expr(f, false);
+	Ast *value;
+	bool prev_allow_range = f->allow_range;
+	f->allow_range = true;
+	value = parse_expr(f, false);
+	f->allow_range = prev_allow_range;
 	return value;
 	return value;
 }
 }
 
 
@@ -1735,7 +1739,8 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 				operand = ast_bad_expr(f, token, f->curr_token);
 				operand = ast_bad_expr(f, token, f->curr_token);
 			}
 			}
 			operand->stmt_state_flags |= StmtStateFlag_no_deferred;
 			operand->stmt_state_flags |= StmtStateFlag_no_deferred;
-		} */ else if (name.string == "file") { return ast_basic_directive(f, token, name.string);
+		} */ else if (name.string == "file") {
+			return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
 		} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);

+ 1 - 0
src/parser.hpp

@@ -222,6 +222,7 @@ enum StmtAllowFlag {
 	AST_KIND(Undef,          "undef",           Token) \
 	AST_KIND(Undef,          "undef",           Token) \
 	AST_KIND(BasicLit,       "basic literal",   struct { \
 	AST_KIND(BasicLit,       "basic literal",   struct { \
 		Token token; \
 		Token token; \
+		ExactValue value; \
 	}) \
 	}) \
 	AST_KIND(BasicDirective, "basic directive", struct { \
 	AST_KIND(BasicDirective, "basic directive", struct { \
 		Token  token; \
 		Token  token; \