Browse Source

Optional main for DLL; access struct elements by "index"

Ginger Bill 8 years ago
parent
commit
41aa4e606b
6 changed files with 434 additions and 36 deletions
  1. 12 3
      src/check_expr.c
  2. 136 15
      src/checker.c
  3. 14 3
      src/ir.c
  4. 5 7
      src/ir_print.c
  5. 266 7
      src/parser.c
  6. 1 1
      src/types.c

+ 12 - 3
src/check_expr.c

@@ -3054,8 +3054,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	// if (selector->kind != AstNode_Ident && selector->kind != AstNode_BasicLit) {
-	if (selector->kind != AstNode_Ident) {
+	if (selector->kind != AstNode_Ident && selector->kind != AstNode_BasicLit) {
+	// if (selector->kind != AstNode_Ident) {
 		error_node(selector, "Illegal selector kind: `%.*s`", LIT(ast_node_strings[selector->kind]));
 		error_node(selector, "Illegal selector kind: `%.*s`", LIT(ast_node_strings[selector->kind]));
 		operand->mode = Addressing_Invalid;
 		operand->mode = Addressing_Invalid;
 		operand->expr = node;
 		operand->expr = node;
@@ -5406,6 +5406,15 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 						check_assignment(c, o, field->type, str_lit("structure literal"));
 						check_assignment(c, o, field->type, str_lit("structure literal"));
 					}
 					}
 				} else {
 				} else {
+					bool all_fields_are_blank = true;
+					for (isize i = 0; i < t->Record.field_count; i++) {
+						Entity *field = t->Record.fields_in_src_order[i];
+						if (str_ne(field->token.string, str_lit("_"))) {
+							all_fields_are_blank = false;
+							break;
+						}
+					}
+
 					for_array(index, cl->elems) {
 					for_array(index, cl->elems) {
 						AstNode *elem = cl->elems.e[index];
 						AstNode *elem = cl->elems.e[index];
 						if (elem->kind == AstNode_FieldValue) {
 						if (elem->kind == AstNode_FieldValue) {
@@ -5414,7 +5423,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 						}
 						}
 						Entity *field = t->Record.fields_in_src_order[index];
 						Entity *field = t->Record.fields_in_src_order[index];
 
 
-						if (str_eq(field->token.string, str_lit("_"))) {
+						if (!all_fields_are_blank && str_eq(field->token.string, str_lit("_"))) {
 							// NOTE(bill): Ignore blank identifiers
 							// NOTE(bill): Ignore blank identifiers
 							continue;
 							continue;
 						}
 						}

+ 136 - 15
src/checker.c

@@ -291,6 +291,13 @@ typedef struct DelayedDecl {
 	AstNode *decl;
 	AstNode *decl;
 } DelayedDecl;
 } DelayedDecl;
 
 
+typedef struct CheckerFileNode {
+	i32       id;
+	Array_i32 wheres;
+	Array_i32 whats;
+	i32       score; // Higher the score, the better
+} CheckerFileNode;
+
 typedef struct CheckerContext {
 typedef struct CheckerContext {
 	Scope *    file_scope;
 	Scope *    file_scope;
 	Scope *    scope;
 	Scope *    scope;
@@ -326,6 +333,7 @@ typedef struct Checker {
 	Array(ProcedureInfo)   procs; // NOTE(bill): Procedures to check
 	Array(ProcedureInfo)   procs; // NOTE(bill): Procedures to check
 	Array(DelayedDecl)     delayed_imports;
 	Array(DelayedDecl)     delayed_imports;
 	Array(DelayedDecl)     delayed_foreign_libraries;
 	Array(DelayedDecl)     delayed_foreign_libraries;
+	Array(CheckerFileNode) file_nodes;
 
 
 	gbArena                arena;
 	gbArena                arena;
 	gbArena                tmp_arena;
 	gbArena                tmp_arena;
@@ -735,6 +743,16 @@ void init_checker(Checker *c, Parser *parser, BuildContext *bc) {
 	array_init(&c->procs, a);
 	array_init(&c->procs, a);
 	array_init(&c->delayed_imports, a);
 	array_init(&c->delayed_imports, a);
 	array_init(&c->delayed_foreign_libraries, a);
 	array_init(&c->delayed_foreign_libraries, a);
+	array_init(&c->file_nodes, a);
+
+	for_array(i, parser->files) {
+		AstFile *file = &parser->files.e[i];
+		CheckerFileNode node = {0};
+		node.id = file->id;
+		array_init(&node.whats,  a);
+		array_init(&node.wheres, a);
+		array_add(&c->file_nodes, node);
+	}
 
 
 	// NOTE(bill): Is this big enough or too small?
 	// NOTE(bill): Is this big enough or too small?
 	isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope));
 	isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope));
@@ -762,6 +780,7 @@ void destroy_checker(Checker *c) {
 	array_free(&c->procs);
 	array_free(&c->procs);
 	array_free(&c->delayed_imports);
 	array_free(&c->delayed_imports);
 	array_free(&c->delayed_foreign_libraries);
 	array_free(&c->delayed_foreign_libraries);
+	array_free(&c->file_nodes);
 
 
 	gb_arena_free(&c->arena);
 	gb_arena_free(&c->arena);
 }
 }
@@ -1746,6 +1765,106 @@ String path_to_entity_name(String name, String fullpath) {
 }
 }
 
 
 void check_import_entities(Checker *c, MapScope *file_scopes) {
 void check_import_entities(Checker *c, MapScope *file_scopes) {
+#if 0
+	// TODO(bill): Dependency ordering for imports
+	{
+		Array_i32 shared_global_file_ids = {0};
+		array_init_reserve(&shared_global_file_ids, heap_allocator(), c->file_nodes.count);
+		for_array(i, c->file_nodes) {
+			CheckerFileNode *node = &c->file_nodes.e[i];
+			AstFile *f = &c->parser->files.e[node->id];
+			GB_ASSERT(f->id == node->id);
+			if (f->scope->is_global) {
+				array_add(&shared_global_file_ids, f->id);
+			}
+		}
+
+		for_array(i, c->file_nodes) {
+			CheckerFileNode *node = &c->file_nodes.e[i];
+			AstFile *f = &c->parser->files.e[node->id];
+			if (!f->scope->is_global) {
+				for_array(j, shared_global_file_ids) {
+					array_add(&node->whats, shared_global_file_ids.e[j]);
+				}
+			}
+		}
+
+		array_free(&shared_global_file_ids);
+	}
+
+	for_array(i, c->delayed_imports) {
+		Scope *parent_scope = c->delayed_imports.e[i].parent;
+		AstNode *decl = c->delayed_imports.e[i].decl;
+		ast_node(id, ImportDecl, decl);
+		Token token = id->relpath;
+
+		GB_ASSERT(parent_scope->is_file);
+
+		if (!parent_scope->has_been_imported) {
+			continue;
+		}
+
+		HashKey key = hash_string(id->fullpath);
+		Scope **found = map_scope_get(file_scopes, key);
+		if (found == NULL) {
+			for_array(scope_index, file_scopes->entries) {
+				Scope *scope = file_scopes->entries.e[scope_index].value;
+				gb_printf_err("%.*s\n", LIT(scope->file->tokenizer.fullpath));
+			}
+			gb_printf_err("%.*s(%td:%td)\n", LIT(token.pos.file), token.pos.line, token.pos.column);
+			GB_PANIC("Unable to find scope for file: %.*s", LIT(id->fullpath));
+		}
+		Scope *scope = *found;
+
+		if (scope->is_global) {
+			continue;
+		}
+
+		i32 parent_id = parent_scope->file->id;
+		i32 child_id  = scope->file->id;
+
+		// TODO(bill): Very slow
+		CheckerFileNode *parent_node = &c->file_nodes.e[parent_id];
+		bool add_child = true;
+		for_array(j, parent_node->whats) {
+			if (parent_node->whats.e[j] == child_id) {
+				add_child = false;
+				break;
+			}
+		}
+		if (add_child) {
+			array_add(&parent_node->whats, child_id);
+		}
+
+		CheckerFileNode *child_node  = &c->file_nodes.e[child_id];
+		bool add_parent = true;
+		for_array(j, parent_node->wheres) {
+			if (parent_node->wheres.e[j] == parent_id) {
+				add_parent = false;
+				break;
+			}
+		}
+		if (add_parent) {
+			array_add(&child_node->wheres, parent_id);
+		}
+	}
+
+	for_array(i, c->file_nodes) {
+		CheckerFileNode *node = &c->file_nodes.e[i];
+		AstFile *f = &c->parser->files.e[node->id];
+		gb_printf_err("File %d %.*s", node->id, LIT(f->tokenizer.fullpath));
+		gb_printf_err("\n  wheres:");
+		for_array(j, node->wheres) {
+			gb_printf_err(" %d", node->wheres.e[j]);
+		}
+		gb_printf_err("\n  whats:");
+		for_array(j, node->whats) {
+			gb_printf_err(" %d", node->whats.e[j]);
+		}
+		gb_printf_err("\n");
+	}
+#endif
+
 	for_array(i, c->delayed_imports) {
 	for_array(i, c->delayed_imports) {
 		Scope *parent_scope = c->delayed_imports.e[i].parent;
 		Scope *parent_scope = c->delayed_imports.e[i].parent;
 		AstNode *decl = c->delayed_imports.e[i].decl;
 		AstNode *decl = c->delayed_imports.e[i].decl;
@@ -2017,24 +2136,26 @@ void check_parsed_files(Checker *c) {
 
 
 	// gb_printf_err("Count: %td\n", c->info.type_info_count++);
 	// gb_printf_err("Count: %td\n", c->info.type_info_count++);
 
 
-	for_array(i, file_scopes.entries) {
-		Scope *s = file_scopes.entries.e[i].value;
-		if (s->is_init) {
-			Entity *e = current_scope_lookup_entity(s, str_lit("main"));
-			if (e == NULL) {
-				Token token = {0};
-				if (s->file->tokens.count > 0) {
-					token = s->file->tokens.e[0];
-				} else {
-					token.pos.file = s->file->tokenizer.fullpath;
-					token.pos.line = 1;
-					token.pos.column = 1;
+	if (!build_context.is_dll) {
+		for_array(i, file_scopes.entries) {
+			Scope *s = file_scopes.entries.e[i].value;
+			if (s->is_init) {
+				Entity *e = current_scope_lookup_entity(s, str_lit("main"));
+				if (e == NULL) {
+					Token token = {0};
+					if (s->file->tokens.count > 0) {
+						token = s->file->tokens.e[0];
+					} else {
+						token.pos.file = s->file->tokenizer.fullpath;
+						token.pos.line = 1;
+						token.pos.column = 1;
+					}
+
+					error(token, "Undefined entry point procedure `main`");
 				}
 				}
 
 
-				error(token, "Undefined entry point procedure `main`");
+				break;
 			}
 			}
-
-			break;
 		}
 		}
 	}
 	}
 
 

+ 14 - 3
src/ir.c

@@ -4830,8 +4830,9 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 			a = ir_emit_deep_field_gep(proc, a, sel);
 			a = ir_emit_deep_field_gep(proc, a, sel);
 			return ir_addr(a);
 			return ir_addr(a);
 		} else {
 		} else {
-			Type *type = base_type(type_of_expr(proc->module->info, se->expr));
-			GB_ASSERT(is_type_integer(type));
+			Type *type = type_deref(type_of_expr(proc->module->info, se->expr));
+			Type *selector_type = base_type(type_of_expr(proc->module->info, se->selector));
+			GB_ASSERT_MSG(is_type_integer(selector_type), "%s", type_to_string(selector_type));
 			ExactValue val = type_and_value_of_expression(proc->module->info, sel)->value;
 			ExactValue val = type_and_value_of_expression(proc->module->info, sel)->value;
 			i64 index = val.value_integer;
 			i64 index = val.value_integer;
 
 
@@ -7283,7 +7284,17 @@ void ir_gen_tree(irGen *s) {
 		irBlock *done = ir_new_block(proc, NULL, "if.done"); // NOTE(bill): Append later
 		irBlock *done = ir_new_block(proc, NULL, "if.done"); // NOTE(bill): Append later
 		ir_emit_if(proc, cond, then, done);
 		ir_emit_if(proc, cond, then, done);
 		ir_start_block(proc, then);
 		ir_start_block(proc, then);
-		ir_emit_global_call(proc, "main", NULL, 0);
+
+		{
+			String main_name = str_lit("main");
+			irValue **found = map_ir_value_get(&m->members, hash_string(main_name));
+			if (found != NULL) {
+				ir_emit_call(proc, *found, NULL, 0);
+			} else {
+				ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
+			}
+		}
+
 		ir_emit_jump(proc, done);
 		ir_emit_jump(proc, done);
 		ir_start_block(proc, done);
 		ir_start_block(proc, done);
 
 

+ 5 - 7
src/ir_print.c

@@ -573,14 +573,12 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 			} else {
 			} else {
 				for (isize i = 0; i < value_count; i++) {
 				for (isize i = 0; i < value_count; i++) {
 					Entity *f = type->Record.fields_in_src_order[i];
 					Entity *f = type->Record.fields_in_src_order[i];
-
-					if (str_eq(f->token.string, str_lit("_"))) {
-						values[f->Variable.field_index] = (ExactValue){0};
-					} else {
-						TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems.e[i]);
-						GB_ASSERT(tav != NULL);
-						values[f->Variable.field_index] = tav->value;
+					TypeAndValue *tav = type_and_value_of_expression(m->info, cl->elems.e[i]);
+					ExactValue val = {0};
+					if (tav != NULL) {
+						val = tav->value;
 					}
 					}
+					values[f->Variable.field_index] = val;
 				}
 				}
 			}
 			}
 
 

+ 266 - 7
src/parser.c

@@ -17,8 +17,6 @@ typedef enum ParseFileError {
 
 
 typedef Array(AstNode *) AstNodeArray;
 typedef Array(AstNode *) AstNodeArray;
 
 
-gb_global i32 global_file_id = 0;
-
 typedef struct AstFile {
 typedef struct AstFile {
 	i32            id;
 	i32            id;
 	gbArena        arena;
 	gbArena        arena;
@@ -504,8 +502,9 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_ReturnStmt:    return node->ReturnStmt.token;
 	case AstNode_ReturnStmt:    return node->ReturnStmt.token;
 	case AstNode_ForStmt:       return node->ForStmt.token;
 	case AstNode_ForStmt:       return node->ForStmt.token;
 	case AstNode_RangeStmt:     return node->RangeStmt.token;
 	case AstNode_RangeStmt:     return node->RangeStmt.token;
-	case AstNode_MatchStmt:     return node->MatchStmt.token;
 	case AstNode_CaseClause:    return node->CaseClause.token;
 	case AstNode_CaseClause:    return node->CaseClause.token;
+	case AstNode_MatchStmt:     return node->MatchStmt.token;
+	case AstNode_TypeMatchStmt: return node->TypeMatchStmt.token;
 	case AstNode_DeferStmt:     return node->DeferStmt.token;
 	case AstNode_DeferStmt:     return node->DeferStmt.token;
 	case AstNode_BranchStmt:    return node->BranchStmt.token;
 	case AstNode_BranchStmt:    return node->BranchStmt.token;
 	case AstNode_UsingStmt:     return node->UsingStmt.token;
 	case AstNode_UsingStmt:     return node->UsingStmt.token;
@@ -547,6 +546,267 @@ Token ast_node_token(AstNode *node) {
 	return empty_token;
 	return empty_token;
 }
 }
 
 
+AstNode *clone_ast_node(gbAllocator a, AstNode *node);
+AstNodeArray clone_ast_node_array(gbAllocator a, AstNodeArray array) {
+	AstNodeArray result = {0};
+	if (array.count > 0) {
+		array_init_count(&result, a, array.count);
+		for_array(i, array) {
+			result.e[i] = clone_ast_node(a, array.e[i]);
+		}
+	}
+	return result;
+}
+
+AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
+	if (node == NULL) {
+		return NULL;
+	}
+	AstNode *n = gb_alloc_item(a, AstNode);
+	gb_memmove(n, node, gb_size_of(AstNode));
+
+	switch (n->kind) {
+	case AstNode_Ident: break;
+	case AstNode_Implicit: break;
+	case AstNode_BasicLit: break;
+	case AstNode_BasicDirective: break;
+	case AstNode_Ellipsis:
+		n->Ellipsis.expr = clone_ast_node(a, n->Ellipsis.expr);
+		break;
+	case AstNode_ProcLit:
+		n->ProcLit.type = clone_ast_node(a, n->ProcLit.type);
+		n->ProcLit.body = clone_ast_node(a, n->ProcLit.body);
+		n->ProcLit.foreign_library = clone_ast_node(a, n->ProcLit.foreign_library);
+		break;
+	case AstNode_CompoundLit:
+		n->CompoundLit.type  = clone_ast_node(a, n->CompoundLit.type);
+		n->CompoundLit.elems = clone_ast_node_array(a, n->CompoundLit.elems);
+		break;
+	case AstNode_Alias:
+		n->Alias.expr = clone_ast_node(a, n->Alias.expr);
+		break;
+
+	case AstNode_BadExpr: break;
+	case AstNode_TagExpr:
+		n->TagExpr.expr = clone_ast_node(a, n->TagExpr.expr);
+		break;
+	case AstNode_RunExpr:
+		n->RunExpr.expr = clone_ast_node(a, n->RunExpr.expr);
+		break;
+	case AstNode_UnaryExpr:
+		n->RunExpr.expr = clone_ast_node(a, n->RunExpr.expr);
+		break;
+	case AstNode_BinaryExpr:
+		n->BinaryExpr.left  = clone_ast_node(a, n->BinaryExpr.left);
+		n->BinaryExpr.right = clone_ast_node(a, n->BinaryExpr.right);
+		break;
+	case AstNode_ParenExpr:
+		n->ParenExpr.expr = clone_ast_node(a, n->ParenExpr.expr);
+		break;
+	case AstNode_SelectorExpr:
+		n->SelectorExpr.expr = clone_ast_node(a, n->SelectorExpr.expr);
+		n->SelectorExpr.selector = clone_ast_node(a, n->SelectorExpr.selector);
+		break;
+	case AstNode_IndexExpr:
+		n->IndexExpr.expr  = clone_ast_node(a, n->IndexExpr.expr);
+		n->IndexExpr.index = clone_ast_node(a, n->IndexExpr.index);
+		break;
+	case AstNode_DerefExpr:
+		n->DerefExpr.expr = clone_ast_node(a, n->DerefExpr.expr);
+		break;
+	case AstNode_SliceExpr:
+		n->SliceExpr.expr = clone_ast_node(a, n->SliceExpr.expr);
+		n->SliceExpr.low  = clone_ast_node(a, n->SliceExpr.low);
+		n->SliceExpr.high = clone_ast_node(a, n->SliceExpr.high);
+		n->SliceExpr.max  = clone_ast_node(a, n->SliceExpr.max);
+		break;
+	case AstNode_CallExpr:
+		n->CallExpr.proc = clone_ast_node(a, n->CallExpr.proc);
+		n->CallExpr.args = clone_ast_node_array(a, n->CallExpr.args);
+		break;
+	case AstNode_MacroCallExpr:
+		n->MacroCallExpr.macro = clone_ast_node(a, n->MacroCallExpr.macro);
+		n->MacroCallExpr.args  = clone_ast_node_array(a, n->MacroCallExpr.args);
+		break;
+
+	case AstNode_FieldValue:
+		n->FieldValue.field = clone_ast_node(a, n->FieldValue.field);
+		n->FieldValue.value = clone_ast_node(a, n->FieldValue.value);
+		break;
+
+	case AstNode_TernaryExpr:
+		n->TernaryExpr.cond = clone_ast_node(a, n->TernaryExpr.cond);
+		n->TernaryExpr.x    = clone_ast_node(a, n->TernaryExpr.x);
+		n->TernaryExpr.y    = clone_ast_node(a, n->TernaryExpr.cond);
+		break;
+	case AstNode_TypeAssertion:
+		n->TypeAssertion.expr = clone_ast_node(a, n->TypeAssertion.expr);
+		n->TypeAssertion.type = clone_ast_node(a, n->TypeAssertion.type);
+		break;
+
+	case AstNode_BadStmt:   break;
+	case AstNode_EmptyStmt: break;
+	case AstNode_ExprStmt:
+		n->ExprStmt.expr = clone_ast_node(a, n->ExprStmt.expr);
+		break;
+	case AstNode_TagStmt:
+		n->TagStmt.stmt = clone_ast_node(a, n->TagStmt.stmt);
+		break;
+	case AstNode_AssignStmt:
+		n->AssignStmt.lhs = clone_ast_node_array(a, n->AssignStmt.lhs);
+		n->AssignStmt.rhs = clone_ast_node_array(a, n->AssignStmt.rhs);
+		break;
+	case AstNode_IncDecStmt:
+		n->IncDecStmt.expr = clone_ast_node(a, n->IncDecStmt.expr);
+		break;
+	case AstNode_BlockStmt:
+		n->BlockStmt.stmts = clone_ast_node_array(a, n->BlockStmt.stmts);
+		break;
+	case AstNode_IfStmt:
+		n->IfStmt.init = clone_ast_node(a, n->IfStmt.init);
+		n->IfStmt.cond = clone_ast_node(a, n->IfStmt.cond);
+		n->IfStmt.body = clone_ast_node(a, n->IfStmt.body);
+		n->IfStmt.else_stmt = clone_ast_node(a, n->IfStmt.else_stmt);
+		break;
+	case AstNode_WhenStmt:
+		n->WhenStmt.cond = clone_ast_node(a, n->WhenStmt.cond);
+		n->WhenStmt.body = clone_ast_node(a, n->WhenStmt.body);
+		n->WhenStmt.else_stmt = clone_ast_node(a, n->WhenStmt.else_stmt);
+		break;
+	case AstNode_ReturnStmt:
+		n->ReturnStmt.results = clone_ast_node_array(a, n->ReturnStmt.results);
+		break;
+	case AstNode_ForStmt:
+		n->ForStmt.label = clone_ast_node(a, n->ForStmt.label);
+		n->ForStmt.init  = clone_ast_node(a, n->ForStmt.init);
+		n->ForStmt.cond  = clone_ast_node(a, n->ForStmt.cond);
+		n->ForStmt.post  = clone_ast_node(a, n->ForStmt.post);
+		n->ForStmt.body  = clone_ast_node(a, n->ForStmt.body);
+		break;
+	case AstNode_RangeStmt:
+		n->RangeStmt.label = clone_ast_node(a, n->RangeStmt.label);
+		n->RangeStmt.value = clone_ast_node(a, n->RangeStmt.value);
+		n->RangeStmt.index = clone_ast_node(a, n->RangeStmt.index);
+		n->RangeStmt.expr  = clone_ast_node(a, n->RangeStmt.expr);
+		n->RangeStmt.body  = clone_ast_node(a, n->RangeStmt.body);
+		break;
+	case AstNode_CaseClause:
+		n->CaseClause.list  = clone_ast_node_array(a, n->CaseClause.list);
+		n->CaseClause.stmts = clone_ast_node_array(a, n->CaseClause.stmts);
+		break;
+	case AstNode_MatchStmt:
+		n->MatchStmt.label = clone_ast_node(a, n->MatchStmt.label);
+		n->MatchStmt.init  = clone_ast_node(a, n->MatchStmt.init);
+		n->MatchStmt.tag   = clone_ast_node(a, n->MatchStmt.tag);
+		n->MatchStmt.body  = clone_ast_node(a, n->MatchStmt.body);
+		break;
+	case AstNode_TypeMatchStmt:
+		n->TypeMatchStmt.label = clone_ast_node(a, n->TypeMatchStmt.label);
+		n->TypeMatchStmt.tag   = clone_ast_node(a, n->TypeMatchStmt.tag);
+		n->TypeMatchStmt.body  = clone_ast_node(a, n->TypeMatchStmt.body);
+		break;
+	case AstNode_DeferStmt:
+		n->DeferStmt.stmt = clone_ast_node(a, n->DeferStmt.stmt);
+		break;
+	case AstNode_BranchStmt:
+		n->BranchStmt.label = clone_ast_node(a, n->BranchStmt.label);
+		break;
+	case AstNode_UsingStmt:
+		n->UsingStmt.list = clone_ast_node_array(a, n->UsingStmt.list);
+		break;
+	case AstNode_AsmOperand:
+		n->AsmOperand.operand = clone_ast_node(a, n->AsmOperand.operand);
+		break;
+	case AstNode_AsmStmt:
+		n->AsmStmt.output_list  = clone_ast_node(a, n->AsmStmt.output_list);
+		n->AsmStmt.input_list   = clone_ast_node(a, n->AsmStmt.input_list);
+		n->AsmStmt.clobber_list = clone_ast_node(a, n->AsmStmt.clobber_list);
+		break;
+	case AstNode_PushAllocator:
+		n->PushAllocator.expr = clone_ast_node(a, n->PushAllocator.expr);
+		n->PushAllocator.body = clone_ast_node(a, n->PushAllocator.body);
+		break;
+	case AstNode_PushContext:
+		n->PushContext.expr = clone_ast_node(a, n->PushContext.expr);
+		n->PushContext.body = clone_ast_node(a, n->PushContext.body);
+		break;
+
+	case AstNode_BadDecl: break;
+	case AstNode_ValueDecl:
+		n->ValueDecl.names  = clone_ast_node_array(a, n->ValueDecl.names);
+		n->ValueDecl.type   = clone_ast_node(a, n->ValueDecl.type);
+		n->ValueDecl.values = clone_ast_node_array(a, n->ValueDecl.values);
+		break;
+	case AstNode_ImportDecl:
+		n->ImportDecl.cond = clone_ast_node(a, n->ImportDecl.cond);
+		n->ImportDecl.note = clone_ast_node(a, n->ImportDecl.note);
+		break;
+	case AstNode_ForeignLibrary:
+		n->ForeignLibrary.cond = clone_ast_node(a, n->ForeignLibrary.cond);
+		break;
+	case AstNode_Label:
+		n->Label.name = clone_ast_node(a, n->Label.name);
+		break;
+
+
+	case AstNode_Field:
+		n->Field.names = clone_ast_node_array(a, n->Field.names);
+		n->Field.type  = clone_ast_node(a, n->Field.type);
+		break;
+	case AstNode_FieldList:
+		n->FieldList.list = clone_ast_node_array(a, n->FieldList.list);
+		break;
+	case AstNode_UnionField:
+		n->UnionField.name = clone_ast_node(a, n->UnionField.name);
+		n->UnionField.list = clone_ast_node(a, n->UnionField.list);
+		break;
+
+	case AstNode_HelperType:
+		n->HelperType.type = clone_ast_node(a, n->HelperType.type);
+		break;
+	case AstNode_ProcType:
+		break;
+	case AstNode_PointerType:
+		n->PointerType.type = clone_ast_node(a, n->PointerType.type);
+		break;
+	case AstNode_AtomicType:
+		n->AtomicType.type = clone_ast_node(a, n->AtomicType.type);
+		break;
+	case AstNode_ArrayType:
+		n->ArrayType.count = clone_ast_node(a, n->ArrayType.count);
+		n->ArrayType.elem  = clone_ast_node(a, n->ArrayType.elem);
+		break;
+	case AstNode_DynamicArrayType:
+		n->DynamicArrayType.elem = clone_ast_node(a, n->DynamicArrayType.elem);
+		break;
+	case AstNode_VectorType:
+		n->VectorType.count = clone_ast_node(a, n->VectorType.count);
+		n->VectorType.elem  = clone_ast_node(a, n->VectorType.elem);
+		break;
+	case AstNode_StructType:
+		n->StructType.fields = clone_ast_node_array(a, n->StructType.fields);
+		break;
+	case AstNode_UnionType:
+		n->UnionType.fields   = clone_ast_node_array(a, n->UnionType.fields);
+		n->UnionType.variants = clone_ast_node_array(a, n->UnionType.variants);
+		break;
+	case AstNode_RawUnionType:
+		n->RawUnionType.fields = clone_ast_node_array(a, n->RawUnionType.fields);
+		break;
+	case AstNode_EnumType:
+		n->EnumType.base_type = clone_ast_node(a, n->EnumType.base_type);
+		n->EnumType.fields    = clone_ast_node_array(a, n->EnumType.fields);
+		break;
+	case AstNode_MapType:
+		n->MapType.count = clone_ast_node(a, n->MapType.count);
+		n->MapType.key   = clone_ast_node(a, n->MapType.key);
+		n->MapType.value = clone_ast_node(a, n->MapType.value);
+		break;
+	}
+
+	return n;
+}
+
 
 
 void error_node(AstNode *node, char *fmt, ...) {
 void error_node(AstNode *node, char *fmt, ...) {
 	va_list va;
 	va_list va;
@@ -1971,9 +2231,9 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
 			case Token_Ident:
 			case Token_Ident:
 				operand = ast_selector_expr(f, token, operand, parse_ident(f));
 				operand = ast_selector_expr(f, token, operand, parse_ident(f));
 				break;
 				break;
-			// case Token_Integer:
-				// operand = ast_selector_expr(f, token, operand, parse_expr(f, lhs));
-				// break;
+			case Token_Integer:
+				operand = ast_selector_expr(f, token, operand, parse_expr(f, lhs));
+				break;
 			case Token_OpenParen: {
 			case Token_OpenParen: {
 				Token open = expect_token(f, Token_OpenParen);
 				Token open = expect_token(f, Token_OpenParen);
 				AstNode *type = parse_type(f);
 				AstNode *type = parse_type(f);
@@ -3653,7 +3913,6 @@ ParseFileError init_ast_file(AstFile *f, String fullpath) {
 		gb_arena_init_from_allocator(&f->arena, heap_allocator(), arena_size);
 		gb_arena_init_from_allocator(&f->arena, heap_allocator(), arena_size);
 
 
 		f->curr_proc = NULL;
 		f->curr_proc = NULL;
-		f->id = ++global_file_id;
 
 
 		return ParseFile_None;
 		return ParseFile_None;
 	}
 	}

+ 1 - 1
src/types.c

@@ -1226,7 +1226,7 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, bool is_ty
 }
 }
 
 
 Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
 Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) {
-	GB_ASSERT(is_type_struct(type) || is_type_tuple(type));
+	GB_ASSERT(is_type_struct(type) || is_type_union(type) || is_type_tuple(type));
 	type = base_type(type);
 	type = base_type(type);
 
 
 	i64 max_count = 0;
 	i64 max_count = 0;