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:
+1
-1
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
// 增量追加到循环体末尾
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
fn main() -> i64 {
|
||||
for i in 0 to 10 step 2 {
|
||||
print_i64(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user