From 06c8773fac415fed01454c71bbc1403dd0f3bb9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Sun, 7 Jun 2026 14:00:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A3=85=E9=A5=B0=E5=99=A8=20#[attr]?= =?UTF-8?q?=20=E8=AF=AD=E6=B3=95=20=E2=80=94=20parser=20=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E5=B9=B6=E8=B7=B3=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Token(74): +TOK_HASH, lexer 识别 '#', parser 在 fn/struct/enum 前解析 #[ident] 语法就位, 后续可扩展存储属性到 AST 节点 Co-Authored-By: Claude Opus 4.7 --- src/lexer/lexer.c | 1 + src/lexer/token.c | 2 +- src/lexer/token.h | 2 +- src/parser/parser.c | 7 +++++++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index eb4b81e..1e207e7 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -158,6 +158,7 @@ Token* lex(Arena* a, const char* source, const char* filename, else if (c == '.') { tokens[idx++] = make_token(&l, TOK_DOT, l.pos, 1); advance(&l); } else if (c == '[') { tokens[idx++] = make_token(&l, TOK_LBRACKET, l.pos, 1); advance(&l); } else if (c == ']') { tokens[idx++] = make_token(&l, TOK_RBRACKET, l.pos, 1); advance(&l); } + else if (c == '#') { tokens[idx++] = make_token(&l, TOK_HASH, l.pos, 1); advance(&l); } else if (c == '(') { tokens[idx++] = make_token(&l, TOK_LPAREN, l.pos, 1); advance(&l); } else if (c == ')') { tokens[idx++] = make_token(&l, TOK_RPAREN, l.pos, 1); advance(&l); } else if (c == '{') { tokens[idx++] = make_token(&l, TOK_LBRACE, l.pos, 1); advance(&l); } diff --git a/src/lexer/token.c b/src/lexer/token.c index ef77300..e1ae531 100644 --- a/src/lexer/token.c +++ b/src/lexer/token.c @@ -29,7 +29,7 @@ static const char* NAMES[] = { [TOK_LBRACKET] = "[", [TOK_RBRACKET] = "]", [TOK_COMMA] = ",", [TOK_COLON] = ":", [TOK_SEMICOLON] = ";", [TOK_ASSIGN] = "=", - [TOK_DOT] = ".", [TOK_COLON_COLON] = "::", + [TOK_DOT] = ".", [TOK_COLON_COLON] = "::", [TOK_HASH] = "#", [TOK_EOF] = "EOF", [TOK_ERROR] = "错误", }; diff --git a/src/lexer/token.h b/src/lexer/token.h index 0682065..9c13a9a 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -26,7 +26,7 @@ typedef enum { TOK_LBRACKET, TOK_RBRACKET, TOK_COMMA, TOK_COLON, TOK_SEMICOLON, TOK_ASSIGN, // 特殊 - TOK_DOT, TOK_COLON_COLON, + TOK_DOT, TOK_COLON_COLON, TOK_HASH, TOK_EOF, TOK_ERROR, } TokenKind; diff --git a/src/parser/parser.c b/src/parser/parser.c index f2fc057..4a6c76a 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -413,6 +413,13 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count, if (peek(&p)->kind == TOK_PUB) { is_pub = true; advance(&p); } + // 装饰器 #[attr] + while (peek(&p)->kind == TOK_HASH) { + advance(&p); // 跳过 # + if (!expect(&p, TOK_LBRACKET, error, "# 后应为 '['")) return NULL; + if (!expect(&p, TOK_IDENT, error, "装饰器名")) return NULL; + if (!expect(&p, TOK_RBRACKET, error, "缺少 ']'")) return NULL; + } if (peek(&p)->kind == TOK_TRAIT) { const Token* tt = advance(&p); const Token* tname = expect(&p, TOK_IDENT, error, "trait 后应为接口名");