فهرست منبع

Remove while loop and readd c-style for loops i.e. all loops are just `for`

Ginger Bill 8 سال پیش
والد
کامیت
92453369c5
11فایلهای تغییر یافته به همراه189 افزوده شده و 127 حذف شده
  1. 15 26
      code/demo.odin
  2. 2 2
      core/atomic.odin
  3. 6 7
      core/fmt.odin
  4. 1 1
      core/hash.odin
  5. 2 3
      core/mem.odin
  6. 1 1
      core/os_windows.odin
  7. 3 4
      core/utf8.odin
  8. 21 15
      src/check_stmt.c
  9. 27 17
      src/ir.c
  10. 111 50
      src/parser.c
  11. 0 1
      src/tokenizer.c

+ 15 - 26
code/demo.odin

@@ -168,25 +168,25 @@ special_expressions :: proc() {
 
 
 loops :: proc() {
 loops :: proc() {
 
 
-	// while loops
-	while true {
+	// The C-style for loop
+	for i := 0; i < 123; i += 1 {
 		break;
 		break;
 	}
 	}
-	while x := 123; x < 124 {
-		x += 2;
+	for i := 0; i < 123; {
+		break;
+	}
+	for false {
+		break;
+	}
+	for {
+		break;
 	}
 	}
 
 
 
 
-/*
-	This only C-style for loop has now been removed
-
-	for i := 0; i < 123; i += 1 {
-	}
-*/
-	for i in 0..<123 {
+	for i in 0..<123 { // 123 exclusive
 	}
 	}
 
 
-	for i in 0..122 {
+	for i in 0..122 { // 122 inclusive
 	}
 	}
 
 
 	for val, idx in 12..<16 {
 	for val, idx in 12..<16 {
@@ -214,26 +214,15 @@ loops :: proc() {
 	}
 	}
 
 
 	when false {
 	when false {
-		while i := 0; i < name.count {
-			r, size := utf8.decode_rune(name[i:]);
-			i += size;
+		for i, size := 0; i < name.count; i += size {
+			r: rune;
+			r, size = utf8.decode_rune(name[i:]);
 			fmt.printf("%r\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;
-
-		/* rest of the code */
-		// If `break` is used, the `defer` is still called so it's not the same
-		// as a C-style for loop
-	}
-
-
-
 	procedure_overloading();
 	procedure_overloading();
 }
 }
 
 

+ 2 - 2
core/atomic.odin

@@ -36,7 +36,7 @@ fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
 spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
 spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
 	old_value := compare_exchange(a, 1, 0);
 	old_value := compare_exchange(a, 1, 0);
 	counter := 0;
 	counter := 0;
-	while old_value != 0 && (time_out < 0 || counter < time_out) {
+	for old_value != 0 && (time_out < 0 || counter < time_out) {
 		counter += 1;
 		counter += 1;
 		yield_thread();
 		yield_thread();
 		old_value = compare_exchange(a, 1, 0);
 		old_value = compare_exchange(a, 1, 0);
@@ -80,7 +80,7 @@ fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
 spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
 spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
 	old_value := compare_exchange(a, 1, 0);
 	old_value := compare_exchange(a, 1, 0);
 	counter := 0;
 	counter := 0;
-	while old_value != 0 && (time_out < 0 || counter < time_out) {
+	for old_value != 0 && (time_out < 0 || counter < time_out) {
 		counter += 1;
 		counter += 1;
 		yield_thread();
 		yield_thread();
 		old_value = compare_exchange(a, 1, 0);
 		old_value = compare_exchange(a, 1, 0);

+ 6 - 7
core/fmt.odin

@@ -460,7 +460,7 @@ fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: stri
 		panic("fmt_integer: unknown base, whoops");
 		panic("fmt_integer: unknown base, whoops");
 	}
 	}
 
 
-	while b := cast(u64)base; u >= b {
+	for b := cast(u64)base; u >= b;  {
 		i -= 1;
 		i -= 1;
 		next := u / b;
 		next := u / b;
 		buf[i] = digits[u%b];
 		buf[i] = digits[u%b];
@@ -468,7 +468,7 @@ fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: stri
 	}
 	}
 	i -= 1;
 	i -= 1;
 	buf[i] = digits[u];
 	buf[i] = digits[u];
-	while i > 0 && prec > buf.count-i {
+	for i > 0 && prec > buf.count-i {
 		i -= 1;
 		i -= 1;
 		buf[i] = '0';
 		buf[i] = '0';
 	}
 	}
@@ -598,7 +598,7 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
 			case fi.space: fill = ' ';
 			case fi.space: fill = ' ';
 			}
 			}
 
 
-			while width > 0 {
+			for width > 0 {
 				width -= 1;
 				width -= 1;
 				buffer_write_byte(fi.buf, fill);
 				buffer_write_byte(fi.buf, fill);
 			}
 			}
@@ -885,11 +885,11 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ..any) -> int {
 	end := fmt.count;
 	end := fmt.count;
 	arg_index := 0;
 	arg_index := 0;
 	was_prev_index := false;
 	was_prev_index := false;
-	while i := 0; i < end {
+	for i := 0; i < end;  {
 		fi = Fmt_Info{buf = b, good_arg_index = true};
 		fi = Fmt_Info{buf = b, good_arg_index = true};
 
 
 		prev_i := i;
 		prev_i := i;
-		while i < end && fmt[i] != '%' {
+		for i < end && fmt[i] != '%' {
 			i += 1;
 			i += 1;
 		}
 		}
 		if i > prev_i {
 		if i > prev_i {
@@ -903,7 +903,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ..any) -> int {
 		i += 1;
 		i += 1;
 
 
 
 
-		while i < end {
+		for ; i < end; i += 1 {
 			skip_loop := false;
 			skip_loop := false;
 			c := fmt[i];
 			c := fmt[i];
 			match c {
 			match c {
@@ -925,7 +925,6 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ..any) -> int {
 			if skip_loop {
 			if skip_loop {
 				break;
 				break;
 			}
 			}
-			i += 1;
 		}
 		}
 
 
 		arg_index, i, was_prev_index = arg_number(^fi, arg_index, fmt, i, args.count);
 		arg_index, i, was_prev_index = arg_number(^fi, arg_index, fmt, i, args.count);

+ 1 - 1
core/hash.odin

@@ -108,7 +108,7 @@ murmur64 :: proc(data_: rawptr, len: int) -> u64 {
 		data := slice_ptr(cast(^u32)data_, len/size_of(u32));
 		data := slice_ptr(cast(^u32)data_, len/size_of(u32));
 
 
 		i := 0;
 		i := 0;
-		while len >= 8 {
+		for len >= 8 {
 			k1, k2: u32;
 			k1, k2: u32;
 			k1 = data[i]; i += 1;
 			k1 = data[i]; i += 1;
 			k1 *= m;
 			k1 *= m;

+ 2 - 3
core/mem.odin

@@ -75,14 +75,13 @@ allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: i
 	header.size = size;
 	header.size = size;
 	ptr := cast(^int)(header+1);
 	ptr := cast(^int)(header+1);
 
 
-	while i := 0; cast(rawptr)ptr < data {
+	for i := 0; cast(rawptr)ptr < data; i += 1 {
 		(ptr+i)^ = -1;
 		(ptr+i)^ = -1;
-		i += 1;
 	}
 	}
 }
 }
 allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
 allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
 	p := cast(^int)data;
 	p := cast(^int)data;
-	while (p-1)^ == -1 {
+	for (p-1)^ == -1 {
 		p = (p-1);
 		p = (p-1);
 	}
 	}
 	return cast(^Allocation_Header)p-1;
 	return cast(^Allocation_Header)p-1;

+ 1 - 1
core/os_windows.odin

@@ -223,7 +223,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
 	single_read_length: i32;
 	single_read_length: i32;
 	total_read: i64;
 	total_read: i64;
 
 
-	while total_read < length {
+	for total_read < length {
 		remaining := length - total_read;
 		remaining := length - total_read;
 		to_read: u32;
 		to_read: u32;
 		MAX :: 1<<32-1;
 		MAX :: 1<<32-1;

+ 3 - 4
core/utf8.odin

@@ -143,8 +143,7 @@ valid_rune :: proc(r: rune) -> bool {
 
 
 valid_string :: proc(s: string) -> bool {
 valid_string :: proc(s: string) -> bool {
 	n := s.count;
 	n := s.count;
-	i := 0;
-	while i < n {
+	for i := 0; i < n; {
 		si := s[i];
 		si := s[i];
 		if si < RUNE_SELF { // ascii
 		if si < RUNE_SELF { // ascii
 			i += 1;
 			i += 1;
@@ -178,8 +177,8 @@ valid_string :: proc(s: string) -> bool {
 rune_count :: proc(s: string) -> int {
 rune_count :: proc(s: string) -> int {
 	count := 0;
 	count := 0;
 	n := s.count;
 	n := s.count;
-	i := 0;
-	while i < n {
+
+	for i := 0; i < n; {
 		defer count += 1;
 		defer count += 1;
 		si := s[i];
 		si := s[i];
 		if si < RUNE_SELF { // ascii
 		if si < RUNE_SELF { // ascii

+ 21 - 15
src/check_stmt.c

@@ -127,13 +127,13 @@ bool check_is_terminating(AstNode *node) {
 		}
 		}
 	case_end;
 	case_end;
 
 
-	case_ast_node(ws, WhileStmt, node);
-		if (ws->cond != NULL && !check_has_break(ws->body, true)) {
-			return check_is_terminating(ws->body);
+	case_ast_node(fs, ForStmt, node);
+		if (!check_has_break(fs->body, true)) {
+			return check_is_terminating(fs->body);
 		}
 		}
 	case_end;
 	case_end;
 
 
-	case_ast_node(rs, ForStmt, node);
+	case_ast_node(rs, RangeStmt, node);
 		if (!check_has_break(rs->body, true)) {
 		if (!check_has_break(rs->body, true)) {
 			return check_is_terminating(rs->body);
 			return check_is_terminating(rs->body);
 		}
 		}
@@ -566,27 +566,33 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 		}
 		}
 	case_end;
 	case_end;
 
 
-	case_ast_node(ws, WhileStmt, node);
+	case_ast_node(fs, ForStmt, node);
 		u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
 		u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
 		check_open_scope(c, node);
 		check_open_scope(c, node);
 
 
-		if (ws->init != NULL) {
-			check_stmt(c, ws->init, 0);
+		if (fs->init != NULL) {
+			check_stmt(c, fs->init, 0);
 		}
 		}
-		if (ws->cond) {
-			Operand operand = {Addressing_Invalid};
-			check_expr(c, &operand, ws->cond);
-			if (operand.mode != Addressing_Invalid &&
-			    !is_type_boolean(operand.type)) {
-				error_node(ws->cond, "Non-boolean condition in `while` statement");
+		if (fs->cond != NULL) {
+			Operand o = {Addressing_Invalid};
+			check_expr(c, &o, fs->cond);
+			if (o.mode != Addressing_Invalid && !is_type_boolean(o.type)) {
+				error_node(fs->cond, "Non-boolean condition in `for` statement");
+			}
+		}
+		if (fs->post != NULL) {
+			check_stmt(c, fs->post, 0);
+
+			if (fs->post->kind != AstNode_AssignStmt) {
+				error_node(fs->post, "`for` statement post statement must be an assignment");
 			}
 			}
 		}
 		}
-		check_stmt(c, ws->body, new_flags);
+		check_stmt(c, fs->body, new_flags);
 
 
 		check_close_scope(c);
 		check_close_scope(c);
 	case_end;
 	case_end;
 
 
-	case_ast_node(rs, ForStmt, node);
+	case_ast_node(rs, RangeStmt, node);
 		u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
 		u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
 		check_open_scope(c, node);
 		check_open_scope(c, node);
 
 

+ 27 - 17
src/ir.c

@@ -4470,44 +4470,54 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
 		proc->curr_block = done;
 		proc->curr_block = done;
 	case_end;
 	case_end;
 
 
-	case_ast_node(ws, WhileStmt, node);
-		ir_emit_comment(proc, str_lit("WhileStmt"));
-		if (ws->init != NULL) {
-			irBlock *init = ir_add_block(proc, node, "while.init");
+	case_ast_node(fs, ForStmt, node);
+		ir_emit_comment(proc, str_lit("ForStmt"));
+		if (fs->init != NULL) {
+			irBlock *init = ir_add_block(proc, node, "for.init");
 			ir_emit_jump(proc, init);
 			ir_emit_jump(proc, init);
 			proc->curr_block = init;
 			proc->curr_block = init;
-			ir_build_stmt(proc, ws->init);
+			ir_build_stmt(proc, fs->init);
 		}
 		}
-		irBlock *body = ir_add_block(proc, node, "while.body");
-		irBlock *done = ir_add_block(proc, node, "while.done"); // NOTE(bill): Append later
-
+		irBlock *body = ir_add_block(proc, node, "for.body");
+		irBlock *done = ir_add_block(proc, node, "for.done"); // NOTE(bill): Append later
 		irBlock *loop = body;
 		irBlock *loop = body;
-
-		if (ws->cond != NULL) {
-			loop = ir_add_block(proc, node, "while.loop");
+		if (fs->cond != NULL) {
+			loop = ir_add_block(proc, node, "for.loop");
+		}
+		irBlock *cont = loop;
+		if (fs->post != NULL) {
+			cont = ir_add_block(proc, node, "for.post");
 		}
 		}
 		ir_emit_jump(proc, loop);
 		ir_emit_jump(proc, loop);
 		proc->curr_block = loop;
 		proc->curr_block = loop;
+
 		if (loop != body) {
 		if (loop != body) {
-			ir_build_cond(proc, ws->cond, body, done);
+			ir_build_cond(proc, fs->cond, body, done);
 			proc->curr_block = body;
 			proc->curr_block = body;
 		}
 		}
 
 
-		ir_push_target_list(proc, done, loop, NULL);
+		ir_push_target_list(proc, done, cont, NULL);
 
 
 		ir_open_scope(proc);
 		ir_open_scope(proc);
-		ir_build_stmt(proc, ws->body);
+		ir_build_stmt(proc, fs->body);
 		ir_close_scope(proc, irDeferExit_Default, NULL);
 		ir_close_scope(proc, irDeferExit_Default, NULL);
 
 
 		ir_pop_target_list(proc);
 		ir_pop_target_list(proc);
-		ir_emit_jump(proc, loop);
+
+		ir_emit_jump(proc, cont);
+
+		if (fs->post != NULL) {
+			proc->curr_block = cont;
+			ir_build_stmt(proc, fs->post);
+			ir_emit_jump(proc, loop);
+		}
 
 
 		proc->curr_block = done;
 		proc->curr_block = done;
 	case_end;
 	case_end;
 
 
 
 
-	case_ast_node(rs, ForStmt, node);
-		ir_emit_comment(proc, str_lit("ForStmt"));
+	case_ast_node(rs, RangeStmt, node);
+		ir_emit_comment(proc, str_lit("RangeStmt"));
 
 
 		Type *val_type = NULL;
 		Type *val_type = NULL;
 		Type *idx_type = NULL;
 		Type *idx_type = NULL;

+ 111 - 50
src/parser.c

@@ -221,16 +221,18 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
 		Token token; \
 		Token token; \
 		AstNodeArray results; \
 		AstNodeArray results; \
 	}) \
 	}) \
-	AST_NODE_KIND(WhileStmt, "while statement", struct { \
+	AST_NODE_KIND(ForStmt, "for statement", struct { \
 		Token    token; \
 		Token    token; \
 		AstNode *init; \
 		AstNode *init; \
 		AstNode *cond; \
 		AstNode *cond; \
+		AstNode *post; \
 		AstNode *body; \
 		AstNode *body; \
 	}) \
 	}) \
-	AST_NODE_KIND(ForStmt, "range statement", struct { \
+	AST_NODE_KIND(RangeStmt, "range statement", struct { \
 		Token    token; \
 		Token    token; \
 		AstNode *value; \
 		AstNode *value; \
 		AstNode *index; \
 		AstNode *index; \
+		Token    in_token; \
 		AstNode *expr; \
 		AstNode *expr; \
 		AstNode *body; \
 		AstNode *body; \
 	}) \
 	}) \
@@ -501,8 +503,10 @@ Token ast_node_token(AstNode *node) {
 		return node->WhenStmt.token;
 		return node->WhenStmt.token;
 	case AstNode_ReturnStmt:
 	case AstNode_ReturnStmt:
 		return node->ReturnStmt.token;
 		return node->ReturnStmt.token;
-	case AstNode_WhileStmt:
-		return node->WhileStmt.token;
+	case AstNode_ForStmt:
+		return node->ForStmt.token;
+	case AstNode_RangeStmt:
+		return node->RangeStmt.token;
 	case AstNode_MatchStmt:
 	case AstNode_MatchStmt:
 		return node->MatchStmt.token;
 		return node->MatchStmt.token;
 	case AstNode_CaseClause:
 	case AstNode_CaseClause:
@@ -904,24 +908,28 @@ AstNode *make_return_stmt(AstFile *f, Token token, AstNodeArray results) {
 	return result;
 	return result;
 }
 }
 
 
-AstNode *make_while_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *body) {
-	AstNode *result = make_node(f, AstNode_WhileStmt);
-	result->WhileStmt.token = token;
-	result->WhileStmt.init  = init;
-	result->WhileStmt.cond  = cond;
-	result->WhileStmt.body  = body;
-	return result;
-}
-AstNode *make_for_stmt(AstFile *f, Token token, AstNode *value, AstNode *index, AstNode *expr, AstNode *body) {
+
+AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) {
 	AstNode *result = make_node(f, AstNode_ForStmt);
 	AstNode *result = make_node(f, AstNode_ForStmt);
 	result->ForStmt.token = token;
 	result->ForStmt.token = token;
-	result->ForStmt.value = value;
-	result->ForStmt.index = index;
-	result->ForStmt.expr  = expr;
+	result->ForStmt.init  = init;
+	result->ForStmt.cond  = cond;
+	result->ForStmt.post  = post;
 	result->ForStmt.body  = body;
 	result->ForStmt.body  = body;
 	return result;
 	return result;
 }
 }
 
 
+AstNode *make_range_stmt(AstFile *f, Token token, AstNode *value, AstNode *index, Token in_token, AstNode *expr, AstNode *body) {
+	AstNode *result = make_node(f, AstNode_RangeStmt);
+	result->RangeStmt.token = token;
+	result->RangeStmt.value = value;
+	result->RangeStmt.index = index;
+	result->RangeStmt.in_token = in_token;
+	result->RangeStmt.expr  = expr;
+	result->RangeStmt.body  = body;
+	return result;
+}
+
 AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, AstNode *body) {
 AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, AstNode *body) {
 	AstNode *result = make_node(f, AstNode_MatchStmt);
 	AstNode *result = make_node(f, AstNode_MatchStmt);
 	result->MatchStmt.token = token;
 	result->MatchStmt.token = token;
@@ -1258,7 +1266,6 @@ void fix_advance_to_next_stmt(AstFile *f) {
 		case Token_if:
 		case Token_if:
 		case Token_when:
 		case Token_when:
 		case Token_return:
 		case Token_return:
-		case Token_while:
 		case Token_range:
 		case Token_range:
 		case Token_match:
 		case Token_match:
 		case Token_defer:
 		case Token_defer:
@@ -1626,7 +1633,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str
 
 
 AstNodeArray parse_lhs_expr_list(AstFile *f);
 AstNodeArray parse_lhs_expr_list(AstFile *f);
 AstNodeArray parse_rhs_expr_list(AstFile *f);
 AstNodeArray parse_rhs_expr_list(AstFile *f);
-AstNode *    parse_simple_stmt  (AstFile *f);
+AstNode *    parse_simple_stmt  (AstFile *f, bool in_stmt_ok);
 AstNode *    parse_type         (AstFile *f);
 AstNode *    parse_type         (AstFile *f);
 
 
 AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
 AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
@@ -1673,7 +1680,7 @@ AstNode *parse_if_expr(AstFile *f) {
 	if (allow_token(f, Token_Semicolon)) {
 	if (allow_token(f, Token_Semicolon)) {
 		cond = parse_expr(f, false);
 		cond = parse_expr(f, false);
 	} else {
 	} else {
-		init = parse_simple_stmt(f);
+		init = parse_simple_stmt(f, false);
 		if (allow_token(f, Token_Semicolon)) {
 		if (allow_token(f, Token_Semicolon)) {
 			cond = parse_expr(f, false);
 			cond = parse_expr(f, false);
 		} else {
 		} else {
@@ -2261,7 +2268,8 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) {
 	return make_value_decl(f, is_mutable, lhs, type, values);
 	return make_value_decl(f, is_mutable, lhs, type, values);
 }
 }
 
 
-AstNode *parse_simple_stmt(AstFile *f) {
+
+AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
 	AstNodeArray lhs = parse_lhs_expr_list(f);
 	AstNodeArray lhs = parse_lhs_expr_list(f);
 	Token token = f->curr_token;
 	Token token = f->curr_token;
 	switch (token.kind) {
 	switch (token.kind) {
@@ -2293,6 +2301,28 @@ AstNode *parse_simple_stmt(AstFile *f) {
 		return make_assign_stmt(f, token, lhs, rhs);
 		return make_assign_stmt(f, token, lhs, rhs);
 	} break;
 	} break;
 
 
+	case Token_in:
+		if (in_stmt_ok) {
+			allow_token(f, Token_in);
+			AstNode *expr = parse_expr(f, false);
+			switch (f->curr_token.kind) {
+			case Token_HalfOpenRange:
+			case Token_Ellipsis: {
+				Token op = f->curr_token;
+				next_token(f);
+				AstNode *right = parse_expr(f, false);
+				expr = make_interval_expr(f, op, expr, right);
+			} break;
+			}
+
+			AstNodeArray rhs = {0};
+			array_init_count(&rhs, heap_allocator(), 1);
+			rhs.e[0] = expr;
+
+			return make_assign_stmt(f, token, lhs, rhs);
+		}
+		break;
+
 	case Token_Colon:
 	case Token_Colon:
 		return parse_value_decl(f, lhs);
 		return parse_value_decl(f, lhs);
 	}
 	}
@@ -2782,7 +2812,7 @@ AstNode *parse_if_stmt(AstFile *f) {
 	if (allow_token(f, Token_Semicolon)) {
 	if (allow_token(f, Token_Semicolon)) {
 		cond = parse_expr(f, false);
 		cond = parse_expr(f, false);
 	} else {
 	} else {
-		init = parse_simple_stmt(f);
+		init = parse_simple_stmt(f, false);
 		if (allow_token(f, Token_Semicolon)) {
 		if (allow_token(f, Token_Semicolon)) {
 			cond = parse_expr(f, false);
 			cond = parse_expr(f, false);
 		} else {
 		} else {
@@ -2900,47 +2930,78 @@ AstNode *parse_give_stmt(AstFile *f) {
 	return make_expr_stmt(f, ge);
 	return make_expr_stmt(f, ge);
 }
 }
 
 
-AstNode *parse_while_stmt(AstFile *f) {
+AstNode *parse_for_stmt(AstFile *f) {
 	if (f->curr_proc == NULL) {
 	if (f->curr_proc == NULL) {
-		syntax_error(f->curr_token, "You cannot use a while statement in the file scope");
+		syntax_error(f->curr_token, "You cannot use a for statement in the file scope");
 		return make_bad_stmt(f, f->curr_token, f->curr_token);
 		return make_bad_stmt(f, f->curr_token, f->curr_token);
 	}
 	}
 
 
-	Token token = expect_token(f, Token_while);
+	Token token = expect_token(f, Token_for);
 
 
 	AstNode *init = NULL;
 	AstNode *init = NULL;
 	AstNode *cond = NULL;
 	AstNode *cond = NULL;
+	AstNode *post = NULL;
 	AstNode *body = NULL;
 	AstNode *body = NULL;
+	bool is_range = false;
 
 
-	isize prev_level = f->expr_level;
-	f->expr_level = -1;
-
+	if (f->curr_token.kind != Token_OpenBrace) {
+		isize prev_level = f->expr_level;
+		f->expr_level = -1;
+		if (f->curr_token.kind != Token_Semicolon) {
+			cond = parse_simple_stmt(f, true);
+			if (cond->kind == AstNode_AssignStmt &&
+			    cond->AssignStmt.op.kind == Token_in) {
+				is_range = true;
+			}
+		}
 
 
-	cond = parse_simple_stmt(f);
-	if (is_ast_node_complex_stmt(cond)) {
-		syntax_error(f->curr_token, "You are not allowed that type of statement in a while statement, it is too complex!");
-	}
+		if (!is_range && f->curr_token.kind == Token_Semicolon) {
+			next_token(f);
+			init = cond;
+			cond = NULL;
+			if (f->curr_token.kind != Token_Semicolon) {
+				cond = parse_simple_stmt(f, false);
+			}
+			expect_semicolon(f, cond);
+			if (f->curr_token.kind != Token_OpenBrace) {
+				post = parse_simple_stmt(f, false);
+			}
+		}
 
 
-	if (allow_token(f, Token_Semicolon)) {
-		init = cond;
-		cond = parse_simple_stmt(f);
+		f->expr_level = prev_level;
 	}
 	}
-	f->expr_level = prev_level;
 
 
 	body = parse_block_stmt(f, false);
 	body = parse_block_stmt(f, false);
 
 
-	cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
-
-	return make_while_stmt(f, token, init, cond, body);
-}
-
+	if (is_range) {
+		GB_ASSERT(cond->kind == AstNode_AssignStmt);
+		Token in_token = cond->AssignStmt.op;
+		AstNode *value = NULL;
+		AstNode *index = NULL;
+		switch (cond->AssignStmt.lhs.count) {
+		case 1:
+			value = cond->AssignStmt.lhs.e[0];
+			break;
+		case 2:
+			value = cond->AssignStmt.lhs.e[0];
+			index = cond->AssignStmt.lhs.e[1];
+			break;
+		default:
+			error_node(cond, "Expected at 1 or 2 identifiers");
+			return make_bad_stmt(f, token, f->curr_token);
+		}
 
 
-AstNode *parse_for_stmt(AstFile *f) {
-	if (f->curr_proc == NULL) {
-		syntax_error(f->curr_token, "You cannot use a for statement in the file scope");
-		return make_bad_stmt(f, f->curr_token, f->curr_token);
+		AstNode *rhs = NULL;
+		if (cond->AssignStmt.rhs.count > 0) {
+			rhs = cond->AssignStmt.rhs.e[0];
+		}
+		return make_range_stmt(f, token, value, index, in_token, rhs, body);
 	}
 	}
 
 
+	cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
+	return make_for_stmt(f, token, init, cond, post, body);
+
+#if 0
 	Token token = expect_token(f, Token_for);
 	Token token = expect_token(f, Token_for);
 	AstNodeArray names = parse_ident_list(f);
 	AstNodeArray names = parse_ident_list(f);
 	parse_check_name_list_for_reserves(f, names);
 	parse_check_name_list_for_reserves(f, names);
@@ -2977,7 +3038,8 @@ AstNode *parse_for_stmt(AstFile *f) {
 		return make_bad_stmt(f, token, f->curr_token);
 		return make_bad_stmt(f, token, f->curr_token);
 	}
 	}
 
 
-	return make_for_stmt(f, token, value, index, expr, body);
+	return make_range_stmt(f, token, value, index, expr, body);
+#endif
 }
 }
 
 
 AstNode *parse_case_clause(AstFile *f) {
 AstNode *parse_case_clause(AstFile *f) {
@@ -3030,7 +3092,7 @@ AstNode *parse_match_stmt(AstFile *f) {
 
 
 		AstNode *var = parse_identifier(f);
 		AstNode *var = parse_identifier(f);
 		expect_token_after(f, Token_in, "match type name");
 		expect_token_after(f, Token_in, "match type name");
-		tag = parse_simple_stmt(f);
+		tag = parse_simple_stmt(f, false);
 
 
 		f->expr_level = prev_level;
 		f->expr_level = prev_level;
 
 
@@ -3052,13 +3114,13 @@ AstNode *parse_match_stmt(AstFile *f) {
 			isize prev_level = f->expr_level;
 			isize prev_level = f->expr_level;
 			f->expr_level = -1;
 			f->expr_level = -1;
 			if (f->curr_token.kind != Token_Semicolon) {
 			if (f->curr_token.kind != Token_Semicolon) {
-				tag = parse_simple_stmt(f);
+				tag = parse_simple_stmt(f, false);
 			}
 			}
 			if (allow_token(f, Token_Semicolon)) {
 			if (allow_token(f, Token_Semicolon)) {
 				init = tag;
 				init = tag;
 				tag = NULL;
 				tag = NULL;
 				if (f->curr_token.kind != Token_OpenBrace) {
 				if (f->curr_token.kind != Token_OpenBrace) {
-					tag = parse_simple_stmt(f);
+					tag = parse_simple_stmt(f, false);
 				}
 				}
 			}
 			}
 
 
@@ -3151,13 +3213,12 @@ AstNode *parse_stmt(AstFile *f) {
 	case Token_Sub:
 	case Token_Sub:
 	case Token_Xor:
 	case Token_Xor:
 	case Token_Not:
 	case Token_Not:
-		s = parse_simple_stmt(f);
+		s = parse_simple_stmt(f, false);
 		expect_semicolon(f, s);
 		expect_semicolon(f, s);
 		return s;
 		return s;
 
 
 	case Token_if:     return parse_if_stmt(f);
 	case Token_if:     return parse_if_stmt(f);
 	case Token_when:   return parse_when_stmt(f);
 	case Token_when:   return parse_when_stmt(f);
-	case Token_while:  return parse_while_stmt(f);
 	case Token_for:    return parse_for_stmt(f);
 	case Token_for:    return parse_for_stmt(f);
 	case Token_match:  return parse_match_stmt(f);
 	case Token_match:  return parse_match_stmt(f);
 	case Token_defer:  return parse_defer_stmt(f);
 	case Token_defer:  return parse_defer_stmt(f);

+ 0 - 1
src/tokenizer.c

@@ -92,7 +92,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_then,           "then"), \
 	TOKEN_KIND(Token_then,           "then"), \
 	TOKEN_KIND(Token_if,             "if"), \
 	TOKEN_KIND(Token_if,             "if"), \
 	TOKEN_KIND(Token_else,           "else"), \
 	TOKEN_KIND(Token_else,           "else"), \
-	TOKEN_KIND(Token_while,          "while"), \
 	TOKEN_KIND(Token_for,            "for"), \
 	TOKEN_KIND(Token_for,            "for"), \
 	TOKEN_KIND(Token_in,             "in"), \
 	TOKEN_KIND(Token_in,             "in"), \
 	TOKEN_KIND(Token_when,           "when"), \
 	TOKEN_KIND(Token_when,           "when"), \