feat: 列表推导式 [for x in arr: expr] — parser+sema+codegen
AST(29): +AST_LIST_COMP, parser 解析 [for var in expr: body] sema: 创建子作用域注册循环变量, codegen: for 循环绑定+填充结果数组 已知限制: 仅支持 2 元素及以下数组 (大数组 alloca 对齐问题待修) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -403,6 +403,74 @@ CG_HANDLER(cg_if_expr)
|
||||
// === Visitor Dispatch 表 ===
|
||||
static AstDispatch cg_dispatch;
|
||||
|
||||
static LLVMValueRef cg_list_comp_impl(CgCtx* ctx, AstNode* node) {
|
||||
TypeInfo* ti = &node->type;
|
||||
LLVMTypeRef elem_ty = type_info_to_llvm(ctx, ti);
|
||||
LLVMTypeRef arr_ty = LLVMArrayType(elem_ty, (unsigned)ti->array_size);
|
||||
LLVMValueRef result = LLVMBuildAlloca(ctx->builder, arr_ty, "list");
|
||||
// 初始化为零
|
||||
LLVMBuildStore(ctx->builder, LLVMConstNull(arr_ty), result);
|
||||
// 获取源数组指针 (需要 alloca 做 GEP, 不能用 load 后的值)
|
||||
LLVMValueRef src_ptr = NULL;
|
||||
if (node->as.list_comp.array->kind == AST_IDENT_EXPR) {
|
||||
src_ptr = find_var(ctx, node->as.list_comp.array->as.ident.name);
|
||||
}
|
||||
if (!src_ptr) return NULL;
|
||||
// for i in 0 to N
|
||||
LLVMValueRef func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(ctx->builder));
|
||||
LLVMBasicBlockRef cond_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "lc_cond");
|
||||
LLVMBasicBlockRef body_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "lc_body");
|
||||
LLVMBasicBlockRef exit_bb = LLVMAppendBasicBlockInContext(ctx->context, func, "lc_exit");
|
||||
// 循环变量 i
|
||||
LLVMValueRef i_alloca = LLVMBuildAlloca(ctx->builder,
|
||||
LLVMInt64TypeInContext(ctx->context), "lc_i");
|
||||
LLVMBuildStore(ctx->builder,
|
||||
LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 0, false), i_alloca);
|
||||
LLVMBuildBr(ctx->builder, cond_bb);
|
||||
// 条件块
|
||||
LLVMPositionBuilderAtEnd(ctx->builder, cond_bb);
|
||||
LLVMValueRef i_val = LLVMBuildLoad2(ctx->builder,
|
||||
LLVMInt64TypeInContext(ctx->context), i_alloca, "i");
|
||||
LLVMValueRef end_val = LLVMConstInt(LLVMInt64TypeInContext(ctx->context),
|
||||
(unsigned long long)ti->array_size, false);
|
||||
LLVMValueRef cond = LLVMBuildICmp(ctx->builder, LLVMIntSLT, i_val, end_val, "lc_cond");
|
||||
LLVMBuildCondBr(ctx->builder, cond, body_bb, exit_bb);
|
||||
// 循环体
|
||||
LLVMPositionBuilderAtEnd(ctx->builder, body_bb);
|
||||
LLVMValueRef i32_trunc = LLVMBuildTrunc(ctx->builder, i_val,
|
||||
LLVMInt32TypeInContext(ctx->context), "i32");
|
||||
// 绑定循环变量: var x = arr[i]
|
||||
LLVMValueRef src_indices[] = {
|
||||
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false), i32_trunc
|
||||
};
|
||||
LLVMValueRef src_gep = LLVMBuildGEP2(ctx->builder, arr_ty, src_ptr, src_indices, 2, "src_gep");
|
||||
LLVMValueRef var_alloca = LLVMBuildAlloca(ctx->builder, elem_ty,
|
||||
node->as.list_comp.var_name);
|
||||
LLVMBuildStore(ctx->builder,
|
||||
LLVMBuildLoad2(ctx->builder, elem_ty, src_gep, "src_val"), var_alloca);
|
||||
add_var(ctx, node->as.list_comp.var_name, var_alloca, elem_ty);
|
||||
// map 表达式(可引用循环变量)
|
||||
LLVMValueRef map_val = codegen_expr(ctx, node->as.list_comp.map_expr);
|
||||
if (!map_val) return NULL;
|
||||
// 结果数组: GEP + store
|
||||
LLVMValueRef dst_indices[] = {
|
||||
LLVMConstInt(LLVMInt32TypeInContext(ctx->context), 0, false),
|
||||
LLVMBuildTrunc(ctx->builder, i_val,
|
||||
LLVMInt32TypeInContext(ctx->context), "i32")
|
||||
};
|
||||
LLVMBuildStore(ctx->builder, map_val,
|
||||
LLVMBuildGEP2(ctx->builder, arr_ty, result, dst_indices, 2, "dst_ptr"));
|
||||
// i = i + 1
|
||||
LLVMValueRef next_i = LLVMBuildAdd(ctx->builder, i_val,
|
||||
LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 1, false), "i_inc");
|
||||
LLVMBuildStore(ctx->builder, next_i, i_alloca);
|
||||
LLVMBuildBr(ctx->builder, cond_bb);
|
||||
// 出口
|
||||
LLVMPositionBuilderAtEnd(ctx->builder, exit_bb);
|
||||
return LLVMBuildLoad2(ctx->builder, arr_ty, result, "list_val");
|
||||
}
|
||||
CG_HANDLER(cg_list_comp)
|
||||
|
||||
void codegen_expr_init(void) {
|
||||
ast_dispatch_set(&cg_dispatch, AST_LITERAL_EXPR, cg_literal);
|
||||
ast_dispatch_set(&cg_dispatch, AST_IDENT_EXPR, cg_ident);
|
||||
@@ -416,6 +484,7 @@ void codegen_expr_init(void) {
|
||||
ast_dispatch_set(&cg_dispatch, AST_INDEX_EXPR, cg_index);
|
||||
ast_dispatch_set(&cg_dispatch, AST_BLOCK, cg_block);
|
||||
ast_dispatch_set(&cg_dispatch, AST_IF_STMT, cg_if_expr);
|
||||
ast_dispatch_set(&cg_dispatch, AST_LIST_COMP, cg_list_comp);
|
||||
}
|
||||
|
||||
// === 统一入口 ===
|
||||
|
||||
Reference in New Issue
Block a user