feat: const 编译期常量 — const N = 42;

Token(77): +TOK_CONST, AST_LET_STMT 新增 is_const, Symbol 新增 const_value
sema: 字面量初始化自动折叠为编译期常量值

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 14:26:59 +08:00
parent f7710ede9d
commit 0a0667776a
8 changed files with 19 additions and 8 deletions
+1
View File
@@ -67,6 +67,7 @@ AstNode* ast_make_let(void* alloc, const char* name, TypeKind annot_type, bool h
NEW(alloc, AST_LET_STMT);
n->as.let_stmt.name = name; n->as.let_stmt.annot_type = annot_type;
n->as.let_stmt.has_type_annot = has_type_annot; n->as.let_stmt.is_mut = is_mut;
n->as.let_stmt.is_const = false;
n->as.let_stmt.init = init;
n->as.let_stmt.struct_type_name = struct_type_name;
n->as.let_stmt.annot_element_type = annot_elem_type;
+1 -1
View File
@@ -78,7 +78,7 @@ struct AstNode {
// AST_BLOCK
struct { struct AstNode** stmts; size_t stmt_count; } block;
// AST_LET_STMT
struct { const char* name; TypeKind annot_type; bool has_type_annot; bool is_mut; struct AstNode* init;
struct { const char* name; TypeKind annot_type; bool has_type_annot; bool is_mut; bool is_const; struct AstNode* init;
const char* struct_type_name;
TypeKind annot_element_type; const char* annot_element_struct_name; int64_t annot_array_size; } let_stmt;
// AST_ASSIGN_STMT
+1
View File
@@ -57,6 +57,7 @@ static TokenKind check_keyword(const Token* tok) {
KW("fn", TOK_FN); KW("let", TOK_LET);
KW("var", TOK_VAR);
KW("if", TOK_IF); KW("else", TOK_ELSE); KW("guard", TOK_GUARD);
KW("const", TOK_CONST);
KW("while", TOK_WHILE); KW("for", TOK_FOR); KW("in", TOK_IN);
KW("to", TOK_TO); KW("step", TOK_STEP);
KW("return", TOK_RETURN);
+1 -1
View File
@@ -5,7 +5,7 @@
#include <inttypes.h>
static const char* NAMES[] = {
[TOK_FN] = "fn", [TOK_LET] = "let", [TOK_VAR] = "var", [TOK_IF] = "if", [TOK_GUARD] = "guard",
[TOK_FN] = "fn", [TOK_LET] = "let", [TOK_VAR] = "var", [TOK_CONST] = "const", [TOK_IF] = "if", [TOK_GUARD] = "guard",
[TOK_PUB] = "pub", [TOK_MOD] = "mod", [TOK_USE] = "use",
[TOK_TRAIT] = "trait", [TOK_SELF] = "Self",
[TOK_ELSE] = "else", [TOK_WHILE] = "while", [TOK_FOR] = "for", [TOK_IN] = "in", [TOK_RETURN] = "return",
+1 -1
View File
@@ -6,7 +6,7 @@
// === Token 类型枚举 ===
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_CONST, TOK_IF, TOK_ELSE, TOK_WHILE, TOK_FOR, TOK_IN, TOK_RETURN, TOK_GUARD,
TOK_STRUCT, TOK_TYPE, TOK_ENUM, TOK_EXTEND, TOK_DEFER, TOK_MATCH, TOK_PUB, TOK_MOD, TOK_USE,
TOK_TRAIT, TOK_SELF,
// 类型关键字
+8 -5
View File
@@ -118,10 +118,11 @@ AstNode* parse_block(Parser* p, ErrorInfo* error) {
AstNode* parse_statement(Parser* p, ErrorInfo* error) {
const Token* t = peek(p);
if (t->kind == TOK_LET || t->kind == TOK_VAR) {
bool is_mut = (advance(p)->kind == TOK_VAR);
const Token* name = expect(p, TOK_IDENT, error,
is_mut ? "var 后应为变量名" : "let 后应为变量名");
if (t->kind == TOK_LET || t->kind == TOK_VAR || t->kind == TOK_CONST) {
TokenKind decl_kind = advance(p)->kind;
bool is_mut = (decl_kind == TOK_VAR);
bool is_const = (decl_kind == TOK_CONST);
const Token* name = expect(p, TOK_IDENT, error, "变量名");
if (!name) return NULL;
// 可选的类型标注
TypeKind annot_type = TYPE_UNKNOWN;
@@ -144,10 +145,12 @@ AstNode* parse_statement(Parser* p, ErrorInfo* error) {
AstNode* init = parse_expr(p, error);
if (!init) return NULL;
if (!expect(p, TOK_SEMICOLON, error, "缺少 ';'")) return NULL;
return ast_make_let(p->arena,
AstNode* let_node = ast_make_let(p->arena,
arena_strdup_impl(p->arena, name->start, name->length),
annot_type, has_type_annot, is_mut, init, struct_type_name,
annot_elem_type, annot_elem_struct, annot_arr_size, tok_loc(t));
let_node->as.let_stmt.is_const = is_const;
return let_node;
}
if (t->kind == TOK_IF) {
+4
View File
@@ -319,6 +319,10 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
"变量 '%s' 重复定义", node->as.let_stmt.name);
} else {
sym->is_mut = node->as.let_stmt.is_mut;
sym->is_const = node->as.let_stmt.is_const;
if (node->as.let_stmt.is_const && node->as.let_stmt.init->kind == AST_LITERAL_EXPR) {
sym->const_value = node->as.let_stmt.init->as.literal.i64_val;
}
if (var_struct_name) {
sym->type = TYPE_STRUCT;
sym->struct_type_name = var_struct_name;
+2
View File
@@ -11,6 +11,8 @@ typedef struct Symbol {
SymbolKind kind;
TypeKind type; // 变量/参数的类型
bool is_mut; // 变量是否可变(可被赋值)
bool is_const; // 编译期常量 (const 声明)
int64_t const_value; // 编译期常量值
// 函数特有
TypeKind return_type;
const char* return_struct_type_name; // 返回类型为 struct 时的类型名