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("var", TOK_VAR);
|
||||||
KW("if", TOK_IF); KW("else", TOK_ELSE); KW("guard", TOK_GUARD);
|
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("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("return", TOK_RETURN);
|
||||||
KW("i32", TOK_I32); KW("i64", TOK_I64);
|
KW("i32", TOK_I32); KW("i64", TOK_I64);
|
||||||
KW("u64", TOK_U64); KW("f64", TOK_F64);
|
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_EQ_EQ] = "==", [TOK_BANG_EQ] = "!=",
|
||||||
[TOK_LT] = "<", [TOK_GT] = ">", [TOK_LT_EQ] = "<=", [TOK_GT_EQ] = ">=",
|
[TOK_LT] = "<", [TOK_GT] = ">", [TOK_LT_EQ] = "<=", [TOK_GT_EQ] = ">=",
|
||||||
[TOK_AND_AND] = "&&", [TOK_PIPE_PIPE] = "||", [TOK_PIPE] = "|>", [TOK_BANG] = "!",
|
[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_PLUS_EQ] = "+=", [TOK_MINUS_EQ] = "-=", [TOK_STAR_EQ] = "*=", [TOK_SLASH_EQ] = "/=",
|
||||||
[TOK_LPAREN] = "(", [TOK_RPAREN] = ")",
|
[TOK_LPAREN] = "(", [TOK_RPAREN] = ")",
|
||||||
[TOK_LBRACE] = "{", [TOK_RBRACE] = "}",
|
[TOK_LBRACE] = "{", [TOK_RBRACE] = "}",
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ typedef enum {
|
|||||||
TOK_PLUS, TOK_MINUS, TOK_STAR, TOK_SLASH, TOK_PERCENT,
|
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_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_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_PLUS_EQ, TOK_MINUS_EQ, TOK_STAR_EQ, TOK_SLASH_EQ,
|
||||||
// 分隔符
|
// 分隔符
|
||||||
TOK_LPAREN, TOK_RPAREN, TOK_LBRACE, TOK_RBRACE,
|
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));
|
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,
|
AstNode* desugar_for(Parser* p, const Token* for_tok,
|
||||||
const char* var_name, AstNode* start_expr,
|
const char* var_name, AstNode* start_expr,
|
||||||
AstNode* end_expr, AstNode* body) {
|
AstNode* end_expr, AstNode* step_expr, AstNode* body) {
|
||||||
// var i = start;
|
|
||||||
AstNode* let_stmt = ast_make_let(p->arena, var_name, TYPE_UNKNOWN,
|
AstNode* let_stmt = ast_make_let(p->arena, var_name, TYPE_UNKNOWN,
|
||||||
false, true, start_expr, NULL, 0, NULL, 0, tok_loc(for_tok));
|
false, true, start_expr, NULL, 0, NULL, 0, tok_loc(for_tok));
|
||||||
|
|
||||||
// i < end
|
|
||||||
AstNode* cond = ast_make_binary(p->arena, OP_LT,
|
AstNode* cond = ast_make_binary(p->arena, OP_LT,
|
||||||
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
|
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
|
||||||
end_expr, 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,
|
AstNode* incr = ast_make_assign(p->arena, var_name,
|
||||||
ast_make_binary(p->arena, OP_ADD,
|
ast_make_binary(p->arena, OP_ADD,
|
||||||
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
|
ast_make_ident(p->arena, var_name, tok_loc(for_tok)),
|
||||||
ast_make_literal_i64(p->arena, 1, tok_loc(for_tok)),
|
step, tok_loc(for_tok)),
|
||||||
tok_loc(for_tok)),
|
|
||||||
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* desugar_guard(Parser* p, const Token* guard_tok,
|
||||||
AstNode* cond, AstNode* body);
|
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,
|
AstNode* desugar_for(Parser* p, const Token* for_tok,
|
||||||
const char* var_name, AstNode* start_expr,
|
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 ... }
|
// if let pattern = expr { then } else { else } → { let __match = expr; if __match == pattern ... }
|
||||||
AstNode* desugar_if_let(Parser* p, const Token* if_tok,
|
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;
|
if (!expect(p, TOK_TO, error, "缺少 'to'")) return NULL;
|
||||||
AstNode* end_expr = parse_expr(p, error);
|
AstNode* end_expr = parse_expr(p, error);
|
||||||
if (!end_expr) return NULL;
|
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);
|
AstNode* body = parse_block(p, error);
|
||||||
if (!body) return NULL;
|
if (!body) return NULL;
|
||||||
const char* vname = arena_strdup_impl(p->arena, var_name->start, var_name->length);
|
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) {
|
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