Prechádzať zdrojové kódy

Comma for all field separators; Overloaded procedures follow exportation rules

Ginger Bill 8 rokov pred
rodič
commit
cb59c1cf08
14 zmenil súbory, kde vykonal 440 pridanie a 286 odobranie
  1. 11 6
      code/demo.odin
  2. 56 56
      core/_preload.odin
  3. 21 21
      core/fmt.odin
  4. 7 7
      core/mem.odin
  5. 18 18
      core/sync.odin
  6. 46 48
      core/sys/windows.odin
  7. 1 3
      core/utf8.odin
  8. 88 28
      src/check_expr.c
  9. 6 12
      src/check_stmt.c
  10. 6 6
      src/checker.c
  11. 3 2
      src/entity.c
  12. 164 74
      src/parser.c
  13. 3 3
      src/tokenizer.c
  14. 10 2
      src/types.c

+ 11 - 6
code/demo.odin

@@ -1,23 +1,29 @@
 #import "atomic.odin";
 #import "fmt.odin";
+#import "hash.odin";
 #import "math.odin";
 #import "mem.odin";
+#import "opengl.odin";
+#import "os.odin";
+#import "sync.odin";
+#import "utf8.odin";
 
 main :: proc() {
-	foo :: proc(x: ^int) {
+	foo :: proc(x: ^i32) {
 		fmt.println("^int");
 	}
 	foo :: proc(x: rawptr) {
 		fmt.println("rawptr");
 	}
 
-	a: ^int;
-	b: ^f32;
+	a: i32;
+	b: f32;
 	c: rawptr;
-	foo(a);
-	foo(b);
+	foo(^a);
+	foo(^b);
 	foo(c);
 	// foo(nil);
+	atomic.store(^a, 1);
 
 	foo :: proc() {
 		fmt.printf("Zero args\n");
@@ -32,7 +38,6 @@ main :: proc() {
 	THINGI :: 14451;
 	THINGF :: 14451.1;
 
-
 	foo();
 	foo(THINGI as int);
 	foo(int(THINGI));

+ 56 - 56
core/_preload.odin

@@ -14,20 +14,20 @@
 // IMPORTANT NOTE(bill): Do not change the order of any of this data
 // The compiler relies upon this _exact_ order
 Type_Info_Member :: struct #ordered {
-	name:      string;     // can be empty if tuple
-	type_info: ^Type_Info;
-	offset:    int;        // offsets are not used in tuples
+	name:      string,     // can be empty if tuple
+	type_info: ^Type_Info,
+	offset:    int,        // offsets are not used in tuples
 }
 Type_Info_Record :: struct #ordered {
-	fields:  []Type_Info_Member;
-	size:    int; // in bytes
-	align:   int; // in bytes
-	packed:  bool;
-	ordered: bool;
+	fields:  []Type_Info_Member,
+	size:    int, // in bytes
+	align:   int, // in bytes
+	packed:  bool,
+	ordered: bool,
 }
 Type_Info_Enum_Value :: raw_union {
-	f: f64;
-	i: i64;
+	f: f64,
+	i: i64,
 }
 
 // NOTE(bill): This much the same as the compiler's
@@ -40,55 +40,55 @@ Calling_Convention :: enum {
 
 Type_Info :: union {
 	Named: struct #ordered {
-		name: string;
-		base: ^Type_Info; // This will _not_ be a Type_Info.Named
-	};
+		name: string,
+		base: ^Type_Info, // This will _not_ be a Type_Info.Named
+	},
 	Integer: struct #ordered {
-		size:   int; // in bytes
-		signed: bool;
-	};
+		size:   int, // in bytes
+		signed: bool,
+	},
 	Float: struct #ordered {
-		size: int; // in bytes
-	};
-	Any:     struct #ordered {};
-	String:  struct #ordered {};
-	Boolean: struct #ordered {};
+		size: int, // in bytes
+	},
+	Any:     struct #ordered {},
+	String:  struct #ordered {},
+	Boolean: struct #ordered {},
 	Pointer: struct #ordered {
-		elem: ^Type_Info; // nil -> rawptr
-	};
+		elem: ^Type_Info, // nil -> rawptr
+	},
 	Maybe: struct #ordered {
-		elem: ^Type_Info;
-	};
+		elem: ^Type_Info,
+	},
 	Procedure: struct #ordered {
-		params:     ^Type_Info; // Type_Info.Tuple
-		results:    ^Type_Info; // Type_Info.Tuple
-		variadic:   bool;
-		convention: Calling_Convention;
-	};
+		params:     ^Type_Info, // Type_Info.Tuple
+		results:    ^Type_Info, // Type_Info.Tuple
+		variadic:   bool,
+		convention: Calling_Convention,
+	},
 	Array: struct #ordered {
-		elem:      ^Type_Info;
-		elem_size: int;
-		count:     int;
-	};
+		elem:      ^Type_Info,
+		elem_size: int,
+		count:     int,
+	},
 	Slice: struct #ordered {
-		elem:      ^Type_Info;
-		elem_size: int;
-	};
+		elem:      ^Type_Info,
+		elem_size: int,
+	},
 	Vector: struct #ordered {
-		elem:      ^Type_Info;
-		elem_size: int;
-		count:     int;
-		align:     int;
-	};
-	Tuple:     Type_Info_Record;
-	Struct:    Type_Info_Record;
-	Union:     Type_Info_Record;
-	Raw_Union: Type_Info_Record;
+		elem:      ^Type_Info,
+		elem_size: int,
+		count:     int,
+		align:     int,
+	},
+	Tuple:     Type_Info_Record,
+	Struct:    Type_Info_Record,
+	Union:     Type_Info_Record,
+	Raw_Union: Type_Info_Record,
 	Enum: struct #ordered {
