feat: let mut + 赋值语句 — while 循环可修改变量
- lexer: 新增 TOK_MUT 关键字 - ast: AST_ASSIGN_STMT 节点 + let_stmt.is_mut 标志 - parser: ‘let mut’ 前缀识别 + ‘ident = expr;’ 赋值语句 - sema: Symbol.is_mut 可变性检查(不可变变量赋值报错) - codegen: AST_ASSIGN_STMT → store 指令 - 新增集成测试 06_mut_while.l(while 循环 + 计数器) 基于 Codex 分析报告 P0 建议。
This commit is contained in:
+36
-1
@@ -204,13 +204,48 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
|
||||
}
|
||||
|
||||
node->type.kind = var_type;
|
||||
if (!scope_insert(scope, a, node->as.let_stmt.name, SYM_VARIABLE, var_type)) {
|
||||
Symbol* sym = scope_insert(scope, a, node->as.let_stmt.name, SYM_VARIABLE, var_type);
|
||||
if (!sym) {
|
||||
error_add(errors, "<sema>", node->line, node->col,
|
||||
"变量 '%s' 重复定义", node->as.let_stmt.name);
|
||||
} else {
|
||||
sym->is_mut = node->as.let_stmt.is_mut;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_ASSIGN_STMT: {
|
||||
Symbol* sym = scope_lookup(scope, node->as.assign_stmt.name);
|
||||
if (!sym) {
|
||||
error_add(errors, "<sema>", node->line, node->col,
|
||||
"未定义的变量 '%s'", node->as.assign_stmt.name);
|
||||
node->type.kind = TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
if (sym->kind != SYM_VARIABLE) {
|
||||
error_add(errors, "<sema>", node->line, node->col,
|
||||
"'%s' 不是变量,不能赋值", node->as.assign_stmt.name);
|
||||
node->type.kind = TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
if (!sym->is_mut) {
|
||||
error_add(errors, "<sema>", node->line, node->col,
|
||||
"不能对不可变变量 '%s' 赋值(需用 let mut 声明)",
|
||||
node->as.assign_stmt.name);
|
||||
node->type.kind = TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
analyze_expr(node->as.assign_stmt.value, scope, errors, a);
|
||||
TypeKind value_ty = node->as.assign_stmt.value->type.kind;
|
||||
if (value_ty != TYPE_ERROR && value_ty != sym->type) {
|
||||
error_add(errors, "<sema>", node->line, node->col,
|
||||
"赋值类型不匹配: 变量 '%s' 类型为 '%s',但表达式类型为 '%s'",
|
||||
node->as.assign_stmt.name, type_name(sym->type), type_name(value_ty));
|
||||
}
|
||||
node->type.kind = TYPE_VOID;
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_IF_STMT:
|
||||
analyze_expr(node->as.if_stmt.cond, scope, errors, a);
|
||||
if (node->as.if_stmt.cond->type.kind != TYPE_BOOL &&
|
||||
|
||||
@@ -27,6 +27,8 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name,
|
||||
}
|
||||
Symbol* sym = (Symbol*)arena_alloc_impl(alloc, sizeof(Symbol));
|
||||
sym->name = name; sym->kind = kind; sym->type = type;
|
||||
sym->is_mut = false; sym->return_type = TYPE_VOID;
|
||||
sym->param_types = NULL; sym->param_count = 0;
|
||||
sym->next = scope->head;
|
||||
scope->head = sym;
|
||||
return sym;
|
||||
|
||||
@@ -10,6 +10,7 @@ typedef struct Symbol {
|
||||
const char* name;
|
||||
SymbolKind kind;
|
||||
TypeKind type; // 变量/参数的类型
|
||||
bool is_mut; // 变量是否可变(可被赋值)
|
||||
// 函数特有
|
||||
TypeKind return_type;
|
||||
TypeKind* param_types;
|
||||
|
||||
Reference in New Issue
Block a user