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:
2026-06-05 00:42:50 +08:00
parent f8c5e18188
commit bd02a4989e
11 changed files with 88 additions and 8 deletions
+36 -1
View File
@@ -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 &&
+2
View File
@@ -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;
+1
View File
@@ -10,6 +10,7 @@ typedef struct Symbol {
const char* name;
SymbolKind kind;
TypeKind type; // 变量/参数的类型
bool is_mut; // 变量是否可变(可被赋值)
// 函数特有
TypeKind return_type;
TypeKind* param_types;