feat: for 循环 + range (for i in start..end)
- lexer: TOK_FOR, TOK_IN, TOK_DOT_DOT + 修复数字中 .. 解析
- parser: for-in-range → desugar to {let mut, while, assign}
- 零 sema/codegen 改动,复用现有机制
- 新增 2 个集成测试 (10_for_range.l, 11_for_step2.l)
- mem2reg: LLVM 22 C API 不导出,标注已知限制
基于 Codex 分析报告 §6 P0 #3。
This commit is contained in:
@@ -254,6 +254,70 @@ static AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
||||
return ast_make_while(p->arena, cond, body, t->line, t->col);
|
||||
}
|
||||
|
||||
if (t->kind == TOK_FOR) {
|
||||
advance(p); // 跳过 'for'
|
||||
|
||||
// 解析循环变量名
|
||||
const Token* var_name = expect(p, TOK_IDENT, error, "for 后应为变量名");
|
||||
if (!var_name) return NULL;
|
||||
|
||||
// 解析 'in'
|
||||
if (!expect(p, TOK_IN, error, "缺少 'in'")) return NULL;
|
||||
|
||||
// 解析起始表达式
|
||||
AstNode* start_expr = parse_expr(p, error);
|
||||
if (!start_expr) return NULL;
|
||||
|
||||
// 解析 '..'
|
||||
if (!expect(p, TOK_DOT_DOT, error, "缺少 '..'")) return NULL;
|
||||
|
||||
// 解析结束表达式
|
||||
AstNode* end_expr = parse_expr(p, error);
|
||||
if (!end_expr) return NULL;
|
||||
|
||||
// 解析循环体
|
||||
AstNode* body = parse_block(p, error);
|
||||
if (!body) return NULL;
|
||||
|
||||
// 脱糖: for i in start..end { body; }
|
||||
// → { let mut i = start; while i < end { body; i = i + 1; } }
|
||||
|
||||
const char* vname = arena_strdup_impl(p->arena, var_name->start, var_name->length);
|
||||
|
||||
// 构建: let mut i = start;
|
||||
AstNode* let_stmt = ast_make_let(p->arena, vname, TYPE_UNKNOWN, false, true, start_expr, var_name->line, var_name->col);
|
||||
|
||||
// 构建: i < end (while 条件)
|
||||
AstNode* cond = ast_make_binary(p->arena, OP_LT,
|
||||
ast_make_ident(p->arena, vname, var_name->line, var_name->col),
|
||||
end_expr, var_name->line, var_name->col);
|
||||
|
||||
// 构建: i = i + 1 (循环增量)
|
||||
AstNode* incr = ast_make_assign(p->arena, vname,
|
||||
ast_make_binary(p->arena, OP_ADD,
|
||||
ast_make_ident(p->arena, vname, var_name->line, var_name->col),
|
||||
ast_make_literal_i64(p->arena, 1, var_name->line, var_name->col),
|
||||
var_name->line, var_name->col),
|
||||
var_name->line, var_name->col);
|
||||
|
||||
// 将增量追加到循环体末尾
|
||||
AstNode** new_stmts = arena_alloc_impl(p->arena,
|
||||
(body->as.block.stmt_count + 1) * sizeof(AstNode*));
|
||||
memcpy(new_stmts, body->as.block.stmts, body->as.block.stmt_count * sizeof(AstNode*));
|
||||
new_stmts[body->as.block.stmt_count] = incr;
|
||||
AstNode* new_body = ast_make_block(p->arena, new_stmts,
|
||||
body->as.block.stmt_count + 1, body->line, body->col);
|
||||
|
||||
// 构建: while i < end { ... body ... ; i = i + 1; }
|
||||
AstNode* while_loop = ast_make_while(p->arena, cond, new_body, t->line, t->col);
|
||||
|
||||
// 包装: { let mut i = start; while i < end { ... } }
|
||||
AstNode* stmts_arr[2] = { let_stmt, while_loop };
|
||||
AstNode** stmts = arena_alloc_impl(p->arena, 2 * sizeof(AstNode*));
|
||||
memcpy(stmts, stmts_arr, 2 * sizeof(AstNode*));
|
||||
return ast_make_block(p->arena, stmts, 2, t->line, t->col);
|
||||
}
|
||||
|
||||
if (t->kind == TOK_RETURN) {
|
||||
advance(p);
|
||||
if (match(p, TOK_SEMICOLON)) {
|
||||
|
||||
Reference in New Issue
Block a user