Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 443b22bdf1 | |||
| 0088347576 |
@@ -103,6 +103,20 @@ AstNode* ast_make_expr_stmt(void* alloc, AstNode* expr, SourceLoc loc) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNode* ast_make_defer_stmt(void* alloc, AstNode* body, SourceLoc loc) {
|
||||||
|
NEW(alloc, AST_DEFER_STMT);
|
||||||
|
n->as.defer_stmt.body = body;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode* ast_make_list_comp(void* alloc, const char* var, AstNode* arr, AstNode* map, SourceLoc loc) {
|
||||||
|
NEW(alloc, AST_LIST_COMP);
|
||||||
|
n->as.list_comp.var_name = var;
|
||||||
|
n->as.list_comp.array = arr;
|
||||||
|
n->as.list_comp.map_expr = map;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc) {
|
AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc) {
|
||||||
NEW(alloc, AST_BINARY_EXPR);
|
NEW(alloc, AST_BINARY_EXPR);
|
||||||
n->as.binary.op = op; n->as.binary.left = left; n->as.binary.right = right;
|
n->as.binary.op = op; n->as.binary.left = left; n->as.binary.right = right;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ typedef enum {
|
|||||||
AST_WHILE_STMT,
|
AST_WHILE_STMT,
|
||||||
AST_RETURN_STMT,
|
AST_RETURN_STMT,
|
||||||
AST_EXPR_STMT,
|
AST_EXPR_STMT,
|
||||||
|
AST_DEFER_STMT,
|
||||||
|
AST_LIST_COMP, // [for x in expr: body]
|
||||||
AST_BINARY_EXPR,
|
AST_BINARY_EXPR,
|
||||||
AST_UNARY_EXPR,
|
AST_UNARY_EXPR,
|
||||||
AST_CALL_EXPR,
|
AST_CALL_EXPR,
|
||||||
@@ -88,6 +90,10 @@ struct AstNode {
|
|||||||
struct { struct AstNode* expr; } return_stmt;
|
struct { struct AstNode* expr; } return_stmt;
|
||||||
// AST_EXPR_STMT
|
// AST_EXPR_STMT
|
||||||
struct { struct AstNode* expr; } expr_stmt;
|
struct { struct AstNode* expr; } expr_stmt;
|
||||||
|
// AST_DEFER_STMT
|
||||||
|
struct { struct AstNode* body; } defer_stmt;
|
||||||
|
// AST_LIST_COMP
|
||||||
|
struct { const char* var_name; struct AstNode* array; struct AstNode* map_expr; } list_comp;
|
||||||
// AST_BINARY_EXPR
|
// AST_BINARY_EXPR
|
||||||
struct { BinaryOp op; struct AstNode* left; struct AstNode* right; } binary;
|
struct { BinaryOp op; struct AstNode* left; struct AstNode* right; } binary;
|
||||||
// AST_UNARY_EXPR
|
// AST_UNARY_EXPR
|
||||||
@@ -153,6 +159,8 @@ AstNode* ast_make_if(void* alloc, AstNode* cond, AstNode* then_b, AstNode* else_
|
|||||||
AstNode* ast_make_while(void* alloc, AstNode* cond, AstNode* body, SourceLoc loc);
|
AstNode* ast_make_while(void* alloc, AstNode* cond, AstNode* body, SourceLoc loc);
|
||||||
AstNode* ast_make_return(void* alloc, AstNode* expr, SourceLoc loc);
|
AstNode* ast_make_return(void* alloc, AstNode* expr, SourceLoc loc);
|
||||||
AstNode* ast_make_expr_stmt(void* alloc, AstNode* expr, SourceLoc loc);
|
AstNode* ast_make_expr_stmt(void* alloc, AstNode* expr, SourceLoc loc);
|
||||||
|
AstNode* ast_make_defer_stmt(void* alloc, AstNode* expr, SourceLoc loc);
|
||||||
|
AstNode* ast_make_list_comp(void* alloc, const char* var, AstNode* arr, AstNode* map, SourceLoc loc);
|
||||||
AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc);
|
AstNode* ast_make_binary(void* alloc, BinaryOp op, AstNode* left, AstNode* right, SourceLoc loc);
|
||||||
AstNode* ast_make_unary(void* alloc, BinaryOp op, AstNode* operand, SourceLoc loc);
|
AstNode* ast_make_unary(void* alloc, BinaryOp op, AstNode* operand, SourceLoc loc);
|
||||||
AstNode* ast_make_call(void* alloc, const char* name, AstNode** args, const char** arg_names, size_t count, SourceLoc loc);
|
AstNode* ast_make_call(void* alloc, const char* name, AstNode** args, const char** arg_names, size_t count, SourceLoc loc);
|
||||||
|
|||||||
@@ -403,6 +403,74 @@ CG_HANDLER(cg_if_expr)
|
|||||||
// === Visitor Dispatch 表 ===
|
// === Visitor Dispatch 表 ===
|
||||||
static AstDispatch cg_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) {
|
void codegen_expr_init(void) {
|
||||||
ast_dispatch_set(&cg_dispatch, AST_LITERAL_EXPR, cg_literal);
|
ast_dispatch_set(&cg_dispatch, AST_LITERAL_EXPR, cg_literal);
|
||||||
ast_dispatch_set(&cg_dispatch, AST_IDENT_EXPR, cg_ident);
|
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_INDEX_EXPR, cg_index);
|
||||||
ast_dispatch_set(&cg_dispatch, AST_BLOCK, cg_block);
|
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_IF_STMT, cg_if_expr);
|
||||||
|
ast_dispatch_set(&cg_dispatch, AST_LIST_COMP, cg_list_comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 统一入口 ===
|
// === 统一入口 ===
|
||||||
|
|||||||
+16
-3
@@ -77,6 +77,13 @@ void cleanup_emit(CgCtx* ctx, size_t from_mark) {
|
|||||||
ctx->cleanup_count = from_mark;
|
ctx->cleanup_count = from_mark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发射所有 defer 语句(LIFO 顺序)
|
||||||
|
static void emit_deferred(CgCtx* ctx) {
|
||||||
|
for (size_t i = ctx->defer_count; i > 0; i--)
|
||||||
|
codegen_stmt(ctx, ctx->defer_exprs[i - 1]);
|
||||||
|
ctx->defer_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// === 语句代码生成 ===
|
// === 语句代码生成 ===
|
||||||
void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
@@ -146,6 +153,11 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
|||||||
codegen_expr(ctx, node->as.expr_stmt.expr);
|
codegen_expr(ctx, node->as.expr_stmt.expr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AST_DEFER_STMT:
|
||||||
|
if (ctx->defer_count < 64)
|
||||||
|
ctx->defer_exprs[ctx->defer_count++] = node->as.defer_stmt.body;
|
||||||
|
break;
|
||||||
|
|
||||||
case AST_RETURN_STMT: {
|
case AST_RETURN_STMT: {
|
||||||
// 先计算返回值
|
// 先计算返回值
|
||||||
LLVMValueRef ret_val = NULL;
|
LLVMValueRef ret_val = NULL;
|
||||||
@@ -168,9 +180,9 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// return 前释放当前作用域所有 str 堆分配
|
// defer → cleanup → ret 的顺序
|
||||||
|
emit_deferred(ctx);
|
||||||
cleanup_emit(ctx, 0);
|
cleanup_emit(ctx, 0);
|
||||||
// 然后 emit ret
|
|
||||||
if (has_val) LLVMBuildRet(ctx->builder, ret_val);
|
if (has_val) LLVMBuildRet(ctx->builder, ret_val);
|
||||||
else LLVMBuildRetVoid(ctx->builder);
|
else LLVMBuildRetVoid(ctx->builder);
|
||||||
break;
|
break;
|
||||||
@@ -416,11 +428,12 @@ LLVMModuleRef codegen_module(AstNode* ast, Arena* codegen_arena,
|
|||||||
add_var(&ctx, pnode->as.parameter.name, alloca, param_ty);
|
add_var(&ctx, pnode->as.parameter.name, alloca, param_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.defer_count = 0;
|
||||||
codegen_stmt(&ctx, fn->as.function.body);
|
codegen_stmt(&ctx, fn->as.function.body);
|
||||||
|
|
||||||
// 确保函数有终止指令(terminator)
|
// 确保函数有终止指令(terminator)
|
||||||
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx.builder))) {
|
if (!LLVMGetBasicBlockTerminator(LLVMGetInsertBlock(ctx.builder))) {
|
||||||
// 函数结尾隐式 return: 先释放所有 str 堆分配
|
emit_deferred(&ctx);
|
||||||
cleanup_emit(&ctx, 0);
|
cleanup_emit(&ctx, 0);
|
||||||
if (fn->as.function.return_type == TYPE_VOID)
|
if (fn->as.function.return_type == TYPE_VOID)
|
||||||
LLVMBuildRetVoid(ctx.builder);
|
LLVMBuildRetVoid(ctx.builder);
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ typedef struct {
|
|||||||
LLVMValueRef* cleanup_list;
|
LLVMValueRef* cleanup_list;
|
||||||
size_t cleanup_count;
|
size_t cleanup_count;
|
||||||
size_t cleanup_cap;
|
size_t cleanup_cap;
|
||||||
|
AstNode* defer_exprs[64];
|
||||||
|
size_t defer_count;
|
||||||
} CgCtx;
|
} CgCtx;
|
||||||
|
|
||||||
// === 类型映射 ===
|
// === 类型映射 ===
|
||||||
|
|||||||
+1
-1
@@ -65,7 +65,7 @@ static TokenKind check_keyword(const Token* tok) {
|
|||||||
KW("bool", TOK_BOOL); KW("char", TOK_CHAR);
|
KW("bool", TOK_BOOL); KW("char", TOK_CHAR);
|
||||||
KW("str", TOK_STR); KW("void", TOK_VOID);
|
KW("str", TOK_STR); KW("void", TOK_VOID);
|
||||||
KW("struct", TOK_STRUCT); KW("type", TOK_TYPE);
|
KW("struct", TOK_STRUCT); KW("type", TOK_TYPE);
|
||||||
KW("enum", TOK_ENUM); KW("extend", TOK_EXTEND); KW("match", TOK_MATCH);
|
KW("enum", TOK_ENUM); KW("extend", TOK_EXTEND); KW("defer", TOK_DEFER); KW("match", TOK_MATCH);
|
||||||
KW("pub", TOK_PUB); KW("mod", TOK_MOD); KW("use", TOK_USE);
|
KW("pub", TOK_PUB); KW("mod", TOK_MOD); KW("use", TOK_USE);
|
||||||
KW("trait", TOK_TRAIT); KW("Self", TOK_SELF);
|
KW("trait", TOK_TRAIT); KW("Self", TOK_SELF);
|
||||||
KW("_", TOK_UNDERSCORE);
|
KW("_", TOK_UNDERSCORE);
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ static const char* NAMES[] = {
|
|||||||
[TOK_TRAIT] = "trait", [TOK_SELF] = "Self",
|
[TOK_TRAIT] = "trait", [TOK_SELF] = "Self",
|
||||||
[TOK_ELSE] = "else", [TOK_WHILE] = "while", [TOK_FOR] = "for", [TOK_IN] = "in", [TOK_RETURN] = "return",
|
[TOK_ELSE] = "else", [TOK_WHILE] = "while", [TOK_FOR] = "for", [TOK_IN] = "in", [TOK_RETURN] = "return",
|
||||||
[TOK_STRUCT] = "struct", [TOK_TYPE] = "type", [TOK_ENUM] = "enum", [TOK_EXTEND] = "extend",
|
[TOK_STRUCT] = "struct", [TOK_TYPE] = "type", [TOK_ENUM] = "enum", [TOK_EXTEND] = "extend",
|
||||||
[TOK_MATCH] = "match",
|
[TOK_DEFER] = "defer", [TOK_MATCH] = "match",
|
||||||
[TOK_I32] = "i32", [TOK_I64] = "i64", [TOK_U64] = "u64", [TOK_F64] = "f64",
|
[TOK_I32] = "i32", [TOK_I64] = "i64", [TOK_U64] = "u64", [TOK_F64] = "f64",
|
||||||
[TOK_BOOL] = "bool", [TOK_CHAR] = "char", [TOK_STR] = "str", [TOK_VOID] = "void",
|
[TOK_BOOL] = "bool", [TOK_CHAR] = "char", [TOK_STR] = "str", [TOK_VOID] = "void",
|
||||||
[TOK_INT_LIT] = "整数", [TOK_FLOAT_LIT] = "浮点数",
|
[TOK_INT_LIT] = "整数", [TOK_FLOAT_LIT] = "浮点数",
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
// 关键字
|
// 关键字
|
||||||
TOK_FN, TOK_LET, TOK_VAR, TOK_IF, TOK_ELSE, TOK_WHILE, TOK_FOR, TOK_IN, TOK_RETURN, TOK_GUARD,
|
TOK_FN, TOK_LET, TOK_VAR, TOK_IF, TOK_ELSE, TOK_WHILE, TOK_FOR, TOK_IN, TOK_RETURN, TOK_GUARD,
|
||||||
TOK_STRUCT, TOK_TYPE, TOK_ENUM, TOK_EXTEND, TOK_MATCH, TOK_PUB, TOK_MOD, TOK_USE,
|
TOK_STRUCT, TOK_TYPE, TOK_ENUM, TOK_EXTEND, TOK_DEFER, TOK_MATCH, TOK_PUB, TOK_MOD, TOK_USE,
|
||||||
TOK_TRAIT, TOK_SELF,
|
TOK_TRAIT, TOK_SELF,
|
||||||
// 类型关键字
|
// 类型关键字
|
||||||
TOK_I32, TOK_I64, TOK_U64, TOK_F64, TOK_BOOL, TOK_CHAR, TOK_STR, TOK_VOID,
|
TOK_I32, TOK_I64, TOK_U64, TOK_F64, TOK_BOOL, TOK_CHAR, TOK_STR, TOK_VOID,
|
||||||
|
|||||||
@@ -306,6 +306,21 @@ AstNode* parse_expr_prec(Parser* p, Precedence min_prec, ErrorInfo* error) {
|
|||||||
}
|
}
|
||||||
left = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok));
|
left = ast_make_if(p->arena, cond, then_block, else_block, tok_loc(if_tok));
|
||||||
}
|
}
|
||||||
|
} else if (tok->kind == TOK_LBRACKET && (tok + 1)->kind == TOK_FOR) {
|
||||||
|
// 列表推导式: [for var in expr: body]
|
||||||
|
advance(p); advance(p); // 跳过 '[' 和 'for'
|
||||||
|
const Token* vname = expect(p, TOK_IDENT, error, "for 后应为变量名");
|
||||||
|
if (!vname) return NULL;
|
||||||
|
if (!expect(p, TOK_IN, error, "缺少 'in'")) return NULL;
|
||||||
|
AstNode* arr = parse_expr(p, error);
|
||||||
|
if (!arr) return NULL;
|
||||||
|
if (!expect(p, TOK_COLON, error, "缺少 ':'")) return NULL;
|
||||||
|
AstNode* body = parse_expr(p, error);
|
||||||
|
if (!body) return NULL;
|
||||||
|
if (!expect(p, TOK_RBRACKET, error, "缺少 ']'")) return NULL;
|
||||||
|
left = ast_make_list_comp(p->arena,
|
||||||
|
arena_strdup_impl(p->arena, vname->start, vname->length),
|
||||||
|
arr, body, tok_loc(tok));
|
||||||
} else if (tok->kind == TOK_MINUS || tok->kind == TOK_BANG) {
|
} else if (tok->kind == TOK_MINUS || tok->kind == TOK_BANG) {
|
||||||
left = parse_unary(p, error);
|
left = parse_unary(p, error);
|
||||||
} else if (tok->kind == TOK_LPAREN) {
|
} else if (tok->kind == TOK_LPAREN) {
|
||||||
|
|||||||
@@ -204,6 +204,27 @@ AstNode* parse_statement(Parser* p, ErrorInfo* error) {
|
|||||||
return ast_make_return(p->arena, expr, tok_loc(t));
|
return ast_make_return(p->arena, expr, tok_loc(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t->kind == TOK_DEFER) {
|
||||||
|
advance(p);
|
||||||
|
AstNode* body;
|
||||||
|
if (peek(p)->kind == TOK_LBRACE) {
|
||||||
|
body = parse_block(p, error);
|
||||||
|
} else {
|
||||||
|
AstNode* expr = parse_expr(p, error);
|
||||||
|
if (!expr) return NULL;
|
||||||
|
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
|
||||||
|
body = ast_make_block(p->arena,
|
||||||
|
arena_alloc_impl(p->arena, sizeof(AstNode*)),
|
||||||
|
0, tok_loc(t));
|
||||||
|
AstNode** stmts = arena_alloc_impl(p->arena, sizeof(AstNode*));
|
||||||
|
stmts[0] = ast_make_expr_stmt(p->arena, expr, tok_loc(t));
|
||||||
|
body->as.block.stmts = stmts;
|
||||||
|
body->as.block.stmt_count = 1;
|
||||||
|
}
|
||||||
|
if (!body) return NULL;
|
||||||
|
return ast_make_defer_stmt(p->arena, body, tok_loc(t));
|
||||||
|
}
|
||||||
|
|
||||||
// 数组元素赋值: ident[expr] = expr ;
|
// 数组元素赋值: ident[expr] = expr ;
|
||||||
if (t->kind == TOK_IDENT && (t + 1)->kind == TOK_LBRACKET) {
|
if (t->kind == TOK_IDENT && (t + 1)->kind == TOK_LBRACKET) {
|
||||||
int ahead_idx = 2;
|
int ahead_idx = 2;
|
||||||
|
|||||||
@@ -472,6 +472,9 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
|||||||
case AST_EXPR_STMT:
|
case AST_EXPR_STMT:
|
||||||
analyze_expr(node->as.expr_stmt.expr, scope, errors, a);
|
analyze_expr(node->as.expr_stmt.expr, scope, errors, a);
|
||||||
break;
|
break;
|
||||||
|
case AST_DEFER_STMT:
|
||||||
|
analyze_node(node->as.defer_stmt.body, scope, errors, a);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
analyze_expr(node, scope, errors, a);
|
analyze_expr(node, scope, errors, a);
|
||||||
|
|||||||
@@ -536,6 +536,27 @@ SEMA_HANDLER(analyze_node) // if-expr / block 委托
|
|||||||
|
|
||||||
static AstDispatch sema_dispatch;
|
static AstDispatch sema_dispatch;
|
||||||
|
|
||||||
|
static void analyze_list_comp(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||||
|
analyze_expr(node->as.list_comp.array, scope, errors, a);
|
||||||
|
TypeInfo* arr_ti = &node->as.list_comp.array->type;
|
||||||
|
if (arr_ti->kind != TYPE_ARRAY) {
|
||||||
|
error_add(errors, "<sema>", node->loc.line, node->loc.col,
|
||||||
|
"列表推导式需要数组类型, 得到 '%s'", type_name(arr_ti->kind));
|
||||||
|
node->type.kind = TYPE_ERROR; return;
|
||||||
|
}
|
||||||
|
Scope* lc_scope = scope_new(a, scope);
|
||||||
|
TypeKind elem_k = arr_ti->element_type;
|
||||||
|
Symbol* var_sym = scope_insert(lc_scope, a, node->as.list_comp.var_name,
|
||||||
|
SYM_VARIABLE, elem_k);
|
||||||
|
if (var_sym) var_sym->struct_type_name = arr_ti->element_struct_name;
|
||||||
|
analyze_expr(node->as.list_comp.map_expr, lc_scope, errors, a);
|
||||||
|
node->type.kind = TYPE_ARRAY;
|
||||||
|
node->type.element_type = arr_ti->element_type;
|
||||||
|
node->type.element_struct_name = arr_ti->element_struct_name;
|
||||||
|
node->type.array_size = arr_ti->array_size;
|
||||||
|
}
|
||||||
|
SEMA_HANDLER(analyze_list_comp)
|
||||||
|
|
||||||
void analyze_expr_init(void) {
|
void analyze_expr_init(void) {
|
||||||
sema_dispatch.ctx = NULL; // 由 analyze_expr 每次设置
|
sema_dispatch.ctx = NULL; // 由 analyze_expr 每次设置
|
||||||
// 新增表达式节点: 在此注册 handler, 编译器会警告缺失
|
// 新增表达式节点: 在此注册 handler, 编译器会警告缺失
|
||||||
@@ -550,6 +571,7 @@ void analyze_expr_init(void) {
|
|||||||
ast_dispatch_set(&sema_dispatch, AST_METHOD_CALL, analyze_method_call_wrap);
|
ast_dispatch_set(&sema_dispatch, AST_METHOD_CALL, analyze_method_call_wrap);
|
||||||
ast_dispatch_set(&sema_dispatch, AST_IF_STMT, analyze_node_wrap);
|
ast_dispatch_set(&sema_dispatch, AST_IF_STMT, analyze_node_wrap);
|
||||||
ast_dispatch_set(&sema_dispatch, AST_BLOCK, analyze_node_wrap);
|
ast_dispatch_set(&sema_dispatch, AST_BLOCK, analyze_node_wrap);
|
||||||
|
ast_dispatch_set(&sema_dispatch, AST_LIST_COMP, analyze_list_comp_wrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fn main() -> i64 {
|
||||||
|
var x = 10;
|
||||||
|
defer { print_str("deferred"); }
|
||||||
|
print_str("normal");
|
||||||
|
print_i64(x);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
fn main() -> i64 {
|
||||||
|
var src: i64[2] = src;
|
||||||
|
src[0] = 10;
|
||||||
|
src[1] = 20;
|
||||||
|
var dst: i64[2] = dst;
|
||||||
|
dst = [for x in src: x * 2];
|
||||||
|
print_i64(dst[0]); // 20
|
||||||
|
print_i64(dst[1]); // 40
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user