Browse Source

Compound Literals - struct, array, slice, vector

gingerBill 9 years ago
parent
commit
c10b46af9f
9 changed files with 356 additions and 87 deletions
  1. 111 11
      examples/main.ll
  2. 20 7
      examples/main.odin
  3. 26 5
      src/checker/expr.cpp
  4. 2 1
      src/codegen/codegen.cpp
  5. 24 8
      src/codegen/print_llvm.cpp
  6. 138 28
      src/codegen/ssa.cpp
  7. 32 18
      src/parser.cpp
  8. 1 4
      src/printer.cpp
  9. 2 5
      src/tokenizer.cpp

+ 111 - 11
examples/main.ll

@@ -4,6 +4,7 @@
 
 
 declare void @llvm.memmove.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1)
 declare void @llvm.memmove.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1)
 
 
+%main.Vec2 = type <2 x float>
 define void @exec(i64 ()* %p) {
 define void @exec(i64 ()* %p) {
 "entry - 0":
 "entry - 0":
 	%0 = alloca i64 ()*, align 8 ; p
 	%0 = alloca i64 ()*, align 8 ; p
@@ -18,21 +19,119 @@ define void @exec(i64 ()* %p) {
 
 
 define void @main() {
 define void @main() {
 "entry - 0":
 "entry - 0":
-	%0 = alloca i8, align 1 ; a
-	store i8 zeroinitializer, i8* %0
-	store i8 123, i8* %0
-	%1 = load i8, i8* %0
-	%2 = zext i8 %1 to i64
-	call void @print_int(i64 %2)
+	%0 = alloca i64, align 8 ; i
+	store i64 zeroinitializer, i64* %0
+	store i64 123, i64* %0
+	%1 = load i64, i64* %0
+	call void @print_int(i64 %1)
 	call void @print_rune(i32 128149)
 	call void @print_rune(i32 128149)
 	call void @print_rune(i32 10)
 	call void @print_rune(i32 10)
-	call void @exec(i64 ()* @main$cool_beans)
+	%2 = alloca %main.Vec2, align 2 ; v
+	store %main.Vec2 zeroinitializer, %main.Vec2* %2
+	%3 = alloca %main.Vec2, align 2 
+	store %main.Vec2 zeroinitializer, %main.Vec2* %3
+	%4 = getelementptr inbounds %main.Vec2, %main.Vec2* %3, i64 0, i32 0
+	store float 0x3ff0000000000000, float* %4
+	%5 = getelementptr inbounds %main.Vec2, %main.Vec2* %3, i64 0, i32 1
+	store float 0x4000000000000000, float* %5
+	%6 = load %main.Vec2, %main.Vec2* %3
+	store %main.Vec2 %6, %main.Vec2* %2
+	%7 = alloca [4 x i64], align 8 ; a
+	store [4 x i64] zeroinitializer, [4 x i64]* %7
+	%8 = alloca [4 x i64], align 8 
+	store [4 x i64] zeroinitializer, [4 x i64]* %8
+	%9 = load i64, i64* %0
+	%10 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 0
+	store i64 %9, i64* %10
+	%11 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 1
+	store i64 2, i64* %11
+	%12 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 2
+	store i64 3, i64* %12
+	%13 = getelementptr inbounds [4 x i64], [4 x i64]* %8, i64 0, i32 3
+	store i64 7, i64* %13
+	%14 = load [4 x i64], [4 x i64]* %8
+	store [4 x i64] %14, [4 x i64]* %7
+	%15 = alloca [4 x i64], align 8 ; e
+	store [4 x i64] zeroinitializer, [4 x i64]* %15
+	%16 = alloca [4 x i64], align 8 
+	store [4 x i64] zeroinitializer, [4 x i64]* %16
+	%17 = load i64, i64* %0
+	%18 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 0
+	store i64 %17, i64* %18
+	%19 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 1
+	store i64 2, i64* %19
+	%20 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 2
+	store i64 3, i64* %20
+	%21 = getelementptr inbounds [4 x i64], [4 x i64]* %16, i64 0, i32 3
+	store i64 7, i64* %21
+	%22 = load [4 x i64], [4 x i64]* %16
+	store [4 x i64] %22, [4 x i64]* %15
+	%23 = alloca {i64*, i64, i64}, align 8 ; s
+	store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %23
+	%24 = alloca {i64*, i64, i64}, align 8 
+	store {i64*, i64, i64} zeroinitializer, {i64*, i64, i64}* %24
+	%25 = alloca [4 x i64], align 8 
+	store [4 x i64] zeroinitializer, [4 x i64]* %25
+	%26 = load i64, i64* %0
+	%27 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 0
+	store i64 %26, i64* %27
+	%28 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 1
+	store i64 2, i64* %28
+	%29 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 2
+	store i64 3, i64* %29
+	%30 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 3
+	store i64 7, i64* %30
+	%31 = getelementptr inbounds [4 x i64], [4 x i64]* %25, i64 0, i32 0
+	%32 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 0
+	store i64* %31, i64** %32
+	%33 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 1
+	store i64 4, i64* %33
+	%34 = getelementptr inbounds {i64*, i64, i64}, {i64*, i64, i64}* %24, i64 0, i32 2
+	store i64 4, i64* %34
+	%35 = load {i64*, i64, i64}, {i64*, i64, i64}* %24
+	store {i64*, i64, i64} %35, {i64*, i64, i64}* %23
+	%36 = alloca i64, align 8 ; i
+	store i64 zeroinitializer, i64* %36
+	store i64 0, i64* %36
+	br label %"for.loop - 2"
+
+"for.body - 1":
+	%37 = getelementptr inbounds [4 x i64], [4 x i64]* %7, i64 0, i64 0
+	%38 = load i64, i64* %36
+	%39 = getelementptr i64, i64* %37, i64 %38
+	%40 = load i64, i64* %39
+	call void @print_int(i64 %40)
+	%41 = getelementptr inbounds [2 x i8], [2 x i8]* @.str0, i64 0, i64 0
+	%42 = alloca %.string, align 8 
+	store %.string zeroinitializer, %.string* %42
+	%43 = getelementptr inbounds %.string, %.string* %42, i64 0, i32 0
+	%44 = getelementptr inbounds %.string, %.string* %42, i64 0, i32 1
+	store i8* %41, i8** %43
+	store i64 2, i64* %44
+	%45 = load %.string, %.string* %42
+	call void @print_string(%.string %45)
+	br label %"for.post - 3"
+
+"for.loop - 2":
+	%46 = load i64, i64* %36
+	%47 = icmp slt i64 %46, 4
+	br i1 %47, label %"for.body - 1", label %"for.done - 4"
+
+"for.post - 3":
+	%48 = load i64, i64* %36
+	%49 = add i64 %48, 1
+	store i64 %49, i64* %36
+	br label %"for.loop - 2"
+
+"for.done - 4":
+	call void @print_rune(i32 10)
+	call void @exec(i64 ()* @main$0)
 	ret void
 	ret void
 }
 }
 
 
-define i64 @main$cool_beans() {
+define i64 @main$0() {
 "entry - 0":
 "entry - 0":
-	%0 = alloca i64, align 8 ; a
+	%0 = alloca i64, align 8 ; i
 	store i64 zeroinitializer, i64* %0
 	store i64 zeroinitializer, i64* %0
 	store i64 1337, i64* %0
 	store i64 1337, i64* %0
 	call void @print_rune(i32 128149)
 	call void @print_rune(i32 128149)
@@ -411,7 +510,7 @@ define void @print_int_base(i64 %i, i64 %base) {
 	%16 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
 	%16 = getelementptr inbounds [21 x i8], [21 x i8]* %2, i64 0, i64 0
 	%17 = load i64, i64* %3
 	%17 = load i64, i64* %3
 	%18 = getelementptr i8, i8* %16, i64 %17
 	%18 = getelementptr i8, i8* %16, i64 %17
-	%19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str0, i64 0, i64 0
+	%19 = getelementptr inbounds [64 x i8], [64 x i8]* @.str1, i64 0, i64 0
 	%20 = load i64, i64* %1
 	%20 = load i64, i64* %1
 	%21 = load i64, i64* %0
 	%21 = load i64, i64* %0
 	%22 = srem i64 %21, %20
 	%22 = srem i64 %21, %20
@@ -494,4 +593,5 @@ define void @print_int_base(i64 %i, i64 %base) {
 	ret void
 	ret void
 }
 }
 
 
[email protected] = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$"
[email protected] = global [2 x i8] c"\2C\20"
[email protected] = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$"

+ 20 - 7
examples/main.odin

@@ -2,24 +2,37 @@ import "basic"
 
 
 TWO_HEARTS :: '💕';
 TWO_HEARTS :: '💕';
 
 
+
 exec :: proc(p : proc() -> int) {
 exec :: proc(p : proc() -> int) {
 	print_int(p());
 	print_int(p());
 	print_rune('\n');
 	print_rune('\n');
 }
 }
 
 
 main :: proc() {
 main :: proc() {
-	a : u8 = 123;
-	print_int(cast(int)a);
+	i := 123;
+	print_int(i);
 	print_rune(TWO_HEARTS);
 	print_rune(TWO_HEARTS);
 	print_rune('\n');
 	print_rune('\n');
 
 
-	cool_beans :: proc() -> int {
-		a : int = 1337;
+	type Vec2: {2}f32;
+
+	v := Vec2{1, 2};
+	a := [4] int{i, 2, 3, 7};
+	e := [..]int{i, 2, 3, 7};
+	s := []  int{i, 2, 3, 7};
+
+	for i := 0; i < len(a); i++ {
+		print_int(a[i]);
+		print_string(", ");
+	}
+	print_rune('\n');
+
+	exec(proc() -> int {
+		i : int = 1337;
 		print_rune('💕');
 		print_rune('💕');
 		print_rune('\n');
 		print_rune('\n');
-		return a;
-	}
-	exec(cool_beans);
+		return i;
+	});
 }
 }
 
 
 /*
 /*

+ 26 - 5
src/checker/expr.cpp

@@ -18,10 +18,6 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
 	GB_ASSERT(node->kind == AstNode_StructType);
 	GB_ASSERT(node->kind == AstNode_StructType);
 	GB_ASSERT(struct_type->kind == Type_Structure);
 	GB_ASSERT(struct_type->kind == Type_Structure);
 	ast_node(st, StructType, node);
 	ast_node(st, StructType, node);
-	if (st->field_count == 0) {
-		error(&c->error_collector, ast_node_token(node), "Empty struct{} definition");
-		return;
-	}
 
 
 	Map<Entity *> entity_map = {};
 	Map<Entity *> entity_map = {};
 	map_init(&entity_map, gb_heap_allocator());
 	map_init(&entity_map, gb_heap_allocator());
@@ -1759,8 +1755,21 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 
 
 	case_ast_node(cl, CompoundLit, node);
 	case_ast_node(cl, CompoundLit, node);
 		Type *type = type_hint;
 		Type *type = type_hint;
+		b32 ellipsis_array = false;
 		if (cl->type != NULL) {
 		if (cl->type != NULL) {
-			type = check_type(c, cl->type);
+			type = NULL;
+
+			// [..]Type
+			if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) {
+				if (cl->type->ArrayType.count->kind == AstNode_Ellipsis) {
+					type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1);
+					ellipsis_array = true;
+				}
+			}
+
+			if (type == NULL) {
+				type = check_type(c, cl->type);
+			}
 		}
 		}
 
 
 		if (type == NULL) {
 		if (type == NULL) {
@@ -1798,12 +1807,16 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 
 
 		case Type_Slice:
 		case Type_Slice:
 		case Type_Array:
 		case Type_Array:
+		case Type_Vector:
 		{
 		{
 			Type *elem_type = NULL;
 			Type *elem_type = NULL;
 			String context_name = {};
 			String context_name = {};
 			if (t->kind == Type_Slice) {
 			if (t->kind == Type_Slice) {
 				elem_type = t->slice.elem;
 				elem_type = t->slice.elem;
 				context_name = make_string("slice literal");
 				context_name = make_string("slice literal");
+			} else if (t->kind == Type_Vector) {
+				elem_type = t->vector.elem;
+				context_name = make_string("vector literal");
 			} else {
 			} else {
 				elem_type = t->array.elem;
 				elem_type = t->array.elem;
 				context_name = make_string("array literal");
 				context_name = make_string("array literal");
@@ -1826,6 +1839,10 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
 			}
 			}
 			if (max < index)
 			if (max < index)
 				max = index;
 				max = index;
+
+			if (t->kind == Type_Array && ellipsis_array) {
+				t->array.count = max;
+			}
 		} break;
 		} break;
 
 
 		default: {
 		default: {
@@ -2277,6 +2294,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = write_expr_to_string(str, ce->expr);
 		str = write_expr_to_string(str, ce->expr);
 	case_end;
 	case_end;
 
 
+	case_ast_node(e, Ellipsis, node);
+		str = gb_string_appendc(str, "..");
+	case_end;
+
 	case_ast_node(pt, PointerType, node);
 	case_ast_node(pt, PointerType, node);
 		str = gb_string_appendc(str, "^");
 		str = gb_string_appendc(str, "^");
 		str = write_expr_to_string(str, pt->type);
 		str = write_expr_to_string(str, pt->type);

+ 2 - 1
src/codegen/codegen.cpp

@@ -60,7 +60,8 @@ void ssa_gen_code(ssaGen *s) {
 
 
 		switch (e->kind) {
 		switch (e->kind) {
 		case Entity_TypeName: {
 		case Entity_TypeName: {
-			ssaValue *t = ssa_make_value_type_name(a, e);
+			ssaValue *t = ssa_make_value_type_name(a, e->token.string, e->type);
+			map_set(&m->values,  hash_pointer(e), t);
 			map_set(&m->members, hash_string(name), t);
 			map_set(&m->members, hash_string(name), t);
 		} break;
 		} break;
 
 

+ 24 - 8
src/codegen/print_llvm.cpp

@@ -184,6 +184,12 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
 }
 }
 
 
 void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type) {
 void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type) {
+	if (is_type_float(type)) {
+		value = exact_value_to_float(value);
+	} else if (is_type_integer(type)) {
+		value = exact_value_to_integer(value);
+	}
+
 	switch (value.kind) {
 	switch (value.kind) {
 	case ExactValue_Bool:
 	case ExactValue_Bool:
 		ssa_fprintf(f, (value.value_bool ? "true" : "false"));
 		ssa_fprintf(f, (value.value_bool ? "true" : "false"));
@@ -238,7 +244,7 @@ void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint)
 		ssa_print_exact_value(f, m, value->constant.value, type_hint);
 		ssa_print_exact_value(f, m, value->constant.value, type_hint);
 		break;
 		break;
 	case ssaValue_TypeName:
 	case ssaValue_TypeName:
-		ssa_print_encoded_local(f, value->type_name.entity->token.string);
+		ssa_print_encoded_local(f, value->type_name.name);
 		break;
 		break;
 	case ssaValue_Global:
 	case ssaValue_Global:
 		ssa_print_encoded_global(f, value->global.entity->token.string);
 		ssa_print_encoded_global(f, value->global.entity->token.string);
@@ -592,16 +598,21 @@ void ssa_print_proc(gbFile *f, ssaModule *m, ssaProcedure *proc) {
 		ssa_fprintf(f, "}\n\n");
 		ssa_fprintf(f, "}\n\n");
 	}
 	}
 
 
-	gb_for_array(i, proc->anon_procs) {
-		ssa_print_proc(f, m, proc->anon_procs[i]);
-	}
-	gb_for_array(i, proc->nested_procs) {
-		ssa_print_proc(f, m, proc->nested_procs[i]);
+	gb_for_array(i, proc->children) {
+		ssa_print_proc(f, m, proc->children[i]);
 	}
 	}
 }
 }
 
 
+void ssa_print_type_name(gbFile *f, ssaModule *m, ssaValue *v) {
+	GB_ASSERT(v->kind == ssaValue_TypeName);
+	ssa_print_encoded_local(f, v->type_name.name);
+	ssa_fprintf(f, " = type ");
+	ssa_print_type(f, m->sizes, get_base_type(v->type_name.type));
+	ssa_fprintf(f, "\n");
+}
+
 void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
 void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
-if (m->layout.len > 0) {
+	if (m->layout.len > 0) {
 		ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout));
 		ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout));
 	}
 	}
 
 
@@ -618,12 +629,17 @@ if (m->layout.len > 0) {
 	ssa_print_type(f, m->sizes, t_int);
 	ssa_print_type(f, m->sizes, t_int);
 	ssa_fprintf(f, ", i32, i1)\n\n");
 	ssa_fprintf(f, ", i32, i1)\n\n");
 
 
+	gb_for_array(i, m->nested_type_names) {
+		ssaValue *v = m->nested_type_names[i];
+		ssa_print_type_name(f, m, v);
+	}
+
 	gb_for_array(member_index, m->members.entries) {
 	gb_for_array(member_index, m->members.entries) {
 		auto *entry = &m->members.entries[member_index];
 		auto *entry = &m->members.entries[member_index];
 		ssaValue *v = entry->value;
 		ssaValue *v = entry->value;
 		switch (v->kind) {
 		switch (v->kind) {
 		case ssaValue_TypeName: {
 		case ssaValue_TypeName: {
-			ssa_print_encoded_local(f, v->type_name.entity->token.string);
+			ssa_print_encoded_local(f, v->type_name.name);
 			ssa_fprintf(f, " = type ");
 			ssa_fprintf(f, " = type ");
 			ssa_print_type(f, m->sizes, get_base_type(v->type_name.type));
 			ssa_print_type(f, m->sizes, get_base_type(v->type_name.type));
 			ssa_fprintf(f, "\n");
 			ssa_fprintf(f, "\n");

+ 138 - 28
src/codegen/ssa.cpp

@@ -14,6 +14,7 @@ struct ssaModule {
 
 
 	Map<ssaValue *> values;  // Key: Entity *
 	Map<ssaValue *> values;  // Key: Entity *
 	Map<ssaValue *> members; // Key: String
 	Map<ssaValue *> members; // Key: String
+	gbArray(ssaValue *) nested_type_names; // ssaValue_TypeName
 	i32 global_string_index;
 	i32 global_string_index;
 };
 };
 
 
@@ -38,6 +39,8 @@ struct ssaTargetList {
 
 
 struct ssaProcedure {
 struct ssaProcedure {
 	ssaProcedure *parent;
 	ssaProcedure *parent;
+	gbArray(ssaProcedure *) children;
+
 	ssaModule *   module;
 	ssaModule *   module;
 	String        name;
 	String        name;
 	Type *        type;
 	Type *        type;
@@ -47,9 +50,6 @@ struct ssaProcedure {
 	gbArray(ssaBlock *) blocks;
 	gbArray(ssaBlock *) blocks;
 	ssaBlock *          curr_block;
 	ssaBlock *          curr_block;
 	ssaTargetList *     target_list;
 	ssaTargetList *     target_list;
-
-	gbArray(ssaProcedure *) anon_procs;
-	gbArray(ssaProcedure *) nested_procs;
 };
 };
 
 
 
 
@@ -208,7 +208,7 @@ struct ssaValue {
 			ExactValue value;
 			ExactValue value;
 		} constant;
 		} constant;
 		struct {
 		struct {
-			Entity *entity;
+			String name;
 			Type *  type;
 			Type *  type;
 		} type_name;
 		} type_name;
 		struct {
 		struct {
@@ -276,11 +276,13 @@ void ssa_module_init(ssaModule *m, Checker *c) {
 
 
 	map_init(&m->values,  m->allocator);
 	map_init(&m->values,  m->allocator);
 	map_init(&m->members, m->allocator);
 	map_init(&m->members, m->allocator);
+	gb_array_init(m->nested_type_names, m->allocator);
 }
 }
 
 
 void ssa_module_destroy(ssaModule *m) {
 void ssa_module_destroy(ssaModule *m) {
 	map_destroy(&m->values);
 	map_destroy(&m->values);
 	map_destroy(&m->members);
 	map_destroy(&m->members);
+	gb_array_free(m->nested_type_names);
 	gb_arena_free(&m->arena);
 	gb_arena_free(&m->arena);
 }
 }
 
 
@@ -416,10 +418,10 @@ ssaValue *ssa_alloc_instr(gbAllocator a, ssaInstrKind kind) {
 	return v;
 	return v;
 }
 }
 
 
-ssaValue *ssa_make_value_type_name(gbAllocator a, Entity *e) {
+ssaValue *ssa_make_value_type_name(gbAllocator a, String name, Type *type) {
 	ssaValue *v = ssa_alloc_value(a, ssaValue_TypeName);
 	ssaValue *v = ssa_alloc_value(a, ssaValue_TypeName);
-	v->type_name.entity = e;
-	v->type_name.type = e->type;
+	v->type_name.name = name;
+	v->type_name.type = type;
 	return v;
 	return v;
 }
 }
 
 
@@ -1146,8 +1148,17 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 		return value;
 		return value;
 
 
 	if (value->kind == ssaValue_Constant) {
 	if (value->kind == ssaValue_Constant) {
-		if (dst->kind == Type_Basic)
-			return ssa_make_value_constant(proc->module->allocator, t, value->constant.value);
+		if (dst->kind == Type_Basic) {
+			ExactValue ev = value->constant.value;
+			if (is_type_float(dst)) {
+				ev = exact_value_to_float(ev);
+			} else if (is_type_string(dst)) {
+				//
+			} else if (is_type_integer(dst)) {
+				ev = exact_value_to_integer(ev);
+			}
+			return ssa_make_value_constant(proc->module->allocator, t, ev);
+		}
 	}
 	}
 
 
 	// integer -> integer
 	// integer -> integer
@@ -1337,34 +1348,113 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 	case_end;
 	case_end;
 
 
 	case_ast_node(pl, ProcLit, expr);
 	case_ast_node(pl, ProcLit, expr);
-		if (proc->anon_procs == NULL) {
-			// TODO(bill): Cleanup
-			gb_array_init(proc->anon_procs, gb_heap_allocator());
+		if (proc->children == NULL) {
+			gb_array_init(proc->children, gb_heap_allocator());
 		}
 		}
 		// NOTE(bill): Generate a new name
 		// NOTE(bill): Generate a new name
 		// parent$count
 		// parent$count
 		isize name_len = proc->name.len + 1 + 8 + 1;
 		isize name_len = proc->name.len + 1 + 8 + 1;
 		u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
 		u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
-		name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%d", LIT(proc->name), cast(i32)gb_array_count(proc->anon_procs));
+		name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%d", LIT(proc->name), cast(i32)gb_array_count(proc->children));
 		String name = make_string(name_text, name_len-1);
 		String name = make_string(name_text, name_len-1);
 
 
-
-		// auto **found = map_get(&proc->module->info->definitions,
-		                       // hash_pointer(expr))
 		Type *type = type_of_expr(proc->module->info, expr);
 		Type *type = type_of_expr(proc->module->info, expr);
 		ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
 		ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
 		                                           proc->module, type, pl->type, pl->body, name);
 		                                           proc->module, type, pl->type, pl->body, name);
-		ssaProcedure *np = &value->proc;
 
 
-		gb_array_append(proc->anon_procs, np);
+		gb_array_append(proc->children, &value->proc);
 		ssa_build_proc(value, proc);
 		ssa_build_proc(value, proc);
 
 
-		return value; // TODO(bill): Is this correct?
+		return value;
 	case_end;
 	case_end;
 
 
 
 
-	case_ast_node(pl, CompoundLit, expr);
-		GB_PANIC("TODO(bill): ssa_build_single_expr CompoundLit");
+	case_ast_node(cl, CompoundLit, expr);
+		Type *type = type_of_expr(proc->module->info, expr);
+		Type *base_type = get_base_type(type);
+		ssaValue *v = ssa_add_local_generated(proc, type);
+
+		Type *et = NULL;
+		switch (base_type->kind) {
+		case Type_Vector: et = base_type->vector.elem; break;
+		case Type_Array:  et = base_type->array.elem;  break;
+		case Type_Slice:  et = base_type->slice.elem;  break;
+		}
+
+		switch (base_type->kind) {
+		default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
+		case Type_Structure: {
+			auto *st = &base_type->structure;
+			isize index = 0;
+			for (AstNode *elem = cl->elem_list;
+				elem != NULL;
+				elem = elem->next) {
+				ssaValue *field_expr = ssa_build_expr(proc, elem);
+				Type *t = ssa_value_type(field_expr);
+				if (t->kind != Type_Tuple) {
+					Entity *field = st->fields[index];
+					Type *ft = field->type;
+					ssaValue *fv = ssa_emit_conv(proc, field_expr, ft);
+					ssaValue *gep = ssa_emit_struct_gep(proc, v, index, ft);
+					ssa_emit_store(proc, gep, fv);
+					index++;
+				} else {
+					GB_PANIC("TODO(bill): tuples in struct literals");
+				}
+			}
+
+		} break;
+		case Type_Vector:
+		case Type_Array: {
+			isize index = 0;
+			for (AstNode *elem = cl->elem_list;
+				elem != NULL;
+				elem = elem->next) {
+				ssaValue *field_expr = ssa_build_expr(proc, elem);
+				Type *t = ssa_value_type(field_expr);
+				if (t->kind != Type_Tuple) {
+					ssaValue *ev = ssa_emit_conv(proc, field_expr, et);
+					ssaValue *gep = ssa_emit_struct_gep(proc, v, index, et);
+					ssa_emit_store(proc, gep, ev);
+					index++;
+				} else {
+					GB_PANIC("TODO(bill): tuples in array literals");
+				}
+			}
+		} break;
+		case Type_Slice: {
+			i64 count = cl->elem_count;
+			ssaValue *array = ssa_add_local_generated(proc, make_type_array(proc->module->allocator, et, count));
+			isize index = 0;
+			for (AstNode *elem = cl->elem_list;
+				elem != NULL;
+				elem = elem->next) {
+				ssaValue *field_expr = ssa_build_expr(proc, elem);
+				Type *t = ssa_value_type(field_expr);
+				if (t->kind != Type_Tuple) {
+					ssaValue *ev = ssa_emit_conv(proc, field_expr, et);
+					ssaValue *gep = ssa_emit_struct_gep(proc, array, index, et);
+					ssa_emit_store(proc, gep, ev);
+					index++;
+				} else {
+					GB_PANIC("TODO(bill): tuples in array literals");
+				}
+			}
+
+			ssaValue *elem = ssa_emit_struct_gep(proc, array, v_zero32,
+			                                     make_type_pointer(proc->module->allocator, et));
+			ssaValue *len = ssa_array_len(proc, array);
+			ssaValue *gep = NULL;
+			gep = ssa_emit_struct_gep(proc, v, v_zero32, ssa_value_type(elem));
+			ssa_emit_store(proc, gep, elem);
+			gep = ssa_emit_struct_gep(proc, v, v_one32, t_int);
+			ssa_emit_store(proc, gep, len);
+			gep = ssa_emit_struct_gep(proc, v, v_two32, t_int);
+			ssa_emit_store(proc, gep, len);
+		} break;
+		}
+
+		return ssa_emit_load(proc, v);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ce, CastExpr, expr);
 	case_ast_node(ce, CastExpr, expr);
@@ -1768,9 +1858,8 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 	case_end;
 	case_end;
 
 
 	case_ast_node(pd, ProcDecl, node);
 	case_ast_node(pd, ProcDecl, node);
-		if (proc->nested_procs == NULL) {
-			// TODO(bill): Cleanup
-			gb_array_init(proc->nested_procs, gb_heap_allocator());
+		if (proc->children == NULL) {
+			gb_array_init(proc->children, gb_heap_allocator());
 		}
 		}
 		// NOTE(bill): Generate a new name
 		// NOTE(bill): Generate a new name
 		// parent$name
 		// parent$name
@@ -1780,15 +1869,36 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%.*s", LIT(proc->name), LIT(pd_name));
 		name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s$%.*s", LIT(proc->name), LIT(pd_name));
 		String name = make_string(name_text, name_len-1);
 		String name = make_string(name_text, name_len-1);
 
 
-		Entity *e = *map_get(&proc->module->info->definitions, hash_pointer(pd->name));
+		Entity **found = map_get(&proc->module->info->definitions, hash_pointer(pd->name));
+		GB_ASSERT(found != NULL);
+		Entity *e = *found;
 		ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
 		ssaValue *value = ssa_make_value_procedure(proc->module->allocator,
 		                                           proc->module, e->type, pd->type, pd->body, name);
 		                                           proc->module, e->type, pd->type, pd->body, name);
-		ssaProcedure *np = &value->proc;
-		gb_array_append(proc->nested_procs, np);
+
+		ssa_module_add_value(proc->module, e, value);
+		gb_array_append(proc->children, &value->proc);
 		ssa_build_proc(value, proc);
 		ssa_build_proc(value, proc);
+	case_end;
 
 
-		map_set(&proc->module->values, hash_pointer(e), value);
+	case_ast_node(td, TypeDecl, node);
+
+		// NOTE(bill): Generate a new name
+		// parent_proc.name
+		String td_name = td->name->Ident.token.string;
+		isize name_len = proc->name.len + 1 + td_name.len + 1;
+		u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len);
+		name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s", LIT(proc->name), LIT(td_name));
+		String name = make_string(name_text, name_len-1);
 
 
+		Entity **found = map_get(&proc->module->info->definitions, hash_pointer(td->name));
+		GB_ASSERT(found != NULL);
+		Entity *e = *found;
+		ssaValue *value = ssa_make_value_type_name(proc->module->allocator,
+		                                           name, e->type);
+		// HACK(bill): Override name of type so printer prints it correctly
+		e->type->named.name = name;
+		ssa_module_add_value(proc->module, e, value);
+		gb_array_append(proc->module->nested_type_names, value);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ids, IncDecStmt, node);
 	case_ast_node(ids, IncDecStmt, node);

+ 32 - 18
src/parser.cpp

@@ -2,7 +2,6 @@ struct AstNode;
 struct Type;
 struct Type;
 struct AstScope;
 struct AstScope;
 
 
-
 enum ParseFileError {
 enum ParseFileError {
 	ParseFile_None,
 	ParseFile_None,
 
 
@@ -110,6 +109,7 @@ AST_NODE_KIND(_ExprBegin,       struct{}) \
 		AstNode *low, *high, *max; \
 		AstNode *low, *high, *max; \
 		b32 triple_indexed; \
 		b32 triple_indexed; \
 	}) \
 	}) \
+	AST_NODE_KIND(Ellipsis, struct { Token token; }) \
 AST_NODE_KIND(_ExprEnd,       struct{}) \
 AST_NODE_KIND(_ExprEnd,       struct{}) \
 AST_NODE_KIND(_StmtBegin,     struct{}) \
 AST_NODE_KIND(_StmtBegin,     struct{}) \
 	AST_NODE_KIND(BadStmt,    struct { Token begin, end; }) \
 	AST_NODE_KIND(BadStmt,    struct { Token begin, end; }) \
@@ -164,7 +164,6 @@ AST_NODE_KIND(_DeclBegin,      struct{}) \
 			isize name_count, value_count; \
 			isize name_count, value_count; \
 		}) \
 		}) \
 	AST_NODE_KIND(ProcDecl, struct { \
 	AST_NODE_KIND(ProcDecl, struct { \
-			DeclKind kind;     \
 			AstNode *name;     \
 			AstNode *name;     \
 			AstNode *type;     \
 			AstNode *type;     \
 			AstNode *body;     \
 			AstNode *body;     \
@@ -295,6 +294,8 @@ Token ast_node_token(AstNode *node) {
 		return node->IndexExpr.open;
 		return node->IndexExpr.open;
 	case AstNode_SliceExpr:
 	case AstNode_SliceExpr:
 		return node->SliceExpr.open;
 		return node->SliceExpr.open;
+	case AstNode_Ellipsis:
+		return node->Ellipsis.token;
 	case AstNode_CastExpr:
 	case AstNode_CastExpr:
 		return node->CastExpr.token;
 		return node->CastExpr.token;
 	case AstNode_DerefExpr:
 	case AstNode_DerefExpr:
@@ -553,6 +554,11 @@ gb_inline AstNode *make_deref_expr(AstFile *f, AstNode *expr, Token op) {
 }
 }
 
 
 
 
+gb_inline AstNode *make_ellipsis(AstFile *f, Token token) {
+	AstNode *result = make_node(f, AstNode_Ellipsis);
+	result->Ellipsis.token = token;
+	return result;
+}
 gb_inline AstNode *make_basic_lit(AstFile *f, Token basic_lit) {
 gb_inline AstNode *make_basic_lit(AstFile *f, Token basic_lit) {
 	AstNode *result = make_node(f, AstNode_BasicLit);
 	AstNode *result = make_node(f, AstNode_BasicLit);
 	result->BasicLit = basic_lit;
 	result->BasicLit = basic_lit;
@@ -678,7 +684,7 @@ gb_inline AstNode *make_bad_decl(AstFile *f, Token begin, Token end) {
 	return result;
 	return result;
 }
 }
 
 
-gb_inline AstNode *make_variable_decl(AstFile *f, DeclKind kind, AstNode *name_list, isize name_count, AstNode *type, AstNode *value_list, isize value_count) {
+gb_inline AstNode *make_var_decl(AstFile *f, DeclKind kind, AstNode *name_list, isize name_count, AstNode *type, AstNode *value_list, isize value_count) {
 	AstNode *result = make_node(f, AstNode_VarDecl);
 	AstNode *result = make_node(f, AstNode_VarDecl);
 	result->VarDecl.kind = kind;
 	result->VarDecl.kind = kind;
 	result->VarDecl.name_list = name_list;
 	result->VarDecl.name_list = name_list;
@@ -707,9 +713,8 @@ gb_inline AstNode *make_proc_type(AstFile *f, Token token, AstNode *param_list,
 	return result;
 	return result;
 }
 }
 
 
-gb_inline AstNode *make_procedure_decl(AstFile *f, DeclKind kind, AstNode *name, AstNode *proc_type, AstNode *body, AstNode *tag_list, isize tag_count) {
+gb_inline AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, AstNode *tag_list, isize tag_count) {
 	AstNode *result = make_node(f, AstNode_ProcDecl);
 	AstNode *result = make_node(f, AstNode_ProcDecl);
-	result->ProcDecl.kind = kind;
 	result->ProcDecl.name = name;
 	result->ProcDecl.name = name;
 	result->ProcDecl.type = proc_type;
 	result->ProcDecl.type = proc_type;
 	result->ProcDecl.body = body;
 	result->ProcDecl.body = body;
@@ -1169,7 +1174,6 @@ AstNode *parse_atom_expr(AstFile *f, b32 lhs) {
 
 
 		case Token_OpenBrace: {
 		case Token_OpenBrace: {
 			if (is_literal_type(operand) && f->expr_level >= 0) {
 			if (is_literal_type(operand) && f->expr_level >= 0) {
-				gb_printf_err("here\n");
 				if (lhs) {
 				if (lhs) {
 					// TODO(bill): Handle this
 					// TODO(bill): Handle this
 				}
 				}
@@ -1474,8 +1478,12 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 		Token token = expect_token(f, Token_OpenBracket);
 		Token token = expect_token(f, Token_OpenBracket);
 		AstNode *count_expr = NULL;
 		AstNode *count_expr = NULL;
 
 
-		if (f->cursor[0].kind != Token_CloseBracket)
+		if (f->cursor[0].kind == Token_Ellipsis) {
+			count_expr = make_ellipsis(f, f->cursor[0]);
+			next_token(f);
+		} else if (f->cursor[0].kind != Token_CloseBracket) {
 			count_expr = parse_expr(f, false);
 			count_expr = parse_expr(f, false);
+		}
 		expect_token(f, Token_CloseBracket);
 		expect_token(f, Token_CloseBracket);
 		f->expr_level--;
 		f->expr_level--;
 		return make_array_type(f, token, count_expr, parse_type(f));
 		return make_array_type(f, token, count_expr, parse_type(f));
@@ -1596,7 +1604,7 @@ AstNode *parse_body(AstFile *f, AstScope *scope) {
 	return make_block_stmt(f, statement_list, statement_list_count, open, close);
 	return make_block_stmt(f, statement_list, statement_list_count, open, close);
 }
 }
 
 
-AstNode *parse_procedure_decl(AstFile *f, Token proc_token, AstNode *name, DeclKind kind) {
+	AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) {
 	AstNode *param_list = NULL;
 	AstNode *param_list = NULL;
 	AstNode *result_list = NULL;
 	AstNode *result_list = NULL;
 	isize param_count = 0;
 	isize param_count = 0;
@@ -1621,7 +1629,7 @@ AstNode *parse_procedure_decl(AstFile *f, Token proc_token, AstNode *name, DeclK
 	close_ast_scope(f);
 	close_ast_scope(f);
 
 
 	AstNode *proc_type = make_proc_type(f, proc_token, param_list, param_count, result_list, result_count);
 	AstNode *proc_type = make_proc_type(f, proc_token, param_list, param_count, result_list, result_count);
-	return make_procedure_decl(f, kind, name, proc_type, body, tag_list, tag_count);
+	return make_proc_decl(f, name, proc_type, body, tag_list, tag_count);
 }
 }
 
 
 AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) {
 AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) {
@@ -1642,7 +1650,9 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) {
 			declaration_kind = Declaration_Immutable;
 			declaration_kind = Declaration_Immutable;
 		next_token(f);
 		next_token(f);
 
 
-		if (f->cursor[0].kind == Token_proc) { // NOTE(bill): Procedure declarations
+		if (f->cursor[0].kind == Token_proc &&
+		    declaration_kind == Declaration_Immutable) {
+		    // NOTE(bill): Procedure declarations
 			Token proc_token = f->cursor[0];
 			Token proc_token = f->cursor[0];
 			AstNode *name = name_list;
 			AstNode *name = name_list;
 			if (name_count != 1) {
 			if (name_count != 1) {
@@ -1650,9 +1660,9 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) {
 				return make_bad_decl(f, name->Ident.token, proc_token);
 				return make_bad_decl(f, name->Ident.token, proc_token);
 			}
 			}
 
 
-			AstNode *procedure_decl = parse_procedure_decl(f, proc_token, name, declaration_kind);
-			add_ast_entity(f, f->curr_scope, procedure_decl, name_list);
-			return procedure_decl;
+			AstNode *proc_decl = parse_proc_decl(f, proc_token, name);
+			add_ast_entity(f, f->curr_scope, proc_decl, name_list);
+			return proc_decl;
 
 
 		} else {
 		} else {
 			value_list = parse_rhs_expr_list(f, &value_count);
 			value_list = parse_rhs_expr_list(f, &value_count);
@@ -1684,9 +1694,9 @@ AstNode *parse_decl(AstFile *f, AstNode *name_list, isize name_count) {
 		return make_bad_decl(f, begin, f->cursor[0]);
 		return make_bad_decl(f, begin, f->cursor[0]);
 	}
 	}
 
 
-	AstNode *variable_decl = make_variable_decl(f, declaration_kind, name_list, name_count, type, value_list, value_count);
-	add_ast_entity(f, f->curr_scope, variable_decl, name_list);
-	return variable_decl;
+	AstNode *var_decl = make_var_decl(f, declaration_kind, name_list, name_count, type, value_list, value_count);
+	add_ast_entity(f, f->curr_scope, var_decl, name_list);
+	return var_decl;
 }
 }
 
 
 
 
@@ -1761,7 +1771,8 @@ AstNode *parse_return_stmt(AstFile *f) {
 	isize result_count = 0;
 	isize result_count = 0;
 	if (f->cursor[0].kind != Token_Semicolon)
 	if (f->cursor[0].kind != Token_Semicolon)
 		result = parse_rhs_expr_list(f, &result_count);
 		result = parse_rhs_expr_list(f, &result_count);
-	expect_token(f, Token_Semicolon);
+	if (f->cursor[0].kind != Token_CloseBrace)
+		expect_token(f, Token_Semicolon);
 
 
 	return make_return_stmt(f, token, result, result_count);
 	return make_return_stmt(f, token, result, result_count);
 }
 }
@@ -1899,7 +1910,10 @@ AstNode *parse_stmt(AstFile *f) {
 	case Token_Xor:
 	case Token_Xor:
 	case Token_Not:
 	case Token_Not:
 		s = parse_simple_stmt(f);
 		s = parse_simple_stmt(f);
-		if (s->kind != AstNode_ProcDecl && !allow_token(f, Token_Semicolon)) {
+		if (s->kind != AstNode_ProcDecl &&
+			!allow_token(f, Token_Semicolon) &&
+			f->cursor[0].kind == Token_CloseBrace) {
+			// TODO(bill): Cleanup semicolon handling in parser
 			ast_file_err(f, f->cursor[0],
 			ast_file_err(f, f->cursor[0],
 			             "Expected `;` after statement, got `%.*s`",
 			             "Expected `;` after statement, got `%.*s`",
 			             LIT(token_strings[f->cursor[0].kind]));
 			             LIT(token_strings[f->cursor[0].kind]));

+ 1 - 4
src/printer.cpp

@@ -146,10 +146,7 @@ void print_ast(AstNode *node, isize indent) {
 		break;
 		break;
 	case AstNode_ProcDecl:
 	case AstNode_ProcDecl:
 		print_indent(indent);
 		print_indent(indent);
-		if (node->ProcDecl.kind == Declaration_Mutable)
-			gb_printf("(decl:proc,mutable)\n");
-		else if (node->ProcDecl.kind == Declaration_Immutable)
-			gb_printf("(decl:proc,immutable)\n");
+		gb_printf("(decl:proc)\n");
 		print_ast(node->ProcDecl.type, indent+1);
 		print_ast(node->ProcDecl.type, indent+1);
 		print_ast(node->ProcDecl.body, indent+1);
 		print_ast(node->ProcDecl.body, indent+1);
 		print_ast(node->ProcDecl.tag_list, indent+1);
 		print_ast(node->ProcDecl.tag_list, indent+1);

+ 2 - 5
src/tokenizer.cpp

@@ -95,7 +95,7 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
 	TOKEN_KIND(Token_Semicolon, ";"), \
 	TOKEN_KIND(Token_Semicolon, ";"), \
 	TOKEN_KIND(Token_Period, "."), \
 	TOKEN_KIND(Token_Period, "."), \
 	TOKEN_KIND(Token_Comma, ","), \
 	TOKEN_KIND(Token_Comma, ","), \
-	TOKEN_KIND(Token_Ellipsis, "..."), \
+	TOKEN_KIND(Token_Ellipsis, ".."), \
 TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
 TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
 \
 \
 TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
@@ -741,10 +741,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 				token = scan_number_to_token(t, true);
 				token = scan_number_to_token(t, true);
 			} else if (t->curr_rune == '.') { // Could be an ellipsis
 			} else if (t->curr_rune == '.') { // Could be an ellipsis
 				advance_to_next_rune(t);
 				advance_to_next_rune(t);
-				if (t->curr_rune == '.') {
-					advance_to_next_rune(t);
-					token.kind = Token_Ellipsis;
-				}
+				token.kind = Token_Ellipsis;
 			}
 			}
 			break;
 			break;