-		base:  ^Type_Info;
-		names: []string;
-		values: []Type_Info_Enum_Value;
-	};
+		base:  ^Type_Info,
+		names: []string,
+		values: []Type_Info_Enum_Value,
+	},
 }
 
 type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
@@ -137,17 +137,17 @@ Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocator_Mode,
                             size, alignment: int,
                             old_memory: rawptr, old_size: int, flags: u64) -> rawptr;
 Allocator :: struct #ordered {
-	procedure: Allocator_Proc;
-	data:      rawptr;
+	procedure: Allocator_Proc,
+	data:      rawptr,
 }
 
 Context :: struct #ordered {
-	thread_id: int;
+	thread_id: int,
 
-	allocator: Allocator;
+	allocator: Allocator,
 
-	user_data:  rawptr;
-	user_index: int;
+	user_data:  rawptr,
+	user_index: int,
 }
 
 #thread_local __context: Context;

+ 21 - 21
core/fmt.odin

@@ -5,8 +5,8 @@
 DEFAULT_BUFFER_SIZE :: 1<<12;
 
 Buffer :: struct {
-	data:   []byte;
-	length: int;
+	data:   []byte,
+	length: int,
 }
 
 buffer_write :: proc(buf: ^Buffer, b: []byte) {
@@ -38,22 +38,22 @@ buffer_write_rune :: proc(buf: ^Buffer, r: rune) {
 }
 
 Fmt_Info :: struct {
-	minus:     bool;
-	plus:      bool;
-	space:     bool;
-	zero:      bool;
-	hash:      bool;
-	width_set: bool;
-	prec_set:  bool;
-
-	width:     int;
-	prec:      int;
-
-	reordered:      bool;
-	good_arg_index: bool;
-
-	buf: ^Buffer;
-	arg: any; // Temporary
+	minus:     bool,
+	plus:      bool,
+	space:     bool,
+	zero:      bool,
+	hash:      bool,
+	width_set: bool,
+	prec_set:  bool,
+
+	width:     int,
+	prec:      int,
+
+	reordered:      bool,
+	good_arg_index: bool,
+
+	buf: ^Buffer,
+	arg: any, // Temporary
 }
 
 
@@ -827,9 +827,9 @@ __real_to_string :: proc(start: ^string, out: []byte, decimal_pos: ^i32, val: f6
 
 generic_ftoa :: proc(buf: []byte, val: f64, verb: rune, prec, bit_size: int) -> []byte {
 	Float_Info :: struct {
-		mantbits: uint;
-		expbits:  uint;
-		bias:     int;
+		mantbits: uint,
+		expbits:  uint,
+		bias:     int,
 	};
 	f32info := Float_Info{23,  8,  -127};
 	f64info := Float_Info{52, 11, -1023};

+ 7 - 7
core/mem.odin

@@ -68,7 +68,7 @@ align_forward :: proc(ptr: rawptr, align: int) -> rawptr {
 
 
 Allocation_Header :: struct {
-	size: int;
+	size: int,
 }
 
 allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: int) {
@@ -94,15 +94,15 @@ allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
 
 // Custom allocators
 Arena :: struct {
-	backing:    Allocator;
-	offset:     int;
-	memory:     []byte;
-	temp_count: int;
+	backing:    Allocator,
+	offset:     int,
+	memory:     []byte,
+	temp_count: int,
 }
 
 Arena_Temp_Memory :: struct {
-	arena:          ^Arena;
-	original_count: int;
+	arena:          ^Arena,
+	original_count: int,
 }
 
 

+ 18 - 18
core/sync.odin

@@ -2,14 +2,14 @@
 #import "atomic.odin";
 
 Semaphore :: struct {
-	handle: win32.HANDLE;
+	handle: win32.HANDLE,
 }
 
 Mutex :: struct {
-	semaphore: Semaphore;
-	counter:   i32;
-	owner:     i32;
-	recursion: i32;
+	semaphore: Semaphore,
+	counter:   i32,
+	owner:     i32,
+	recursion: i32,
 }
 
 current_thread_id :: proc() -> i32 {
@@ -36,8 +36,8 @@ semaphore_wait :: proc(s: ^Semaphore) {
 
 
 mutex_init :: proc(m: ^Mutex) {
-	atomic.store32(^m.counter, 0);
-	atomic.store32(^m.owner, current_thread_id());
+	atomic.store(^m.counter, 0);
+	atomic.store(^m.owner, current_thread_id());
 	semaphore_init(^m.semaphore);
 	m.recursion = 0;
 }
@@ -46,27 +46,27 @@ mutex_destroy :: proc(m: ^Mutex) {
 }
 mutex_lock :: proc(m: ^Mutex) {
 	thread_id := current_thread_id();
-	if atomic.fetch_add32(^m.counter, 1) > 0 {
-		if thread_id != atomic.load32(^m.owner) {
+	if atomic.fetch_add(^m.counter, 1) > 0 {
+		if thread_id != atomic.load(^m.owner) {
 			semaphore_wait(^m.semaphore);
 		}
 	}
-	atomic.store32(^m.owner, thread_id);
+	atomic.store(^m.owner, thread_id);
 	m.recursion += 1;
 }
 mutex_try_lock :: proc(m: ^Mutex) -> bool {
 	thread_id := current_thread_id();
-	if atomic.load32(^m.owner) == thread_id {
-		atomic.fetch_add32(^m.counter, 1);
+	if atomic.load(^m.owner) == thread_id {
+		atomic.fetch_add(^m.counter, 1);
 	} else {
 		expected: i32 = 0;
-		if atomic.load32(^m.counter) != 0 {
+		if atomic.load(^m.counter) != 0 {
 			return false;
 		}
-		if atomic.compare_exchange32(^m.counter, expected, 1) == 0 {
+		if atomic.compare_exchange(^m.counter, expected, 1) == 0 {
 			return false;
 		}
-		atomic.store32(^m.owner, thread_id);
+		atomic.store(^m.owner, thread_id);
 	}
 	m.recursion += 1;
 	return true;
@@ -74,15 +74,15 @@ mutex_try_lock :: proc(m: ^Mutex) -> bool {
 mutex_unlock :: proc(m: ^Mutex) {
 	recursion: i32;
 	thread_id := current_thread_id();
-	assert(thread_id == atomic.load32(^m.owner));
+	assert(thread_id == atomic.load(^m.owner));
 
 	m.recursion -= 1;
 	recursion = m.recursion;
 	if recursion == 0 {
-		atomic.store32(^m.owner, thread_id);
+		atomic.store(^m.owner, thread_id);
 	}
 
-	if atomic.fetch_add32(^m.counter, -1) > 1 {
+	if atomic.fetch_add(^m.counter, -1) > 1 {
 		if recursion == 0 {
 			semaphore_release(^m.semaphore);
 		}

+ 46 - 48
core/sys/windows.odin

@@ -16,7 +16,7 @@ LPARAM    :: int;
 LRESULT   :: int;
 ATOM      :: i16;
 BOOL      :: i32;
-WNDPROC   :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT;
+WNDPROC   :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
 
 
 INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE;
@@ -56,61 +56,61 @@ SW_SHOW :: 5;
 
 
 POINT :: struct #ordered {
-	x, y: i32;
+	x, y: i32,
 }
 
 WNDCLASSEXA :: struct #ordered {
-	size, style:           u32;
-	wnd_proc:              WNDPROC;
-	cls_extra, wnd_extra:  i32;
-	instance:              HINSTANCE;
-	icon:                  HICON;
-	cursor:                HCURSOR;
-	background:            HBRUSH;
-	menu_name, class_name: ^u8;
-	sm:                    HICON;
+	size, style:           u32,
+	wnd_proc:              WNDPROC,
+	cls_extra, wnd_extra:  i32,
+	instance:              HINSTANCE,
+	icon:                  HICON,
+	cursor:                HCURSOR,
+	background:            HBRUSH,
+	menu_name, class_name: ^u8,
+	sm:                    HICON,
 }
 
 MSG :: struct #ordered {
-	hwnd:    HWND;
-	message: u32;
-	wparam:  WPARAM;
-	lparam:  LPARAM;
-	time:    u32;
-	pt:      POINT;
+	hwnd:    HWND,
+	message: u32,
+	wparam:  WPARAM,
+	lparam:  LPARAM,
+	time:    u32,
+	pt:      POINT,
 }
 
 RECT :: struct #ordered {
-	left:   i32;
-	top:    i32;
-	right:  i32;
-	bottom: i32;
+	left:   i32,
+	top:    i32,
+	right:  i32,
+	bottom: i32,
 }
 
 FILETIME :: struct #ordered {
-	lo, hi: u32;
+	lo, hi: u32,
 }
 
 BY_HANDLE_FILE_INFORMATION :: struct #ordered {
-	file_attributes:      u32;
+	file_attributes:      u32,
 	creation_time,
 	last_access_time,
-	last_write_time:      FILETIME;
+	last_write_time:      FILETIME,
 	volume_serial_number,
 	file_size_high,
 	file_size_low,
 	number_of_links,
 	file_index_high,
-	file_index_low:       u32;
+	file_index_low:       u32,
 }
 
 FILE_ATTRIBUTE_DATA :: struct #ordered {
-	file_attributes:  u32;
+	file_attributes:  u32,
 	creation_time,
 	last_access_time,
-	last_write_time:  FILETIME;
+	last_write_time:  FILETIME,
 	file_size_high,
-	file_size_low:    u32;
+	file_size_low:    u32,
 }
 
 GET_FILEEX_INFO_LEVELS :: i32;
@@ -249,9 +249,9 @@ HEAP_ZERO_MEMORY :: 0x00000008;
 // Synchronization
 
 SECURITY_ATTRIBUTES :: struct #ordered {
-	length:              u32;
-	security_descriptor: rawptr;
-	inherit_handle:      BOOL;
+	length:              u32,
+	security_descriptor: rawptr,
+	inherit_handle:      BOOL,
 }
 
 INFINITE :: 0xffffffff;
@@ -281,25 +281,23 @@ ReadBarrier      :: proc() #foreign
 
 // GDI
 BITMAPINFOHEADER :: struct #ordered {
-	size:              u32;
-	width, height:     i32;
-	planes, bit_count: i16;
-	compression:       u32;
-	size_image:        u32;
-	x_pels_per_meter:  i32;
-	y_pels_per_meter:  i32;
-	clr_used:          u32;
-	clr_important:     u32;
+	size:              u32,
+	width, height:     i32,
+	planes, bit_count: i16,
+	compression:       u32,
+	size_image:        u32,
+	x_pels_per_meter:  i32,
+	y_pels_per_meter:  i32,
+	clr_used:          u32,
+	clr_important:     u32,
 }
 BITMAPINFO :: struct #ordered {
-	using header: BITMAPINFOHEADER;
-	colors:       [1]RGBQUAD;
+	using header: BITMAPINFOHEADER,
+	colors:       [1]RGBQUAD,
 }
 
 
-RGBQUAD :: struct #ordered {
-	blue, green, red, reserved: byte;
-}
+RGBQUAD :: struct #ordered { blue, green, red, reserved: byte }
 
 BI_RGB         :: 0;
 DIB_RGB_COLORS :: 0x00;
@@ -354,7 +352,7 @@ wglCreateContextAttribsARBType :: proc(hdc: HDC, hshareContext: rawptr, attribLi
 PIXELFORMATDESCRIPTOR :: struct #ordered {
 	size,
 	version,
-	flags: u32;
+	flags: u32,
 
 	pixel_type,
 	color_bits,
@@ -375,11 +373,11 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
 	stencil_bits,
 	aux_buffers,
 	layer_type,
-	reserved: byte;
+	reserved: byte,
 
 	layer_mask,
 	visible_mask,
-	damage_mask: u32;
+	damage_mask: u32,
 }
 
 GetDC             :: proc(h: HANDLE) -> HDC #foreign

+ 1 - 3
core/utf8.odin

@@ -8,9 +8,7 @@ UTF_MAX    :: 4;
 SURROGATE_MIN :: 0xd800;
 SURROGATE_MAX :: 0xdfff;
 
-Accept_Range :: struct {
-	lo, hi: u8;
-}
+Accept_Range :: struct { lo, hi: u8 }
 
 accept_ranges := [5]Accept_Range{
 	{0x80, 0xbf},

+ 88 - 28
src/check_expr.c

@@ -5,7 +5,7 @@ ExprKind check_expr_base                (Checker *c, Operand *operand, AstNode *
 Type *   check_type_extra               (Checker *c, AstNode *expression, Type *named_type);
 Type *   check_type                     (Checker *c, AstNode *expression);
 void     check_type_decl                (Checker *c, Entity *e, AstNode *type_expr, Type *def);
-Entity * check_selector                 (Checker *c, Operand *operand, AstNode *node);
+Entity * check_selector                 (Checker *c, Operand *operand, AstNode *node, Type *type_hint);
 void     check_not_tuple                (Checker *c, Operand *operand);
 void     convert_to_typed               (Checker *c, Operand *operand, Type *target_type, i32 level);
 gbString expr_to_string                 (AstNode *expression);
@@ -757,6 +757,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 					p->flags &= ~FieldFlag_no_alias; // Remove the flag
 				}
 			}
+
 			for_array(j, p->names) {
 				AstNode *name = p->names.e[j];
 				if (ast_node_expect(name, AstNode_Ident)) {
@@ -779,6 +780,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 		// Custom Calling convention for variadic parameters
 		Entity *end = variables[variable_count-1];
 		end->type = make_type_slice(c->allocator, end->type);
+		end->flags |= EntityFlag_Ellipsis;
 	}
 
 	Type *tuple = make_type_tuple(c->allocator);
@@ -874,10 +876,10 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Type
 		Scope *s = e->scope;
 		bool skip = false;
 
+		Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count);
+		map_entity_multi_get_all(&s->elements, key, procs);
 		if (type_hint != NULL) {
 			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
-			Entity **procs = gb_alloc_array(c->tmp_allocator, Entity *, overload_count);
-			map_entity_multi_get_all(&s->elements, key, procs);
 			// NOTE(bill): These should be done
 			for (isize i = 0; i < overload_count; i++) {
 				Type *t = base_type(procs[i]->type);
@@ -899,12 +901,13 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Type
 		}
 
 		if (!skip) {
-			o->mode                    = Addressing_Overload;
-			o->type                    = t_invalid;
-			o->overload_count          = overload_count;
-			o->initial_overload_entity = e;
+			o->mode              = Addressing_Overload;
+			o->type              = t_invalid;
+			o->overload_count    = overload_count;
+			o->overload_entities = procs;
 			return;
 		}
+		gb_free(heap_allocator(), procs);
 	}
 
 	add_entity_use(c, n, e);
@@ -1040,7 +1043,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
 
 	case_ast_node(se, SelectorExpr, e);
 		Operand o = {0};
-		check_selector(c, &o, e);
+		check_selector(c, &o, e, NULL);
 
 		switch (o.mode) {
 		case Addressing_Invalid:
@@ -2461,7 +2464,7 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val
 	return true;
 }
 
-Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
+Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) {
 	ast_node(se, SelectorExpr, node);
 
 	bool check_op_expr = true;
@@ -2480,31 +2483,88 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
 	}
 
 	if (op_expr->kind == AstNode_Ident) {
+		b32 is_not_exported = true;
 		String name = op_expr->Ident.string;
 		Entity *e = scope_lookup_entity(c->context.scope, name);
+
 		add_entity_use(c, op_expr, e);
 		expr_entity = e;
+
 		if (e != NULL && e->kind == Entity_ImportName &&
 		    selector->kind == AstNode_Ident) {
 			String sel_name = selector->Ident.string;
+
 			check_op_expr = false;
 			entity = scope_lookup_entity(e->ImportName.scope, sel_name);
 			if (entity == NULL) {
 				error_node(op_expr, "`%.*s` is not declared by `%.*s`", LIT(sel_name), LIT(name));
 				goto error;
 			}
-			if (entity->type == NULL) { // Not setup yet
-				check_entity_decl(c, entity, NULL, NULL);
-			}
+			check_entity_decl(c, entity, NULL, NULL);
 			GB_ASSERT(entity->type != NULL);
 
-			b32 is_not_exported = true;
-			Entity **found = map_entity_get(&e->ImportName.scope->implicit, hash_string(sel_name));
-			if (found == NULL) {
+			bool is_overloaded = false;
+			isize overload_count = 0;
+			HashKey key = {0};
+			if (entity->kind == Entity_Procedure) {
+				key = hash_string(entity->token.string);
+				// NOTE(bill): Overloads are only allowed with the same scope
+				Scope *s = entity->scope;
+				overload_count = map_entity_multi_count(&s->elements, key);
+				if (overload_count > 1) {
+					is_overloaded = true;
+				}
+			}
+
+			if (is_overloaded) {
+				Scope *s = entity->scope;
+				bool skip = false;
+
+				Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count);
+				map_entity_multi_get_all(&s->elements, key, procs);
+				for (isize i = 0; i < overload_count; /**/) {
+					Type *t = base_type(procs[i]->type);
+					if (t == t_invalid) {
+						continue;
+					}
+
+					// NOTE(bill): Check to see if it's imported
+					if (map_bool_get(&e->ImportName.scope->implicit, hash_pointer(procs[i]))) {
+						gb_swap(Entity *, procs[i], procs[overload_count-1]);
+						overload_count--;
+						continue;
+					}
+
+					Operand x = {0};
+					x.mode = Addressing_Value;
+					x.type = t;
+					if (type_hint != NULL) {
+						if (check_is_assignable_to(c, &x, type_hint)) {
+							entity = procs[i];
+							skip = true;
+							break;
+						}
+					}
+
+					i++;
+				}
+
+				if (overload_count > 0 && !skip) {
+					operand->mode              = Addressing_Overload;
+					operand->type              = t_invalid;
+					operand->expr              = node;
+					operand->overload_count    = overload_count;
+					operand->overload_entities = procs;
+					return procs[0];
+				}
+			}
+
+			bool *found = map_bool_get(&e->ImportName.scope->implicit, hash_pointer(entity));
+
+			if (!found) {
 				is_not_exported = false;
 			} else {
-				Entity *f = *found;
-				if (f->kind == Entity_ImportName) {
+				if (entity->kind == Entity_ImportName) {
 					is_not_exported = true;
 				}
 			}
@@ -2515,8 +2575,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
 				gb_string_free(sel_str);
 				// NOTE(bill): Not really an error so don't goto error
 			}
-
-			add_entity_use(c, selector, entity);
 		}
 	}
 	if (check_op_expr) {
@@ -3606,16 +3664,15 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
 
 
 	if (operand->mode == Addressing_Overload) {
-		Scope *s = operand->initial_overload_entity->scope;
-		String name = operand->initial_overload_entity->token.string;
-		HashKey key = hash_string(name);
+		GB_ASSERT(operand->overload_entities != NULL &&
+		          operand->overload_count > 0);
 
 		isize              overload_count = operand->overload_count;
-		Entity **          procs          = gb_alloc_array(heap_allocator(), Entity *, overload_count);
+		Entity **          procs          = operand->overload_entities;
 		ValidProcAndScore *valids         = gb_alloc_array(heap_allocator(), ValidProcAndScore, overload_count);
 		isize              valid_count    = 0;
 
-		map_entity_multi_get_all(&s->elements, key, procs);
+		String name = procs[0]->token.string;
 
 		for (isize i = 0; i < overload_count; i++) {
 			Entity *e = procs[i];
@@ -3666,9 +3723,13 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
 			}
 			proc_type = t_invalid;
 		} else {
-			GB_ASSERT(operand->expr->kind == AstNode_Ident);
+			AstNode *expr = operand->expr;
+			while (expr->kind == AstNode_SelectorExpr) {
+				expr = expr->SelectorExpr.selector;
+			}
+			GB_ASSERT(expr->kind == AstNode_Ident);
 			Entity *e = procs[valids[0].index];
-			add_entity_use(c, operand->expr, e);
+			add_entity_use(c, expr, e);
 			proc_type = e->type;
 			i64 score = 0;
 			CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, true, &score);
@@ -4473,7 +4534,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 
 
 	case_ast_node(se, SelectorExpr, node);
-		check_selector(c, o, node);
+		check_selector(c, o, node, type_hint);
 	case_end;
 
 
@@ -4763,7 +4824,6 @@ gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) {
 		if (i > 0) {
 			str = gb_string_appendc(str, sep);
 		}
-
 		str = write_expr_to_string(str, params.e[i]);
 	}
 	return str;

+ 6 - 12
src/check_stmt.c

@@ -215,14 +215,9 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 
 	if (op_a->mode == Addressing_Overload) {
 		isize overload_count = op_a->overload_count;
-		Entity *entity = op_a->initial_overload_entity;
-		String name = entity->token.string;
-		Scope *s = entity->scope;
-		gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
-		Entity **procs = gb_alloc_array(c->tmp_allocator, Entity *, overload_count);
-
-		HashKey key = hash_string(name);
-		map_entity_multi_get_all(&s->elements, key, procs);
+		Entity **procs = op_a->overload_entities;
+		GB_ASSERT(procs != NULL && overload_count > 0);
+
 		// NOTE(bill): These should be done
 		for (isize i = 0; i < overload_count; i++) {
 			Type *t = base_type(procs[i]->type);
@@ -238,15 +233,14 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 				break;
 			}
 		}
-		gb_temp_arena_memory_end(tmp);
 
 		if (e != NULL) {
+			// HACK TODO(bill): Should the entities be freed as it's technically a leak
 			op_a->mode = Addressing_Value;
 			op_a->type = e->type;
 			op_a->overload_count = 0;
-			op_a->initial_overload_entity = NULL;
+			op_a->overload_entities = NULL;
 		}
-
 	} else {
 		if (node->kind == AstNode_Ident) {
 			ast_node(i, Ident, node);
@@ -1085,7 +1079,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 				e = scope_lookup_entity(c->context.scope, name);
 			} else if (expr->kind == AstNode_SelectorExpr) {
 				Operand o = {0};
-				e = check_selector(c, &o, expr);
+				e = check_selector(c, &o, expr, NULL);
 				is_selector = true;
 			}
 

+ 6 - 6
src/checker.c

@@ -28,7 +28,7 @@ typedef struct Operand {
 	AstNode *      expr;
 	BuiltinProcId  builtin_id;
 	isize          overload_count;
-	Entity *       initial_overload_entity;
+	Entity **      overload_entities;
 } Operand;
 
 typedef struct TypeAndValue {
@@ -93,7 +93,7 @@ typedef struct Scope {
 	Scope *        first_child;
 	Scope *        last_child;
 	MapEntity      elements; // Key: String
-	MapEntity      implicit; // Key: String
+	MapBool        implicit; // Key: Entity *
 
 	Array(Scope *) shared;
 	Array(Scope *) imported;
@@ -344,7 +344,7 @@ Scope *make_scope(Scope *parent, gbAllocator allocator) {
 	Scope *s = gb_alloc_item(allocator, Scope);
 	s->parent = parent;
 	map_entity_init(&s->elements,   heap_allocator());
-	map_entity_init(&s->implicit,   heap_allocator());
+	map_bool_init(&s->implicit,   heap_allocator());
 	array_init(&s->shared,   heap_allocator());
 	array_init(&s->imported, heap_allocator());
 
@@ -371,7 +371,7 @@ void destroy_scope(Scope *scope) {
 	}
 
 	map_entity_destroy(&scope->elements);
-	map_entity_destroy(&scope->implicit);
+	map_bool_destroy(&scope->implicit);
 	array_free(&scope->shared);
 	array_free(&scope->imported);
 
@@ -540,6 +540,7 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
 	return NULL;
 }
 
+
 void check_scope_usage(Checker *c, Scope *scope) {
 	// TODO(bill): Use this?
 }
@@ -1601,8 +1602,7 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
 				// NOTE(bill): Do not add other imported entities
 				bool ok = add_entity(c, parent_scope, NULL, e);
 				if (ok && id->is_import) { // `#import`ed entities don't get exported
-					HashKey key = hash_string(e->token.string);
-					map_entity_set(&parent_scope->implicit, key, e);
+					map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
 				}
 			}
 		} else {

+ 3 - 2
src/entity.c

@@ -34,8 +34,9 @@ typedef enum EntityFlag {
 	EntityFlag_Anonymous  = 1<<2,
 	EntityFlag_Field      = 1<<3,
 	EntityFlag_Param      = 1<<4,
-	EntityFlag_VectorElem = 1<<5,
-	EntityFlag_NoAlias    = 1<<6,
+	EntityFlag_Ellipsis   = 1<<5,
+	EntityFlag_VectorElem = 1<<6,
+	EntityFlag_NoAlias    = 1<<7,
 } EntityFlag;
 
 typedef enum OverloadKind {

+ 164 - 74
src/parser.c

@@ -432,7 +432,10 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_CallExpr:
 		return ast_node_token(node->CallExpr.proc);
 	case AstNode_SelectorExpr:
-		return ast_node_token(node->SelectorExpr.selector);
+		if (node->SelectorExpr.selector != NULL) {
+			return ast_node_token(node->SelectorExpr.selector);
+		}
+		return node->SelectorExpr.token;
 	case AstNode_IndexExpr:
 		return node->IndexExpr.open;
 	case AstNode_SliceExpr:
@@ -1851,10 +1854,14 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
 			case Token_Ident:
 				operand = make_selector_expr(f, token, operand, parse_identifier(f));
 				break;
+			case Token_Integer:
+				operand = make_selector_expr(f, token, operand, parse_expr(f, lhs));
+				break;
 			default: {
 				syntax_error(f->curr_token, "Expected a selector");
 				next_token(f);
-				operand = make_selector_expr(f, f->curr_token, operand, NULL);
+				operand = make_bad_expr(f, ast_node_token(operand), f->curr_token);
+				// operand = make_selector_expr(f, f->curr_token, operand, NULL);
 			} break;
 			}
 		} break;
@@ -2046,7 +2053,7 @@ AstNodeArray parse_rhs_expr_list(AstFile *f) {
 	return parse_expr_list(f, false);
 }
 
-AstNodeArray parse_identifier_list(AstFile *f) {
+AstNodeArray parse_ident_list(AstFile *f) {
 	AstNodeArray list = make_ast_node_array(f);
 
 	do {
@@ -2227,106 +2234,189 @@ AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_)
 	return make_proc_type(f, proc_token, params, results, tags, cc);
 }
 
-AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
-                              TokenKind separator, TokenKind follow) {
-	AstNodeArray params = make_ast_node_array(f);
-	isize name_count = 0;
-
-	while (f->curr_token.kind != follow &&
-	       f->curr_token.kind != Token_EOF) {
-		i32 using_count    = 0;
-		i32 no_alias_count = 0;
-		while (f->curr_token.kind == Token_using ||
-		       f->curr_token.kind == Token_no_alias) {
-			if (allow_token(f, Token_using)) {
-				using_count++;
-			}
-			if (allow_token(f, Token_no_alias)) {
-				no_alias_count++;
-			}
+void parse_field_prefixes(AstFile *f, u32 flags, i32 *using_count, i32 *no_alias_count) {
+	while (f->curr_token.kind == Token_using ||
+	       f->curr_token.kind == Token_no_alias) {
+		if (allow_token(f, Token_using)) {
+			*using_count += 1;
+		}
+		if (allow_token(f, Token_no_alias)) {
+			*no_alias_count += 1;
 		}
+	}
+	if (*using_count > 1) {
+		syntax_error(f->curr_token, "Multiple `using` in this field list");
+		*using_count = 1;
+	}
+	if (*no_alias_count > 1) {
+		syntax_error(f->curr_token, "Multiple `no_alias` in this field list");
+		*no_alias_count = 1;
+	}
+}
 
+bool parse_expect_separator(AstFile *f, TokenKind separator, AstNode *param) {
+	if (separator == Token_Semicolon) {
+		expect_semicolon(f, param);
+	} else {
+		if (!allow_token(f, separator)) {
+			return true;
+		}
+	}
+	return false;
+}
 
-		AstNodeArray names = parse_identifier_list(f);
-		if (names.count == 0) {
-			syntax_error(f->curr_token, "Empty field declaration");
+AstNodeArray convert_to_ident_list(AstFile *f, AstNodeArray list) {
+	AstNodeArray idents = {0};
+	array_init_reserve(&idents, heap_allocator(), list.count);
+	// Convert to ident list
+	for_array(i, list) {
+		AstNode *ident = list.e[i];
+		switch (ident->kind) {
+		case AstNode_Ident:
+		case AstNode_BadExpr:
+			break;
+		default:
+			error_node(ident, "Expected an identifier");
+			ident = make_ident(f, blank_token);
 			break;
 		}
+		array_add(&idents, ident);
+	}
+	return idents;
+}
 
-		if (names.count > 1 && using_count > 0) {
-			syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
-			using_count = 0;
+AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) {
+	if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) {
+		Token tok = f->curr_token;
+		next_token(f);
+		AstNode *type = parse_identifier_or_type(f);
+		if (type == NULL) {
+			error(tok, "variadic field missing type after `...`");
+			type = make_bad_expr(f, tok, f->curr_token);
 		}
+		return make_ellipsis(f, tok, type);
+	}
+	AstNode *type = parse_type_attempt(f);
+	if (type == NULL) {
+		Token tok = f->curr_token;
+		error(tok, "Expected a type");
+		type = make_bad_expr(f, tok, f->curr_token);
+	}
+	return type;
+}
 
-		if ((flags&FieldFlag_using) == 0 && using_count > 0) {
-			syntax_error(f->curr_token, "`using` is not allowed within this field list");
-			using_count = 0;
-		}
-		if ((flags&FieldFlag_no_alias) == 0 && no_alias_count > 0) {
-			syntax_error(f->curr_token, "`no_alias` is not allowed within this field list");
-			no_alias_count = 0;
-		}
-		if (using_count > 1) {
-			syntax_error(f->curr_token, "Multiple `using` in this field list");
-			using_count = 1;
-		}
-		if (no_alias_count > 1) {
-			syntax_error(f->curr_token, "Multiple `no_alias` in this field list");
-			no_alias_count = 1;
+void check_field_prefixes(AstFile *f, AstNodeArray names, u32 flags, i32 *using_count, i32 *no_alias_count) {
+	if (names.count > 1 && *using_count > 0) {
+		syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
+		*using_count = 0;
+	}
+
+	if ((flags&FieldFlag_using) == 0 && *using_count > 0) {
+		syntax_error(f->curr_token, "`using` is not allowed within this field list");
+		*using_count = 0;
+	}
+	if ((flags&FieldFlag_no_alias) == 0 && *no_alias_count > 0) {
+		syntax_error(f->curr_token, "`no_alias` is not allowed within this field list");
+		*no_alias_count = 0;
+	}
+
+}
+
+u32 field_prefixes_to_flags(i32 using_count, i32 no_alias_count) {
+	u32 field_flags = 0;
+	if (using_count    > 0) field_flags |= FieldFlag_using;
+	if (no_alias_count > 0) field_flags |= FieldFlag_no_alias;
+	return field_flags;
+}
+
+AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
+                              TokenKind separator, TokenKind follow) {
+	AstNodeArray params = make_ast_node_array(f);
+	AstNodeArray list   = make_ast_node_array(f);
+	isize name_count    = 0;
+	bool allow_ellipsis = flags&FieldFlag_ellipsis;
+
+	// TODO(bill): Allow for just a list of types
+	i32 using_count    = 0;
+	i32 no_alias_count = 0;
+	parse_field_prefixes(f, flags, &using_count, &no_alias_count);
+	while (f->curr_token.kind != follow &&
+	       f->curr_token.kind != Token_Colon &&
+	       f->curr_token.kind != Token_EOF) {
+		AstNode *param = parse_var_type(f, allow_ellipsis);
+		array_add(&list, param);
+		if (f->curr_token.kind != Token_Comma) {
+			break;
 		}
+		next_token(f);
+	}
 
+	if (f->curr_token.kind == Token_Colon) {
+		AstNodeArray names = convert_to_ident_list(f, list); // Copy for semantic reasons
+		if (names.count == 0) {
+			syntax_error(f->curr_token, "Empty field declaration");
+		}
+		check_field_prefixes(f, names, flags, &using_count, &no_alias_count);
 
 		name_count += names.count;
 
 		expect_token_after(f, Token_Colon, "field list");
+		AstNode *type = parse_var_type(f, allow_ellipsis);
+		AstNode *param = make_field(f, names, type, field_prefixes_to_flags(using_count, no_alias_count));
+		array_add(&params, param);
 
-		AstNode *type = NULL;
-		if ((flags&FieldFlag_ellipsis) != 0 && f->curr_token.kind == Token_Ellipsis) {
-			Token ellipsis = f->curr_token;
-			next_token(f);
-			type = parse_type_attempt(f);
-			if (type == NULL) {
-				syntax_error(f->curr_token, "variadic field is missing a type after `..`");
-				type = make_bad_expr(f, ellipsis, f->curr_token);
-			} else {
-				if (names.count > 1) {
-					syntax_error(f->curr_token, "mutliple variadic fields, only  `..`");
-				} else {
-					type = make_ellipsis(f, ellipsis, type);
-				}
-			}
-		} else {
-			type = parse_type_attempt(f);
-		}
+		parse_expect_separator(f, separator, type);
 
+		while (f->curr_token.kind != follow &&
+		       f->curr_token.kind != Token_EOF) {
+			i32 using_count    = 0;
+			i32 no_alias_count = 0;
+			parse_field_prefixes(f, flags, &using_count, &no_alias_count);
 
-		if (type == NULL) {
-			syntax_error(f->curr_token, "Expected a type for this field declaration");
-		}
+			AstNodeArray names = parse_ident_list(f);
+			if (names.count == 0) {
+				syntax_error(f->curr_token, "Empty field declaration");
+				break;
+			}
+			check_field_prefixes(f, names, flags, &using_count, &no_alias_count);
+			name_count += names.count;
 
-		u32 flags = 0;
-		if (using_count    > 0) flags |= FieldFlag_using;
-		if (no_alias_count > 0) flags |= FieldFlag_no_alias;
-		AstNode *param = make_field(f, names, type, flags);
-		array_add(&params, param);
+			expect_token_after(f, Token_Colon, "field list");
+			AstNode *type = parse_var_type(f, allow_ellipsis);
 
-		if (separator == Token_Semicolon) {
-			expect_semicolon(f, param);
-		} else {
-			if (!allow_token(f, separator)) {
+			AstNode *param = make_field(f, names, type, field_prefixes_to_flags(using_count, no_alias_count));
+			array_add(&params, param);
+
+			if (parse_expect_separator(f, separator, param)) {
 				break;
 			}
 		}
+
+		if (name_count_) *name_count_ = name_count;
+		return params;
 	}
 
-	if (name_count_) *name_count_ = name_count;
+	check_field_prefixes(f, list, flags, &using_count, &no_alias_count);
+	for_array(i, list) {
+		AstNodeArray names = {0};
+		AstNode *type = list.e[i];
+		Token token = blank_token;
 
+		array_init_count(&names, heap_allocator(), 1);
+		token.pos = ast_node_token(type).pos;
+		names.e[0] = make_ident(f, token);
+
+		AstNode *param = make_field(f, names, list.e[i], field_prefixes_to_flags(using_count, no_alias_count));
+		array_add(&params, param);
+	}
+
+	if (name_count_) *name_count_ = name_count;
 	return params;
 }
 
 
 AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
-	return parse_field_list(f, field_count_, flags, Token_Semicolon, Token_CloseBrace);
+	return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
 }
 
 AstNode *parse_identifier_or_type(AstFile *f) {
@@ -2753,7 +2843,7 @@ AstNode *parse_for_stmt(AstFile *f) {
 	}
 
 	Token token = expect_token(f, Token_for);
-	AstNodeArray names = parse_identifier_list(f);
+	AstNodeArray names = parse_ident_list(f);
 	parse_check_name_list_for_reserves(f, names);
 	Token colon = expect_token_after(f, Token_Colon, "for name list");
 

+ 3 - 3
src/tokenizer.c

@@ -529,7 +529,7 @@ fraction:
 		// HACK(bill): This may be inefficient
 		TokenizerState state = save_tokenizer_state(t);
 		advance_to_next_rune(t);
-		if (t->curr_rune == '.') {
+		if (digit_value(t->curr_rune) >= 10) {
 			// TODO(bill): Clean up this shit
 			restore_tokenizer_state(t, &state);
 			goto end;
@@ -837,9 +837,9 @@ Token tokenizer_get_token(Tokenizer *t) {
 
 		case '.':
 			token.kind = Token_Period; // Default
-			if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number
+			/* if (gb_is_between(t->curr_rune, '0', '9')) { // Might be a number
 				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);
 				if (t->curr_rune == '.') {
 					advance_to_next_rune(t);

+ 10 - 2
src/types.c

@@ -1759,9 +1759,17 @@ gbString write_type_to_string(gbString str, Type *type) {
 				Entity *var = type->Tuple.variables[i];
 				if (var != NULL) {
 					GB_ASSERT(var->kind == Entity_Variable);
-					if (i > 0)
+					if (i > 0) {
 						str = gb_string_appendc(str, ", ");
-					str = write_type_to_string(str, var->type);
+					}
+					if (var->flags&EntityFlag_Ellipsis) {
+						Type *slice = base_type(var->type);
+						str = gb_string_appendc(str, "...");
+						GB_ASSERT(is_type_slice(var->type));
+						str = write_type_to_string(str, slice->Slice.elem);
+					} else {
+						str = write_type_to_string(str, var->type);
+					}
 				}
 			}
 		}