From e5a6616f8bb9b7516d692cd87c05bd72938fb748 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 28 Sep 2026 13:49:28 +0800 Subject: [PATCH] =?UTF-8?q?feat(static):=20static=20=E4=BF=AE=E9=A5=B0?= =?UTF-8?q?=E7=AC=A6=E6=94=B9=E4=B8=BA=E8=AF=AD=E5=8F=A5=E8=B5=B7=E5=A7=8B?= =?UTF-8?q?=E5=89=8D=E7=BD=AE=20+=20=E6=96=B0=E5=A2=9E=20static=20def?= =?UTF-8?q?=EF=BC=88=E6=97=A7=E7=9A=84=E6=B3=A8=E8=A7=A3=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E5=93=8D=E4=BA=AE=E5=A4=B1=E8=B4=A5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vast/Parser.py:ParseStatement 与 _ParseDecorated 新增 static def 分派(判据要求第 2 个 token 是 def,故 static = 5 / static x = 5 不会被误吃成函数定义);新增 _ParseStaticDef,镜像 _ParseExportDef 但**不改写返回注解**、而是在既有装饰器之后合成 @t.CStatic SymbolUtils.py:_TYPE_DESCRIPTOR_MARKERS 删掉 static;新增 _StaticPositionSyntaxError 与 _InStaticOldAnnotationPosition,旧注解位置(名字: static 类型)一律 SyntaxError 并提示前置形式,绝不静默改写;_EXPORT_EXTERN_MODIFIERS 加入 static,_ExpandExportExternVar 新增前置分支——export/extern 追加在类型右侧(或 t.CExport / 或 t.State),static **前置在类型最左**(t.CStatic 加竖线),允许初值;数组前缀展开仍在修饰符展开之前 与 includes/ast/parser.vp 的 pending_static 通道同源:static 名字: 类型 = 值 产出与手写 名字: t.CStatic | 类型、装饰器 @t.CStatic 逐字段同形 --- lib/core/SymbolUtils.py | 191 +++++++++++++++++++++++++++++----------- lib/vast/Parser.py | 68 ++++++++++++++ 2 files changed, 210 insertions(+), 49 deletions(-) diff --git a/lib/core/SymbolUtils.py b/lib/core/SymbolUtils.py index 33ab73e..54a5bef 100644 --- a/lib/core/SymbolUtils.py +++ b/lib/core/SymbolUtils.py @@ -357,12 +357,13 @@ def _ExpandTypedefs(Code: str) -> str: # (BinOp(BitOr, Attribute(t,'CConst'), <类型>)),产出与手写形态逐字段同形。 # # 软关键字边界(唯一识别面 = "注解位置 + token 相邻",与 array 那次同口径): -# const/volatile/static 只在该位置生效——修饰符串的前一个 token 是 `:` 且再前一个是 +# const/volatile 只在该位置生效——修饰符串的前一个 token 是 `:` 且再前一个是 # Name(注解目标:`a:` / `self.x:` / 形参名),或前一个 token 是 `->`(返回注解)。 -# `static` 与另两者同源:ViperOS 驱动广泛写 `pack_head: static uint32 = 0`, -# 注解位置未被消费时会退化成一个叫 static 的"类名"(被建成 opaque 结构体 -# `@a = global %".static" zeroinitializer`,llvm-link 报 invalid type for -# null constant)——故必须与 const/volatile 同路径脱糖为 `t.CStatic | T`。 +# **`static` 已从注解位置迁出**(不再与 const/volatile 同源):注解位置不再接受 +# `名字: static 类型`(如旧的 `pack_head: static uint32 = 0`),必须改写为**语句 +# 起始前置**形式——变量 `static 名字: 类型 = 值`、函数 `static def 名字(...)` +# (见 _ExpandExportExternVar 的 static 前置分支与 vast.Parser._ParseStaticDef); +# 旧注解位置一律**响亮失败**(见下),不再脱糖为 `t.CStatic | T`。 # 非类型位置**原样保留**为普通标识符(不做词法保留字): # - `t.attr.const()`(TransPyV/Test/App/attr_test.vp:142,全仓 .vp 代码内唯一出现) # - `const = 5` / `x = const` / `d = {"k": const}` @@ -370,19 +371,21 @@ def _ExpandTypedefs(Code: str) -> str: # 故 openssl/*.vp 等 C 原型注释里的 `const char *`(全仓 275 处)逐字不变。 # # 非法形态**响亮失败**(SyntaxError,非静默,不丢描述符): -# `a: const`(缺类型)/ `a: const = 1` / `a: const 1`(后随非类型)/ 裸 `const` 语句。 +# `a: const`(缺类型)/ `a: const = 1` / `a: const 1`(后随非类型)/ 裸 `const` 语句; +# **注解位置的 `static`**(如 `memory_regions: static memory_region* = None`): +# 已迁移为前置形式,旧写法一律终止编译。 # 报文含 行:列 + 源码片段 + 期望形态 + 正确示例(文件名由调用方的 SyntaxError # 上报路径补全,与 _ExpandTypedefs / TPV dump_parse_traceback 同约定)。 _TYPE_DESCRIPTOR_MARKERS: dict[str, str] = { - 'const': 'CConst', 'volatile': 'CVolatile', 'static': 'CStatic', + 'const': 'CConst', 'volatile': 'CVolatile', } _DESCRIPTOR_SKIP_TYPES: tuple[int, ...] = (tokenize.COMMENT, tokenize.NL) _DESCRIPTOR_HINT: str = ( - '`名字: const 类型` / `名字: volatile 类型` / `名字: static 类型`' + '`名字: const 类型` / `名字: volatile 类型`' '(可组合:`名字: const volatile 类型`)' ) _DESCRIPTOR_EXAMPLE: str = ( - 'a: const int / a: volatile int / a: static uint32 / a: const volatile t.CInt32T / ' + 'a: const int / a: volatile int / a: const volatile t.CInt32T / ' 'def f(p: const rawptr[Foo]) -> const int' ) @@ -412,12 +415,60 @@ def _TypeDescriptorSyntaxError(Detail: str, Lineno: int, Col: int, Snippet: str) """构造类型描述符非法形态的 fail-fast 报文(行:列 + 源码片段 + 期望形态 + 正确示例)。""" return SyntaxError( f"[TPC] 类型描述符非法({Detail}):行 {Lineno} 列 {Col},源码片段 {Snippet.strip()!r}。" - f"const/volatile/static 是只在**类型位置**生效的软关键字,必须写成 {_DESCRIPTOR_HINT};" + f"const/volatile 是只在**类型位置**生效的软关键字,必须写成 {_DESCRIPTOR_HINT};" f"正确示例:{_DESCRIPTOR_EXAMPLE}。" f"(描述符不会被静默忽略:缺类型 / 后随非类型 / 裸用一律终止编译)" ) +def _StaticPositionSyntaxError(Lineno: int, Col: int, Snippet: str) -> SyntaxError: + """构造旧位置 static(注解位置)的 fail-fast 报文。 + + 注解位置的 `static` 已迁移为**语句起始前置**修饰符(`static 名字: 类型 = 值`); + 旧写法 `名字: static 类型 = 值` 一律终止编译,绝不静默改写。 + """ + return SyntaxError( + f"[TPC] 注解位置的 static 已不再支持:行 {Lineno} 列 {Col}," + f"源码片段 {Snippet.strip()!r}。" + f"请写成前置形式 `static 名字: 类型 = 值`" + f"(等价 `名字: t.CStatic | 类型 = 值`);" + f"正确示例:`static memory_regions: memory_region* = None` / " + f"`static pack_head: uint32 = 0`。" + f"(旧写法 `名字: static 类型` 已删除,绝不静默改写)" + ) + + +def _InStaticOldAnnotationPosition(Tokens: list, Index: int) -> bool: + """`Index` 处的 `static` 是否处于**旧**注解位置(`名字: static 类型` / `-> static 类型`)。 + + 与 _ExpandTypeDescriptors 的注解位置判据同口径,并额外回溯 `const` / `volatile` / + `static` / `|`,以覆盖 `a: const static T` 这类组合旧形态。 + """ + j: int = Index + Guard: int = 0 + while j >= 0 and Guard < 64: + PrevIdx: int = _PrevSignificantTokenIndex(Tokens, j) + if PrevIdx < 0: + return False + Prev = Tokens[PrevIdx] + if Prev.string == '->': + return True + if Prev.string == ':': + BeforeIdx: int = _PrevSignificantTokenIndex(Tokens, PrevIdx) + return BeforeIdx >= 0 and Tokens[BeforeIdx].type == tokenize.NAME + if Prev.string == '|': + j = PrevIdx + Guard += 1 + continue + if Prev.type == tokenize.NAME and ( + Prev.string in _TYPE_DESCRIPTOR_MARKERS or Prev.string == 'static'): + j = PrevIdx + Guard += 1 + continue + return False + return False + + # C-style leading array declarator `const [N]T`: textual desugar into # `t.CArray[T, N]` (same shape as TPV includes/ast/parser.vp:_parse_array_prefix_declarator). _TYPE_BRACKET_OPENERS: frozenset[str] = frozenset({'(', '[', '{'}) @@ -576,13 +627,14 @@ def _AtAnnotationColon(Tokens: list, ColonIdx: int, Stack: list) -> bool: if BoundIdx < 0: return True Bound = Tokens[BoundIdx] - # `export 名字: T` / `extern 名字: T`(变量声明的存储类修饰符,见 - # _ExpandExportExternVar):修饰符与名字之间已构成语句起始,同样算注解位置。 - # 本判据必须在 export/extern 展开**之前**成立——`[N]T` 数组前缀与 + # `export 名字: T` / `extern 名字: T` / `static 名字: T`(变量声明的存储类 + # 修饰符,见 _ExpandExportExternVar):修饰符与名字之间已构成语句起始,同样算 + # 注解位置。本判据必须在修饰符展开**之前**成立——`[N]T` 数组前缀与 # `__attribute__(...)` 两条路径都先于该展开运行,靠它把 - # `export gdt: [7]gdt_entry = []` 正常脱糖成 `export gdt: t.CArray[gdt_entry, 7] = []` - # (若等到展开后再插入 ` | t.CExport`,`|` 不在 _TYPE_EXPR_STOP_TOKENS 中, - # 会被并进数组元素类型 → `t.CArray[gdt_entry | t.CExport, 7]`)。 + # `export gdt: [7]gdt_entry = []` / `static g: [7]int = []` 正常脱糖成 + # `t.CArray[...]` 形态(若等到展开后再插入 ` | t.CExport` / 前置 `t.CStatic | `, + # `|` 不在 _TYPE_EXPR_STOP_TOKENS 中,会被并进数组元素类型 → + # `t.CArray[gdt_entry | t.CExport, 7]`)。 if Bound.type == tokenize.NAME and Bound.string in _EXPORT_EXTERN_MODIFIERS: return True return Bound.type in _ARRAY_STMT_BOUNDARY or Bound.string == ';' @@ -677,25 +729,32 @@ def _ExpandArrayPrefixAnnotations(Code: str) -> str: # --------------------------------------------------------------------------- -# 变量声明的存储类修饰符 export / extern(语句级软关键字)——与 TPV -# includes/ast/parser.vp:_parse_export_extern_var **同一标记、同一消费路径**: +# 变量声明的存储类修饰符 export / extern / static(语句级软关键字)——与 TPV +# includes/ast/parser.vp **同一标记、同一消费路径**: # export 名字: T [= 初值] → 名字: T | t.CExport [= 初值] # (本模块**定义**:定义端裸名,不加模块 SHA1 头;内联汇编 / C 符号对接必需。 # 无初值时按既有零初始化全局定义处理,如 `export tss_buf: [104]uint8`。) # extern 名字: T → 名字: T | t.State # (**仅声明**:t.State = t.CExtern | t.CExport ⇒ 定义端 `@裸名 = external global T`。 # extern 是外部定义,**不允许**初值 ⇒ 带 `= 初值` 一律终止编译。) -# 与函数形态(`export def f()` / `export f()` / `extern def f()`,vast 既有处理) -# 由第三个 token 区分:`:` 是变量,`(` / `[` 是函数 ⇒ 函数语义逐字不变。 -# `export` / `extern` 不在任何 .vp 源码中作标识符(仅本语法与注释使用)。 +# static 名字: T [= 初值] → 名字: t.CStatic | T [= 初值] +# (存储类标记**前置**在类型联合最左,与 TPV `_ParseStaticModified` 的 +# `pending_static` 通道同源——`static 名字: T` → `名字: t.CStatic | T`;允许初值。 +# 产出与手写 `名字: t.CStatic | T` / 装饰器 `@t.CStatic` 逐字段同形。 +# 旧注解位置写法 `名字: static T` 已删除,见 _StaticPositionSyntaxError。) +# 与函数形态(`export def f()` / `export f()` / `extern def f()` / `static def f()`, +# vast 既有处理)由第三个 token 区分:`:` 是变量,`(` / `[` 是函数 ⇒ 函数语义逐字不变。 +# `export` / `extern` / `static` 不在任何 .vp 源码中作标识符(仅本语法与注释使用)。 # --------------------------------------------------------------------------- -_EXPORT_EXTERN_MODIFIERS: frozenset[str] = frozenset({'export', 'extern'}) +_EXPORT_EXTERN_MODIFIERS: frozenset[str] = frozenset({'export', 'extern', 'static'}) _EXPORT_EXTERN_HINT: str = ( '`export 名字: 类型 [= 初值]`(裸名导出,等价 `名字: 类型 | t.CExport`);' - '`extern 名字: 类型`(仅声明,等价 `名字: 类型 | t.State`,**不允许初值**)' + '`extern 名字: 类型`(仅声明,等价 `名字: 类型 | t.State`,**不允许初值**);' + '`static 名字: 类型 [= 初值]`(等价 `名字: t.CStatic | 类型`)' ) _EXPORT_EXTERN_EXAMPLE: str = ( - 'export gdt: [7]gdt_entry = [] / export tss_buf: [104]uint8 / extern a: int' + 'export gdt: [7]gdt_entry = [] / export tss_buf: [104]uint8 / extern a: int / ' + 'static memory_regions: memory_region* = None' ) @@ -711,22 +770,26 @@ def _ExportExternSyntaxError(Detail: str, Lineno: int, Col: int, def _ExpandExportExternVar(Code: str) -> str: - """把 `export 名字: T [= 初值]` / `extern 名字: T` 展开为带存储类标记的注解。 + """把 `export 名字: T [= 初值]` / `extern 名字: T` / `static 名字: T [= 初值]` + 展开为带存储类标记的注解。 - 与 TPV `_parse_export_extern_var` 同口径:export → `| t.CExport`; - extern → `| t.State`;extern 带初值 ⇒ **响亮失败**(SyntaxError)。 + 与 TPV 同口径:export → 类型**右侧追加** `| t.CExport`;extern → 追加 `| t.State` + (extern 带初值 ⇒ **响亮失败** SyntaxError);static → 类型**左侧前置** `t.CStatic | ` + (与 TransPyV `_ParseStaticModified` / `pending_static` 通道同源——`static 名字: T` + → `名字: t.CStatic | T`,亦与手写 `名字: t.CStatic | T` / `@t.CStatic` 逐字段同形; + static **允许**初值)。 - - 只在"语句起始(可缩进)+ export/extern + 标识符 + `:`"形态触发;函数形态 - (`export def f()` / `export f()` / `extern def f()`)第三个 token 不是 `:` - ⇒ 不命中,vast 的既有函数处理逐字不变。 + - 只在"语句起始(可缩进)+ export/extern/static + 标识符 + `:`"形态触发;函数形态 + (`export def f()` / `export f()` / `extern def f()` / `static def f()`)第三个 + token 不是 `:` ⇒ 不命中,vast 的既有函数处理逐字不变。 - **必须排在 `_ExpandArrayPrefixAnnotations` 之后**:此时注解已是规范形态 (`t.CArray[T, N]` / `t.CConst | ...`),插入点由 `_ScanAnnotationTypeEnd` 确定;`|` 不在 `_TYPE_EXPR_STOP_TOKENS` 中,若在数组前缀展开前插入会被 并进数组元素类型(`t.CArray[gdt_entry | t.CExport, 7]`)。数组前缀之所以 - 仍能脱糖,靠的是 `_AtAnnotationColon` 已把 export/extern 认作语句边界。 - - 同行编辑(删修饰符 + 插标记),不增删换行 ⇒ 行号映射保持有效。 + 仍能脱糖,靠的是 `_AtAnnotationColon` 已把 export/extern/static 认作语句边界。 + - 同行编辑(删修饰符 + 插/前置标记),不增删换行 ⇒ 行号映射保持有效。 """ - if 'export' not in Code and 'extern' not in Code: + if 'export' not in Code and 'extern' not in Code and 'static' not in Code: return Code try: Tokens: list = list(tokenize.generate_tokens(io.StringIO(Code).readline)) @@ -755,6 +818,7 @@ def _ExpandExportExternVar(Code: str) -> str: raise _ExportExternSyntaxError( '缺少类型注解', Line, Tok.start[1] + 1, Snippet) IsExtern: bool = Tok.string == 'extern' + IsStatic: bool = Tok.string == 'static' AfterIdx: int = _NextSignificantTokenIndex(Tokens, TypeEnd - 1) if (IsExtern and AfterIdx >= 0 and Tokens[AfterIdx].string == '='): @@ -767,10 +831,19 @@ def _ExpandExportExternVar(Code: str) -> str: DelEnd: int = NameTok.start[1] DelOrig: str = Snippet[DelStart:DelEnd] Edits.append((Line, DelStart, DelEnd, '', DelOrig)) - # 编辑 2:在注解类型终点插入存储类标记。 - InsAt: tuple[int, int] = Tokens[TypeEnd - 1].end - Marker: str = ' | t.State' if IsExtern else ' | t.CExport' - Edits.append((InsAt[0], InsAt[1], InsAt[1], Marker, '')) + if IsStatic: + # 编辑 2(static):存储类标记**前置**在类型左侧(联合最左)。 + # 与 TransPyV `_ParseStaticModified` / `pending_static` 通道 + # 逐字同形:`static 名字: T` → `名字: t.CStatic | T`,产出与 + # 手写 `名字: t.CStatic | T` / `@t.CStatic` 逐字段同形。 + InsAt: tuple[int, int] = Tokens[TypeStart].start + Edits.append((InsAt[0], InsAt[1], InsAt[1], 't.CStatic | ', '')) + else: + # 编辑 2(export/extern):存储类标记**追加**在注解类型终点 + # (右侧):export → `| t.CExport`;extern → `| t.State`。 + InsAt = Tokens[TypeEnd - 1].end + Marker: str = ' | t.State' if IsExtern else ' | t.CExport' + Edits.append((InsAt[0], InsAt[1], InsAt[1], Marker, '')) i = TypeEnd continue i += 1 @@ -1016,11 +1089,16 @@ def _ExpandAttributeDescriptors(Code: str) -> str: def _ExpandTypeDescriptors(Code: str) -> str: - """把 `const T` / `volatile T` / `static T`(含组合、任意顺序)展开为 `t.CConst | T` 等形态(行号不变)。 + """把 `const T` / `volatile T`(含组合、任意顺序)展开为 `t.CConst | T` 等形态(行号不变)。 - 词法级切分(`tokenize`):注释/字符串内容天然不参与,不会被误改写。 - 只在"注解位置"(前一个 token 是 `:` 且再前一个是 Name,或前一个 token 是 `->`) 识别描述符串;非类型位置原样保留为普通标识符(软关键字边界)。 + - **`static` 不再属于本展开器**(已迁出注解位置):注解位置出现 `static` + (如 `memory_regions: static memory_region* = None`)一律**响亮失败** + (_StaticPositionSyntaxError);前置形式 `static 名字: 类型 = 值` 由 + _ExpandExportExternVar 处理,`static def` 由 vast.Parser._ParseStaticDef 处理。 + 入口的 `'static' not in Code` 判据保留,仅为让上述旧位置能被扫描到并报错。 - 只做**同行**替换(不增删换行 ⇒ 行号映射保持有效,与 fn/enum/define/typedef 同约定)。 - 词法失败(未闭合字符串等)时原样返回:该输入在后续 ast.parse 处必然响亮失败, 本层不新增第二套错误通道(不静默丢描述符:词法都没过,描述符根本没被识别为描述符)。 @@ -1039,6 +1117,15 @@ def _ExpandTypeDescriptors(Code: str) -> str: i: int = 0 while i < n: Tok = Tokens[i] + # 旧的注解位置 static(`名字: static 类型`):已迁移为**前置**形式,此处 + # 响亮失败(不脱糖、不静默)。注意 `static 名字: 类型` / `static def 名字` + # 的 static 位于**语句起始**、不在注解位置,故不会被本判据命中(交由 + # _ExpandExportExternVar / vast.Parser._ParseStaticDef 处理)。 + if (Tok.type == tokenize.NAME and Tok.string == 'static' + and _InStaticOldAnnotationPosition(Tokens, i)): + raise _StaticPositionSyntaxError( + Tok.start[0], Tok.start[1], + Code.splitlines()[Tok.start[0] - 1]) if Tok.type == tokenize.NAME and Tok.string in _TYPE_DESCRIPTOR_MARKERS: Run: list = [] j: int = i @@ -1441,7 +1528,8 @@ def ExpandSoftKeywords(Code: str) -> str: 5) 类型描述符 `const T` / `volatile T` → `t.CConst | T` / `t.CVolatile | T`: 与手写 `t.CConst | T` 产出**同一 AST/同一解析路径**(见 _ExpandTypeDescriptors)。 只在注解位置生效的软关键字(`t.attr.const()` 等非类型位置原样保留); - 缺类型 / 后随非类型 / 裸用**响亮失败**(SyntaxError)。 + 缺类型 / 后随非类型 / 裸用**响亮失败**(SyntaxError)。`static` 已从注解位置 + 迁出——注解位置出现 `static`(`名字: static 类型`)**响亮失败**。 6) `union NAME:` → `class NAME(t.CUnion):`:与手写 `class NAME(t.CUnion):` 产出 **同一 AST/同一注册路径**(见 _ExpandUnionBlocks)。成员为普通注解字段。 行首 `union` 的非 `union 名字:` 形态**响亮失败**(该词不在任何源码中作标识符)。 @@ -1454,9 +1542,12 @@ def ExpandSoftKeywords(Code: str) -> str: `class 变体:` + 无载荷赋值)。行首 `renum` 的非 `renum 名字:` 形态**响亮失败** (该词不在任何源码中作标识符)。 9) `export 名字: T [= 初值]` → `名字: T | t.CExport [= 初值]`; - `extern 名字: T` → `名字: T | t.State`(见 _ExpandExportExternVar)。 - 与 TPV `_parse_export_extern_var` 同一标记、同一消费路径;函数形态 - (`export def f()` / `export f()` / `extern def f()`)不受影响; + `extern 名字: T` → `名字: T | t.State`;`static 名字: T [= 初值]` → + `名字: t.CStatic | T [= 初值]`(见 _ExpandExportExternVar)。 + 与 TPV 同一标记、同一消费路径;export/extern 在类型右侧追加标记,static 在 + 类型左侧前置标记(与 TPV `_ParseStaticModified` 的 `pending_static` 同源); + 函数形态(`export def f()` / `export f()` / `extern def f()` / `static def f()`, + 后者由 vast.Parser._ParseStaticDef 处理)不受影响; `extern` 带初值**响亮失败**(外部定义不写初值)。 九种展开都同行替换(长度可增,不增删换行),AST 行号映射保持有效。 """ @@ -1493,19 +1584,21 @@ def _ExpandSoftKeywordsImpl(Code: str) -> str: # 且它自身产出的 `t.attr.X |` 不会干扰紧随的 const/volatile 展开。 if _ATTRIBUTE_CALLEE in Code: Code = _ExpandAttributeDescriptors(Code) - # static 与 const/volatile 同为注解位置的存储类描述符(`名字: static uint32 = 0`, - # ViperOS 驱动广泛使用);三者共用同一展开器与同一 marker 表。 + # const/volatile 是注解位置的存储类描述符;`static` 已从注解位置迁出为**前置** + # 修饰符(`static 名字: 类型 = 值`),本层进入 _ExpandTypeDescriptors 只为让旧位置 + # `名字: static 类型` 能被扫描到并**响亮失败**(见 _StaticPositionSyntaxError)。 if 'const' in Code or 'volatile' in Code or 'static' in Code: Code = _ExpandTypeDescriptors(Code) # 裸 `[N]T` 数组前缀在描述符之后:`const [N]T` 已由 _ExpandTypeDescriptors 消化为 # `t.CConst | t.CArray[T, N]`(此处不再有注解位置的裸 '['),避免两条路径重复改写。 if '[' in Code: Code = _ExpandArrayPrefixAnnotations(Code) - # export / extern 变量声明(语句级软关键字):必须排在**最后**——此时注解已由 - # 数组前缀 / 描述符两层脱糖成规范形态(`t.CArray[T, N]` / `t.CConst | ...`), - # 本层只删修饰符 + 在注解类型终点插入存储类标记(`| t.CExport` / `| t.State`)。 - # 顺序若反过来,`|` 会被数组前缀展开并进元素类型(见 _ExpandExportExternVar)。 - if 'export' in Code or 'extern' in Code: + # export / extern / static 变量声明(语句级软关键字):必须排在**最后**——此时注解 + # 已由数组前缀 / 描述符两层脱糖成规范形态(`t.CArray[T, N]` / `t.CConst | ...`), + # 本层只删修饰符 + 插入存储类标记(export/extern 右追加 `| t.CExport` / `| t.State`; + # static 左前置 `t.CStatic | `)。顺序若反过来,`|` 会被数组前缀展开并进元素类型 + # (见 _ExpandExportExternVar)。 + if 'export' in Code or 'extern' in Code or 'static' in Code: Code = _ExpandExportExternVar(Code) return Code diff --git a/lib/vast/Parser.py b/lib/vast/Parser.py index 6336141..7519cbb 100644 --- a/lib/vast/Parser.py +++ b/lib/vast/Parser.py @@ -108,6 +108,14 @@ class Parser(ExprParserMixin): # 必须在软关键字 def 分派之前 if v == 'export': return self._ParseExportDef() + # static 存储类软关键字(已从"注解位置"迁出为**语句起始前置**修饰符): + # 仅 `static def 名字` 形态判定为函数定义——判据必须同时要求第二个 token + # 是 `def`,故 `static = 5` / `static x = 5` 不会被误吃成函数定义。 + # 变量形式 `static 名字: 类型 = 值` 不在本层处理,由 SymbolUtils 的前置 + # 修饰符展开统一脱糖为 `名字: t.CStatic | 类型 = 值`。 + if (v == 'static' and self._Peek(1).Type == NAME + and self._Peek(1).Value == 'def'): + return self._ParseStaticDef() # define 宏函数定义(与 def 语义一致,返回注解自动追加 t.CDefine # 标记为宏函数;软关键字:仅"define + 标识符"形态才判定为函数定义, # 变量名/调用(define = 5、define(x))不受影响)——必须在软关键字 @@ -565,6 +573,9 @@ class Parser(ExprParserMixin): return self._ParseExternDef(decorators=decorator_list) if tok.Type == NAME and tok.Value == 'export': return self._ParseExportDef(decorators=decorator_list) + if (tok.Type == NAME and tok.Value == 'static' and self._Peek(1).Type == NAME + and self._Peek(1).Value == 'def'): + return self._ParseStaticDef(decorators=decorator_list) if tok.Type == NAME and tok.Value == 'define': return self._ParseDefineDef(decorators=decorator_list) if tok.Type == NAME and tok.Value == 'def': @@ -772,6 +783,63 @@ class Parser(ExprParserMixin): self._FixLoc(node, start) return node + def _ParseStaticDef(self, decorators: list[N.expr] | None = None) -> N.FunctionDef: + """解析 static 函数定义(等价 ``@t.CStatic``,与 TransPyV 的 + `_ParseStaticModified` 同源)。 + + 允许语法(与 export/extern 对称,配不配 def 都一样): + static def A(x: int) -> int: ... + static A(x: int) -> int: ... + + 与 export/extern 的**两处不同**: + - **不改写返回注解**(不追加 `| t.CStatic` / `| t.State`):CStatic 是 + 函数属性,由下面的合成装饰器承载,返回类型语义逐字不变; + - **合成 `@t.CStatic` 装饰器**追加在既有装饰器之后,产出与**手写 + `@t.CStatic`** 逐字段同形(decorator_list 多一个 + Attribute(Name('t', Load), 'CStatic', Load)),下游零新增判据。 + + 另设自定义属性 ``Static = True`` 供 Unparser 还原 static 语法 + (镜像 Extern/Export;因 FunctionDef 的 __slots__ 槽位未含 Static 且 + 补槽位需改第三个文件,此处仅在槽位存在时设置,解析不会因此中断)。 + """ + start: Token = self._Next() # 'static' + if self._AtName('def'): + self._Next() + name_tok: Token = self._ExpectName() + type_params: list[N.AST] = [] + if self._AtOp('['): + type_params = self._ParseTypeParams() + args: N.arguments = self._ParseArguments() + returns: N.expr | None = None + if self._AtOp('->'): + self._Next() + returns = self._ParseTypeAnnotation() + body: list[N.stmt] = [] + if self._AtOp(':'): + self._Next() + body = self._ParseSuite() + # 合成 @t.CStatic 装饰器(追加在既有装饰器之后) + static_attr: N.expr = N.Attribute(value=N.Name(id='t', ctx=N.Load()), + attr='CStatic', ctx=N.Load()) + self._FixLoc(static_attr, start) + deco_list: list[N.expr] = list(decorators or []) + deco_list.append(static_attr) + node: N.FunctionDef = N.FunctionDef( + name=name_tok.Value, args=args, body=body, + decorator_list=deco_list, returns=returns, + type_comment=None, type_params=type_params, + ) + # 自定义属性 Static = True 供 Unparser 还原 static 语法(镜像 Extern/Export)。 + # 注:FunctionDef 是 __slots__ 类(见 vast/Nodes.py 的 _FUNC_ATTRS,当前槽位 + # 为 Extern/Export/Define,未含 Static)——补槽位需改第三个文件(本次不许可), + # 故仅在槽位存在时设置,避免 AttributeError 中断解析;下游对 static 函数的 + # 识别靠上面合成的 @t.CStatic 装饰器(HandlesFunctions 的存储类装饰器分支), + # 与 virtual/novirtual 仅合成装饰器同构。 + if hasattr(type(node), 'Static'): + node.Static = True + self._FixLoc(node, start) + return node + def _ParseDefineDef(self, decorators: list[N.expr] | None = None) -> N.FunctionDef: """解析 define 宏函数定义(语法与 def 完全一致,但固定为宏函数)。