feat(parser): 支持 Viper 软关键字 fn/fun/func/function 展开为 def

行首缩进+软关键字+空白+标识符形态的函数定义(fn foo(): / function bar())
展开为 def,行号不变,供 ast.parse 使用;变量名/调用/注解中的 fn 不受影响。
Converter 同步改为 stub 语法错误直接终止(fail-fast),不再生成残缺 vpi
被全局缓存命中后以 undefined symbol 形式爆发。
This commit is contained in:
TermiNexus committed 2026-08-13 07:51:21 +08:00
1 parent 6a672037c2
commit a99f126cfa
6 files changed
+48 -11

No files matched your search

+19
View File
@@ -1,10 +1,29 @@
"""共享工具函数:符号表处理中使用的 AST 分析工具"""
from __future__ import annotations
import ast
import re
from lib.includes import t
_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__})
# Viper 软关键字 fn/fun/func/function 是 def 的别名(行首 + 空白 + 标识符才算函数定义,
# 变量名/调用/注解中的 fn 不受影响)。展开为 def 后行号不变,供 ast.parse 使用。
_SOFT_KEYWORD_RE: re.Pattern[str] = re.compile(
r'^(\s*)(function|func|fun|fn)(\s+)(?=[A-Za-z_])', re.MULTILINE
)
def ExpandSoftKeywords(Code: str) -> str:
"""将 Viper 软关键字 fn/fun/func/function 展开为 def(函数定义行)。
仅在"行首缩进 + 关键字 + 空白 + 标识符"的函数定义形态匹配,
变量名(fn = 5)、调用(fn(x))、注解(x: fn)与字符串内容不受影响。
展开为 def 与关键字等宽或更短,行号不变,AST 行号映射保持有效。
"""
if not Code:
return Code
return _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code)
def IsTModule(module_id: str, symtable: object | None = None) -> bool:
"""检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)"""
+4 -1
View File
@@ -9,7 +9,7 @@ from typing import Any
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName, ExpandSoftKeywords
from lib.includes import t
from lib.includes.t import CType, CEnum
from lib.constants.config import mode as _config_mode
@@ -197,6 +197,7 @@ class AnnotationLoaderMixin:
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content: str = f.read()
ann_content = ExpandSoftKeywords(ann_content)
ann_tree: ast.Module = ast.parse(ann_content)
for node in ann_tree.body:
if isinstance(node, ast.ClassDef):
@@ -237,6 +238,7 @@ class AnnotationLoaderMixin:
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content: str = f.read()
ann_content = ExpandSoftKeywords(ann_content)
ann_tree: ast.Module = ast.parse(ann_content)
for node in ann_tree.body:
# 检测 xxx: t.CEnum 形式的枚举成员变量
@@ -283,6 +285,7 @@ class AnnotationLoaderMixin:
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content: str = f.read()
ann_content = ExpandSoftKeywords(ann_content)
ann_tree: ast.Module = ast.parse(ann_content)
for node in ann_tree.body:
# 检测 xxx: t.CTypedef = xxx 形式的 typedef 语句
+4 -1
View File
@@ -6,7 +6,7 @@ import struct
from lib.utils.helpers import DetectFileType
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName, ExpandSoftKeywords
from lib.includes import t
from lib.constants.config import mode as _ConfigMode
from lib.core.VLogger import get_logger as _vlog
@@ -72,6 +72,9 @@ class PythonParserMixin:
with open(FilePath, 'r', encoding=encoding) as f:
content: str = f.read()
# 软关键字展开:fn/fun/func/function -> def,供 ast.parse 使用
content = ExpandSoftKeywords(content)
# 保存当前处理的文件路径(仅在主文件处理时更新)
if UpdateCurrentFile:
self.CurrentFile = FilePath