Ver Fonte

`in` keyword for `for` and `match type`

Ginger Bill há 8 anos atrás
pai
commit
832009f33a
10 ficheiros alterados com 98 adições e 94 exclusões
  1. 24 20
      code/demo.odin
  2. 1 1
      core/_preload.odin
  3. 45 45
      core/fmt.odin
  4. 7 7
      core/hash.odin
  5. 4 4
      core/math.odin
  6. 4 4
      core/mem.odin
  7. 1 0
      src/check_decl.c
  8. 5 3
      src/check_expr.c
  9. 2 2
      src/parser.c
  10. 5 8
      src/tokenizer.c

+ 24 - 20
code/demo.odin

@@ -1,5 +1,12 @@
 #import "fmt.odin";
 #import "utf8.odin";
+#import "atomic.odin";
+#import "hash.odin";
+#import "math.odin";
+#import "mem.odin";
+#import "opengl.odin";
+#import "os.odin";
+#import "sync.odin";
 
 main :: proc() {
 	syntax();
@@ -120,7 +127,6 @@ when_statements :: proc() {
 	foreign_procedures();
 }
 
-#import "atomic.odin" when ODIN_OS == "windows";
 #foreign_system_library win32_user "user32.lib" when ODIN_OS == "windows";
 // NOTE: This is done on purpose for two reasons:
 // * Makes it clear where the platform specific stuff is
@@ -132,6 +138,8 @@ foreign_procedures :: proc() {
 	// NOTE: If that library doesn't get used, it doesn't get linked with
 	// NOTE: There is not link checking yet to see if that procedure does come from that library
 
+	// See sys/windows.odin for more examples
+
 	special_expressions();
 }
 
@@ -148,8 +156,7 @@ special_expressions :: proc() {
 		give x;
 	} else {
 		// TODO: Type cohesion is not yet finished
-		// E.g. this constant "number" should be able to be cast to a `f32` automatically
-		give cast(f32)123;
+		give 123;
 	}; // semicolon is required as it's an expression
 
 
@@ -176,24 +183,24 @@ loops :: proc() {
 	for i := 0; i < 123; i += 1 {
 	}
 */
-	for i : 0..<123 {
+	for i in 0..<123 {
 	}
 
-	for i : 0...122 {
+	for i in 0..122 {
 	}
 
-	for val, idx : 12..<16 {
+	for val, idx in 12..<16 {
 		fmt.println(val, idx);
 	}
 
-	primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
+	primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19};
 
-	for p : primes {
+	for p in primes {
 		fmt.println(p);
 	}
 
 	// Pointers to arrays, slices, or strings are allowed
-	for _ : ^primes {
+	for _ in ^primes {
 		// ignore the value and just iterate across it
 	}
 
@@ -201,7 +208,7 @@ loops :: proc() {
 
 	name := "你好,世界";
 	fmt.println(name);
-	for r : name {
+	for r in name {
 		compile_assert(type_of_val(r) == rune);
 		fmt.printf("%r\n", r);
 	}
@@ -210,14 +217,12 @@ loops :: proc() {
 		while i := 0; i < name.count {
 			r, size := utf8.decode_rune(name[i:]);
 			i += size;
-			fmt.printf("%c\n", r);
+			fmt.printf("%r\n", r);
 		}
 	}
 
 
 
-
-
 	// Emulate a C-style loop (not exactly the same though)
 	while x := 0; x < 10 {
 		defer x += 2;
@@ -250,10 +255,8 @@ procedure_overloading :: proc() {
 
 	foo();
 	foo(THINGF);
-	// foo(THINGI);
+	// foo(THINGI); // 14451 is just a number so it could go to either procedures
 	foo(cast(int)THINGI);
-	fmt.println(THINGF);
-	fmt.println(THINGI);
 
 
 
@@ -273,11 +276,12 @@ procedure_overloading :: proc() {
 	fmt.println(foo(^a));
 	foo(^b);
 	foo(c);
-	// foo(nil);
-	atomic.store(^a, 1);
-
+	// foo(nil); // nil could go to numerous types thus the ambiguity
 
 	f: proc();
-	f = foo;
+	f = foo; // The correct `foo` to chosen
 	f();
+
+
+	// See math.odin and atomic.odin for more examples
 }

+ 1 - 1
core/_preload.odin

@@ -100,7 +100,7 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
 		return nil;
 	}
 	base := info;
-	match type i : base {
+	match type i in base {
 	case Type_Info.Named:
 		base = i.base;
 	}

+ 45 - 45
core/fmt.odin

@@ -58,38 +58,38 @@ Fmt_Info :: struct {
 
 
 
-fprint :: proc(fd: os.Handle, args: ...any) -> int {
+fprint :: proc(fd: os.Handle, args: ..any) -> int {
 	data: [DEFAULT_BUFFER_SIZE]byte;
 	buf := Buffer{data[:], 0};
-	bprint(^buf, ...args);
+	bprint(^buf, ..args);
 	os.write(fd, buf.data[:buf.length]);
 	return buf.length;
 }
 
-fprintln :: proc(fd: os.Handle, args: ...any) -> int {
+fprintln :: proc(fd: os.Handle, args: ..any) -> int {
 	data: [DEFAULT_BUFFER_SIZE]byte;
 	buf := Buffer{data[:], 0};
-	bprintln(^buf, ...args);
+	bprintln(^buf, ..args);
 	os.write(fd, buf.data[:buf.length]);
 	return buf.length;
 }
-fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int {
+fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
 	data: [DEFAULT_BUFFER_SIZE]byte;
 	buf := Buffer{data[:], 0};
-	bprintf(^buf, fmt, ...args);
+	bprintf(^buf, fmt, ..args);
 	os.write(fd, buf.data[:buf.length]);
 	return buf.length;
 }
 
 
-print :: proc(args: ...any) -> int {
-	return fprint(os.stdout, ...args);
+print :: proc(args: ..any) -> int {
+	return fprint(os.stdout, ..args);
 }
-println :: proc(args: ...any) -> int {
-	return fprintln(os.stdout, ...args);
+println :: proc(args: ..any) -> int {
+	return fprintln(os.stdout, ..args);
 }
-printf :: proc(fmt: string, args: ...any) -> int {
-	return fprintf(os.stdout, fmt, ...args);
+printf :: proc(fmt: string, args: ..any) -> int {
+	return fprintf(os.stdout, fmt, ..args);
 }
 
 
@@ -107,7 +107,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 	}
 
 	using Type_Info;
-	match type info : ti {
+	match type info in ti {
 	case Named:
 		buffer_write_string(buf, info.name);
 	case Integer:
@@ -154,7 +154,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 	case Tuple:
 		count := info.fields.count;
 		if count != 1 { buffer_write_string(buf, "("); }
-		for i : 0..<count {
+		for i in 0..<count {
 			if i > 0 { buffer_write_string(buf, ", "); }
 
 			f := info.fields[i];
@@ -189,7 +189,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 		if info.packed  { buffer_write_string(buf, "#packed "); }
 		if info.ordered { buffer_write_string(buf, "#ordered "); }
 		buffer_write_string(buf, "{");
-		for field, i : info.fields {
+		for field, i in info.fields {
 			buffer_write_string(buf, field.name);
 			buffer_write_string(buf, ": ");
 			buffer_write_type(buf, field.type_info);
@@ -199,7 +199,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 
 	case Union:
 		buffer_write_string(buf, "union {");
-		for field, i : info.fields {
+		for field, i in info.fields {
 			buffer_write_string(buf, field.name);
 			buffer_write_string(buf, ": ");
 			buffer_write_type(buf, field.type_info);
@@ -209,7 +209,7 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 
 	case Raw_Union:
 		buffer_write_string(buf, "raw_union {");
-		for field, i : info.fields {
+		for field, i in info.fields {
 			buffer_write_string(buf, field.name);
 			buffer_write_string(buf, ": ");
 			buffer_write_type(buf, field.type_info);
@@ -225,12 +225,12 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
 }
 
 
-bprint :: proc(buf: ^Buffer, args: ...any) -> int {
+bprint :: proc(buf: ^Buffer, args: ..any) -> int {
 	fi: Fmt_Info;
 	fi.buf = buf;
 
 	prev_string := false;
-	for arg, i : args {
+	for arg, i in args {
 		is_string := arg.data != nil && is_type_string(arg.type_info);
 		if i > 0 && !is_string && !prev_string {
 			buffer_write_byte(buf, ' ');
@@ -241,11 +241,11 @@ bprint :: proc(buf: ^Buffer, args: ...any) -> int {
 	return buf.length;
 }
 
-bprintln :: proc(buf: ^Buffer, args: ...any) -> int {
+bprintln :: proc(buf: ^Buffer, args: ..any) -> int {
 	fi: Fmt_Info;
 	fi.buf = buf;
 
-	for arg, i : args {
+	for arg, i in args {
 		if i > 0 {
 			buffer_write_byte(buf, ' ');
 		}
@@ -262,7 +262,7 @@ is_type_string :: proc(info: ^Type_Info) -> bool {
 		return false;
 	}
 
-	match type i : type_info_base(info) {
+	match type i in type_info_base(info) {
 	case String:
 		return true;
 	}
@@ -274,7 +274,7 @@ is_type_integer :: proc(info: ^Type_Info) -> bool {
 		return false;
 	}
 
-	match type i : type_info_base(info) {
+	match type i in type_info_base(info) {
 	case Integer:
 		return true;
 	}
@@ -286,7 +286,7 @@ is_type_float :: proc(info: ^Type_Info) -> bool {
 		return false;
 	}
 
-	match type i : type_info_base(info) {
+	match type i in type_info_base(info) {
 	case Float:
 		return true;
 	}
@@ -305,7 +305,7 @@ parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
 	ok := true;
 
 	i := 0;
-	for o : offset..<s.count {
+	for o in offset..<s.count {
 		c := cast(rune)s[offset+i];
 		if !is_digit(c) {
 			break;
@@ -325,7 +325,7 @@ arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset: int, a
 			return 0, 1, false;
 		}
 
-		for i : 1..<format.count {
+		for i in 1..<format.count {
 			if format[i] == ']' {
 				width, new_index, ok := parse_int(format, 1);
 				if !ok || new_index != i {
@@ -358,7 +358,7 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) {
 	if arg_index < args.count {
 		arg := args[arg_index];
 		arg.type_info = type_info_base(arg.type_info);
-		match type i : arg {
+		match type i in arg {
 		case int:  num = i;
 		case i8:   num = cast(int)i;
 		case i16:  num = cast(int)i;
@@ -413,7 +413,7 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
 
 	count := min(width, fi.buf.data.count-fi.buf.length);
 	start := fi.buf.length;
-	for i : start..<count {
+	for i in start..<count {
 		fi.buf.data[i] = pad_byte;
 	}
 	fi.buf.length += count;
@@ -581,7 +581,7 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
 				arg := v - cast(f64)val;
 				mult: f64 = 10;
 				buffer_write_byte(fi.buf, '.');
-				for _ : 0..<prec {
+				for _ in 0..<prec {
 					val := cast(u64)(arg*mult);
 					buffer_write_byte(fi.buf, __DIGITS_LOWER[cast(u64)val]);
 					arg -= cast(f64)val / mult;
@@ -638,7 +638,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 	}
 
 	using Type_Info;
-	match type e : v.type_info {
+	match type e in v.type_info {
 	default:
 		fmt_bad_verb(fi, verb);
 		return;
@@ -651,7 +651,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			f: f64;
 			ok := false;
 			a := any{type_info_base(e.base), v.data};
-			match type v : a {
+			match type v in a {
 			case i8:   i = cast(i64)v;
 			case i16:  i = cast(i64)v;
 			case i32:  i = cast(i64)v;
@@ -667,7 +667,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			}
 
 			if is_type_integer(e.base) {
-				for it, idx : e.values {
+				for it, idx in e.values {
 					if it.i == i {
 						buffer_write_string(fi.buf, e.names[idx]);
 						ok = true;
@@ -675,7 +675,7 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 					}
 				}
 			} else {
-				for it, idx : e.values {
+				for it, idx in e.values {
 					if it.f == f {
 						buffer_write_string(fi.buf, e.names[idx]);
 						ok = true;
@@ -702,9 +702,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 	}
 
 	using Type_Info;
-	match type info : v.type_info {
+	match type info in v.type_info {
 	case Named:
-		match type b : info.base {
+		match type b in info.base {
 		case Struct:
 			if verb != 'v' {
 				fmt_bad_verb(fi, verb);
@@ -712,7 +712,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			}
 			buffer_write_string(fi.buf, info.name);
 			buffer_write_byte(fi.buf, '{');
-			for f, i : b.fields {
+			for f, i in b.fields {
 				if i > 0 {
 					buffer_write_string(fi.buf, ", ");
 				}
@@ -757,7 +757,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 
 		buffer_write_byte(fi.buf, '[');
 		defer buffer_write_byte(fi.buf, ']');
-		for i : 0..<info.count {
+		for i in 0..<info.count {
 			if i > 0 {
 				buffer_write_string(fi.buf, ", ");
 			}
@@ -774,7 +774,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 		buffer_write_byte(fi.buf, '[');
 		defer buffer_write_byte(fi.buf, ']');
 		slice := cast(^[]byte)v.data;
-		for i : 0..<slice.count {
+		for i in 0..<slice.count {
 			if i > 0 {
 				buffer_write_string(fi.buf, ", ");
 			}
@@ -784,7 +784,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 
 	case Vector:
 		is_bool :: proc(type_info: ^Type_Info) -> bool {
-			match type info : type_info {
+			match type info in type_info {
 			case Named:
 				return is_bool(info.base);
 			case Boolean:
@@ -800,7 +800,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			return;
 		}
 
-		for i : 0..<info.count {
+		for i in 0..<info.count {
 			if i > 0 {
 				buffer_write_string(fi.buf, ", ");
 			}
@@ -813,7 +813,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 		buffer_write_byte(fi.buf, '{');
 		defer buffer_write_byte(fi.buf, '}');
 
-		for f, i : info.fields {
+		for f, i in info.fields {
 			if i > 0 {
 				buffer_write_string(fi.buf, ", ");
 			}
@@ -848,7 +848,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
 
 	if verb == 'T' {
 		ti := arg.type_info;
-		match type a : arg {
+		match type a in arg {
 		case ^Type_Info: ti = a;
 		}
 		buffer_write_type(fi.buf, ti);
@@ -858,7 +858,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
 
 	base_arg := arg;
 	base_arg.type_info = type_info_base(base_arg.type_info);
-	match type a : base_arg {
+	match type a in base_arg {
 	case bool:    fmt_bool(fi, a, verb);
 	case f32:     fmt_float(fi, cast(f64)a, 32, verb);
 	case f64:     fmt_float(fi, a, 64, verb);
@@ -880,7 +880,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
 }
 
 
-bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
+bprintf :: proc(b: ^Buffer, fmt: string, args: ..any) -> int {
 	fi := Fmt_Info{};
 	end := fmt.count;
 	arg_index := 0;
@@ -1004,7 +1004,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
 
 	if !fi.reordered && arg_index < args.count {
 		buffer_write_string(b, "%!(EXTRA ");
-		for arg, index : args[arg_index:] {
+		for arg, index in args[arg_index:] {
 			if index > 0 {
 				buffer_write_string(b, ", ");
 			}

+ 7 - 7
core/hash.odin

@@ -1,7 +1,7 @@
 crc32 :: proc(data: rawptr, len: int) -> u32 {
 	result := ~cast(u32)0;
 	s := slice_ptr(cast(^u8)data, len);
-	for i : 0..<len {
+	for i in 0..<len {
 		b := cast(u32)s[i];
 		result = result>>8 ~ __CRC32_TABLE[(result ~ b) & 0xff];
 	}
@@ -10,7 +10,7 @@ crc32 :: proc(data: rawptr, len: int) -> u32 {
 crc64 :: proc(data: rawptr, len: int) -> u64 {
 	result := ~cast(u64)0;
 	s := slice_ptr(cast(^u8)data, len);
-	for i : 0..<len {
+	for i in 0..<len {
 		b := cast(u64)s[i];
 		result = result>>8 ~ __CRC64_TABLE[(result ~ b) & 0xff];
 	}
@@ -21,7 +21,7 @@ fnv32 :: proc(data: rawptr, len: int) -> u32 {
 	s := slice_ptr(cast(^u8)data, len);
 
 	h: u32 = 0x811c9dc5;
-	for i : 0..<len {
+	for i in 0..<len {
 		h = (h * 0x01000193) ~ cast(u32)s[i];
 	}
 	return h;
@@ -31,7 +31,7 @@ fnv64 :: proc(data: rawptr, len: int) -> u64 {
 	s := slice_ptr(cast(^u8)data, len);
 
 	h: u64 = 0xcbf29ce484222325;
-	for i : 0..<len {
+	for i in 0..<len {
 		h = (h * 0x100000001b3) ~ cast(u64)s[i];
 	}
 	return h;
@@ -41,7 +41,7 @@ fnv32a :: proc(data: rawptr, len: int) -> u32 {
 	s := slice_ptr(cast(^u8)data, len);
 
 	h: u32 = 0x811c9dc5;
-	for i : 0..<len {
+	for i in 0..<len {
 		h = (h ~ cast(u32)s[i]) * 0x01000193;
 	}
 	return h;
@@ -51,7 +51,7 @@ fnv64a :: proc(data: rawptr, len: int) -> u64 {
 	s := slice_ptr(cast(^u8)data, len);
 
 	h :u64 = 0xcbf29ce484222325;
-	for i : 0..<len {
+	for i in 0..<len {
 		h = (h ~ cast(u64)s[i]) * 0x100000001b3;
 	}
 	return h;
@@ -70,7 +70,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
 		data := slice_ptr(cast(^u64)data_, len/size_of(u64));
 		data2 := slice_ptr(cast(^u8)data_, len);
 
-		for i : 0 ..< data.count {
+		for i in 0 ..< data.count {
 			k := data[i];
 
 			k *= m;

+ 4 - 4
core/math.odin

@@ -155,8 +155,8 @@ mat4_identity :: proc() -> Mat4 {
 }
 
 mat4_transpose :: proc(m: Mat4) -> Mat4 {
-	for j : 0..<4 {
-		for i : 0..<4 {
+	for j in 0..<4 {
+		for i in 0..<4 {
 			m[i][j], m[j][i] = m[j][i], m[i][j];
 		}
 	}
@@ -165,8 +165,8 @@ mat4_transpose :: proc(m: Mat4) -> Mat4 {
 
 mul :: proc(a, b: Mat4) -> Mat4 {
 	c: Mat4;
-	for j : 0..<4 {
-		for i : 0..<4 {
+	for j in 0..<4 {
+		for i in 0..<4 {
 			c[j][i] = a[0][i]*b[j][0] +
 			          a[1][i]*b[j][1] +
 			          a[2][i]*b[j][2] +

+ 4 - 4
core/mem.odin

@@ -28,7 +28,7 @@ copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "_
 compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
 	a := slice_ptr(cast(^byte)dst, n);
 	b := slice_ptr(cast(^byte)src, n);
-	for i : 0..<n {
+	for i in 0..<n {
 		match {
 		case a[i] < b[i]:
 			return -1;
@@ -212,7 +212,7 @@ align_of_type_info :: proc(type_info: ^Type_Info) -> int {
 	MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants?
 	using Type_Info;
 
-	match type info : type_info {
+	match type info in type_info {
 	case Named:
 		return align_of_type_info(info.base);
 	case Integer:
@@ -257,7 +257,7 @@ align_formula :: proc(size, align: int) -> int {
 size_of_type_info :: proc(type_info: ^Type_Info) -> int {
 	WORD_SIZE :: size_of(int);
 	using Type_Info;
-	match type info : type_info {
+	match type info in type_info {
 	case Named:
 		return size_of_type_info(info.base);
 	case Integer:
@@ -289,7 +289,7 @@ size_of_type_info :: proc(type_info: ^Type_Info) -> int {
 		return 3*WORD_SIZE;
 	case Vector:
 		is_bool :: proc(type_info: ^Type_Info) -> bool {
-			match type info : type_info {
+			match type info in type_info {
 			case Named:
 				return is_bool(info.base);
 			case Boolean:

+ 1 - 0
src/check_decl.c

@@ -64,6 +64,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
 	Array(Operand) operands;
 	array_init_reserve(&operands, c->tmp_allocator, 2*lhs_count);
 
+	// TODO(bill): Allow for type hints from the entities
 	for_array(i, inits) {
 		AstNode *rhs = inits.e[i];
 		Operand o = {0};

+ 5 - 3
src/check_expr.c

@@ -4071,19 +4071,21 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
 			error_node(ie->cond, "Non-boolean condition in if expression");
 		}
 
-
 		Operand x = {Addressing_Invalid};
 		Operand y = {Addressing_Invalid};
 		Type *if_type = NULL;
 		Type *else_type = NULL;
-		check_expr(c, &x, ie->body);
+		if (type_hint) {
+			gb_printf_err("here\n");
+		}
+		check_expr_with_type_hint(c, &x, ie->body, type_hint);
 		if_type = x.type;
 
 		if (ie->else_expr != NULL) {
 			switch (ie->else_expr->kind) {
 			case AstNode_IfExpr:
 			case AstNode_BlockExpr:
-				check_expr(c, &y, ie->else_expr);
+				check_expr_with_type_hint(c, &y, ie->else_expr, if_type);
 				else_type = y.type;
 				break;
 			default:

+ 2 - 2
src/parser.c

@@ -2944,7 +2944,7 @@ AstNode *parse_for_stmt(AstFile *f) {
 	Token token = expect_token(f, Token_for);
 	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");
+	Token colon = expect_token_after(f, Token_in, "for name list");
 
 	isize prev_level = f->expr_level;
 	f->expr_level = -1;
@@ -3029,7 +3029,7 @@ AstNode *parse_match_stmt(AstFile *f) {
 		f->expr_level = -1;
 
 		AstNode *var = parse_identifier(f);
-		expect_token(f, Token_Colon);
+		expect_token_after(f, Token_in, "match type name");
 		tag = parse_simple_stmt(f);
 
 		f->expr_level = prev_level;

+ 5 - 8
src/tokenizer.c

@@ -75,7 +75,7 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
 	TOKEN_KIND(Token_Semicolon,     ";"), \
 	TOKEN_KIND(Token_Period,        "."), \
 	TOKEN_KIND(Token_Comma,         ","), \
-	TOKEN_KIND(Token_Ellipsis,      "..."), \
+	TOKEN_KIND(Token_Ellipsis,      ".."), \
 	TOKEN_KIND(Token_HalfOpenRange, "..<"), \
 TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
 \
@@ -94,6 +94,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_else,           "else"), \
 	TOKEN_KIND(Token_while,          "while"), \
 	TOKEN_KIND(Token_for,            "for"), \
+	TOKEN_KIND(Token_in,             "in"), \
 	TOKEN_KIND(Token_when,           "when"), \
 	TOKEN_KIND(Token_range,          "range"), \
 	TOKEN_KIND(Token_defer,          "defer"), \
@@ -845,14 +846,10 @@ 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
-				token = scan_number_to_token(t, true);
-			} else */ if (t->curr_rune == '.') { // Could be an ellipsis
+			if (t->curr_rune == '.') { // Could be an ellipsis
 				advance_to_next_rune(t);
-				if (t->curr_rune == '.') {
-					advance_to_next_rune(t);
-					token.kind = Token_Ellipsis;
-				} else if (t->curr_rune == '<') {
+				token.kind = Token_Ellipsis;
+				if (t->curr_rune == '<') {
 					advance_to_next_rune(t);
 					token.kind = Token_HalfOpenRange;
 				}