feat: for step 步长 — for i in 0 to 10 step 2 { ... }

Token(75): +TOK_STEP, desugar_for 增加 step_expr 参数, 默认 step=1

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 14:13:09 +08:00
parent 71208a87f4
commit caf17e16fc
7 changed files with 23 additions and 13 deletions
+1 -1
View File
@@ -58,7 +58,7 @@ static TokenKind check_keyword(const Token* tok) {
KW("var", TOK_VAR);
KW("if", TOK_IF); KW("else", TOK_ELSE); KW("guard", TOK_GUARD);
KW("while", TOK_WHILE); KW("for", TOK_FOR); KW("in", TOK_IN);
KW("to", TOK_TO);
KW("to", TOK_TO); KW("step", TOK_STEP);
KW("return", TOK_RETURN);
KW("i32", TOK_I32); KW("i64", TOK_I64);
KW("u64", TOK_U64); KW("f64", TOK_F64);
+1 -1
View File
@@ -22,7 +22,7 @@ static const char* NAMES[] = {
[TOK_EQ_EQ] = "==", [TOK_BANG_EQ] = "!=",
[TOK_LT] = "<", [TOK_GT] = ">", [TOK_LT_EQ] = "<=", [TOK_GT_EQ] = ">=",
[TOK_AND_AND] = "&&", [TOK_PIPE_PIPE] = "||", [TOK_PIPE] = "|>", [TOK_BANG] = "!",
[TOK_ARROW] = "->", [TOK_TO] = "to", [TOK_MATCH_ARROW] = "=>",
[TOK_ARROW] = "->", [TOK_TO] = "to", [TOK_STEP] = "step", [TOK_MATCH_ARROW] = "=>",
[TOK_PLUS_EQ] = "+=", [TOK_MINUS_EQ] = "-=", [TOK_STAR_EQ] = "*=", [TOK_SLASH_EQ] = "/=",
[TOK_LPAREN] = "(", [TOK_RPAREN] = ")",
[TOK_LBRACE] = "{", [TOK_RBRACE] = "}",
+1 -1
View File
@@ -19,7 +19,7 @@ typedef enum {
TOK_PLUS, TOK_MINUS, TOK_STAR, TOK_SLASH, TOK_PERCENT,
TOK_EQ_EQ, TOK_BANG_EQ, TOK_LT, TOK_GT, TOK_LT_EQ, TOK_GT_EQ,
TOK_AND_AND, TOK_PIPE_PIPE, TOK_PIPE, TOK_BANG,
TOK_ARROW, TOK_TO, TOK_MATCH_ARROW,
TOK_ARROW, TOK_TO, TOK_STEP, TOK_MATCH_ARROW,
TOK_PLUS_EQ, TOK_MINUS_EQ, TOK_STAR_EQ, TOK_SLASH_EQ,
// 分隔符
TOK_LPAREN, TOK_RPAREN, TOK_LBRACE, TOK_RBRACE,
+5 -7
View File
@@ -39,25 +39,23 @@ AstNode* desugar_guard(Parser* p, const Token* guard_tok,
return ast_make_if(p->arena, not_cond, body, NULL, tok_loc(guard_tok));
}
// === for i in start to end { body } → { var i = start; while i < end { body; i = i + 1; } } ===
// === for i in start to end [step N] { body } → { var i=start; while i<end { body; i=i+step; } } ===
AstNode* desugar_for(Parser* p, const Token* for_tok,
const char* var_name, AstNode* start_expr,
AstNode* end_expr, AstNode* body) {
// var i = start;
AstNode* end_expr, AstNode* step_expr, AstNode* body) {
AstNode* let_stmt = ast_make_let(p->arena, var_name, TYPE_UNKNOWN,
false, true, start_expr, NULL, 0, NULL, 0, tok_loc(for_tok));
// i < end
AstNode* cond = ast_make_binary(p->arena, OP_LT,
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
end_expr, tok_loc(for_tok));
// i = i + 1
AstNode* step = step_expr ? step_expr
: ast_make_literal_i64(p->arena, 1, tok_loc(for_tok));
AstNode* incr = ast_make_assign(p->arena, var_name,
ast_make_binary(p->arena, OP_ADD,
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
ast_make_literal_i64(p->arena, 1, tok_loc(for_tok)),
tok_loc(for_tok)),
step, tok_loc(for_tok)),
tok_loc(for_tok));
// 增量追加到循环体末尾
+2 -2
View File
@@ -13,10 +13,10 @@ AstNode* desugar_match(Parser* p, const Token* match_tok,
AstNode* desugar_guard(Parser* p, const Token* guard_tok,
AstNode* cond, AstNode* body);
// for i in start to end { body } → { var i = start; while i < end { body; i = i + 1; } }
// for i in start to end [step N] { body } → { var i=start; while i<end { body; i=i+step; } }
AstNode* desugar_for(Parser* p, const Token* for_tok,
const char* var_name, AstNode* start_expr,
AstNode* end_expr, AstNode* body);
AstNode* end_expr, AstNode* step_expr, AstNode* body);
// if let pattern = expr { then } else { else } → { let __match = expr; if __match == pattern ... }
AstNode* desugar_if_let(Parser* p, const Token* if_tok,
+7 -1
View File
@@ -176,10 +176,16 @@ AstNode* parse_statement(Parser* p, ErrorInfo* error) {
if (!expect(p, TOK_TO, error, "缺少 'to'")) return NULL;
AstNode* end_expr = parse_expr(p, error);
if (!end_expr) return NULL;
AstNode* step_expr = NULL;
if (peek(p)->kind == TOK_STEP) {
advance(p);
step_expr = parse_expr(p, error);
if (!step_expr) return NULL;
}
AstNode* body = parse_block(p, error);
if (!body) return NULL;
const char* vname = arena_strdup_impl(p->arena, var_name->start, var_name->length);
return desugar_for(p, t, vname, start_expr, end_expr, body);
return desugar_for(p, t, vname, start_expr, end_expr, step_expr, body);
}
if (t->kind == TOK_MATCH) {
+6
View File
@@ -0,0 +1,6 @@
fn main() -> i64 {
for i in 0 to 10 step 2 {
print_i64(i);
}
return 0;
}