diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 1e207e7..944baa6 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -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); diff --git a/src/lexer/token.c b/src/lexer/token.c index e1ae531..dc959fc 100644 --- a/src/lexer/token.c +++ b/src/lexer/token.c @@ -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] = "}", diff --git a/src/lexer/token.h b/src/lexer/token.h index 9c13a9a..4082d2e 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -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, diff --git a/src/parser/desugar.c b/src/parser/desugar.c index c3c3be1..8eb4646 100644 --- a/src/parser/desugar.c +++ b/src/parser/desugar.c @@ -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 iarena, 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)); // 增量追加到循环体末尾 diff --git a/src/parser/desugar.h b/src/parser/desugar.h index 959571d..acb2ad1 100644 --- a/src/parser/desugar.h +++ b/src/parser/desugar.h @@ -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 ikind == 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) { diff --git a/test/programs/41_for_step.l b/test/programs/41_for_step.l new file mode 100644 index 0000000..c0ac68d --- /dev/null +++ b/test/programs/41_for_step.l @@ -0,0 +1,6 @@ +fn main() -> i64 { + for i in 0 to 10 step 2 { + print_i64(i); + } + return 0; +}