feat(symbols): TPC 侧同步 export/extern 变量声明语法糖
新增 _ExpandExportExternVar:export 名字: T [= 初值] → 名字: T | t.CExport [= 初值];extern 名字: T → 名字: T | t.State;extern 带初值响亮失败 SyntaxError 排在 _ExpandArrayPrefixAnnotations 之后(先让注解规范化,再插标记);_AtAnnotationColon 把 export/extern 认作语句边界,使数组前缀仍能脱糖 新增 _NextSignificantTokenIndex;ExpandSoftKeywords 文档改列九种展开
This commit is contained in:
1 parent
4346552c72
commit
6fce79d531
1 file changed
+138
-2
+138
-2
@@ -395,6 +395,19 @@ def _PrevSignificantTokenIndex(Tokens: list, Index: int) -> int:
|
||||
return j
|
||||
|
||||
|
||||
def _NextSignificantTokenIndex(Tokens: list, Index: int) -> int:
|
||||
"""取 Index 之后第一个"有意义"的 token 下标(跳过注释与 NL;-1=无)。
|
||||
|
||||
与 `_PrevSignificantTokenIndex` 配对:`export 名字 :` 的 lookahead 与
|
||||
注解类型终点后的 `=` 判定(见 `_ExpandExportExternVar`)共用本函数。
|
||||
"""
|
||||
j: int = Index + 1
|
||||
n: int = len(Tokens)
|
||||
while j < n and Tokens[j].type in _DESCRIPTOR_SKIP_TYPES:
|
||||
j += 1
|
||||
return j if j < n else -1
|
||||
|
||||
|
||||
def _TypeDescriptorSyntaxError(Detail: str, Lineno: int, Col: int, Snippet: str) -> SyntaxError:
|
||||
"""构造类型描述符非法形态的 fail-fast 报文(行:列 + 源码片段 + 期望形态 + 正确示例)。"""
|
||||
return SyntaxError(
|
||||
@@ -563,6 +576,15 @@ 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` 数组前缀与
|
||||
# `__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]`)。
|
||||
if Bound.type == tokenize.NAME and Bound.string in _EXPORT_EXTERN_MODIFIERS:
|
||||
return True
|
||||
return Bound.type in _ARRAY_STMT_BOUNDARY or Bound.string == ';'
|
||||
|
||||
|
||||
@@ -654,6 +676,109 @@ def _ExpandArrayPrefixAnnotations(Code: str) -> str:
|
||||
return _ApplySameLineEdits(Code, Edits)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 变量声明的存储类修饰符 export / extern(语句级软关键字)——与 TPV
|
||||
# includes/ast/parser.vp:_parse_export_extern_var **同一标记、同一消费路径**:
|
||||
# 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 源码中作标识符(仅本语法与注释使用)。
|
||||
# ---------------------------------------------------------------------------
|
||||
_EXPORT_EXTERN_MODIFIERS: frozenset[str] = frozenset({'export', 'extern'})
|
||||
_EXPORT_EXTERN_HINT: str = (
|
||||
'`export 名字: 类型 [= 初值]`(裸名导出,等价 `名字: 类型 | t.CExport`);'
|
||||
'`extern 名字: 类型`(仅声明,等价 `名字: 类型 | t.State`,**不允许初值**)'
|
||||
)
|
||||
_EXPORT_EXTERN_EXAMPLE: str = (
|
||||
'export gdt: [7]gdt_entry = [] / export tss_buf: [104]uint8 / extern a: int'
|
||||
)
|
||||
|
||||
|
||||
def _ExportExternSyntaxError(Detail: str, Lineno: int, Col: int,
|
||||
Snippet: str) -> SyntaxError:
|
||||
"""构造 export/extern 变量声明非法形态的 fail-fast 报文。"""
|
||||
return SyntaxError(
|
||||
f"[TPC] export/extern 变量声明非法({Detail}):行 {Lineno} 列 {Col},"
|
||||
f"源码片段 {Snippet.strip()!r}。"
|
||||
f"期望形态:{_EXPORT_EXTERN_HINT};正确示例:{_EXPORT_EXTERN_EXAMPLE}。"
|
||||
f"(非法形态一律终止编译,绝不静默改写)"
|
||||
)
|
||||
|
||||
|
||||
def _ExpandExportExternVar(Code: str) -> str:
|
||||
"""把 `export 名字: T [= 初值]` / `extern 名字: T` 展开为带存储类标记的注解。
|
||||
|
||||
与 TPV `_parse_export_extern_var` 同口径:export → `| t.CExport`;
|
||||
extern → `| t.State`;extern 带初值 ⇒ **响亮失败**(SyntaxError)。
|
||||
|
||||
- 只在"语句起始(可缩进)+ export/extern + 标识符 + `:`"形态触发;函数形态
|
||||
(`export def f()` / `export f()` / `extern 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 认作语句边界。
|
||||
- 同行编辑(删修饰符 + 插标记),不增删换行 ⇒ 行号映射保持有效。
|
||||
"""
|
||||
if 'export' not in Code and 'extern' not in Code:
|
||||
return Code
|
||||
try:
|
||||
Tokens: list = list(tokenize.generate_tokens(io.StringIO(Code).readline))
|
||||
except Exception:
|
||||
return Code
|
||||
n: int = len(Tokens)
|
||||
Lines0: list[str] = Code.splitlines()
|
||||
Edits: list[tuple[int, int, int, str, str]] = []
|
||||
i: int = 0
|
||||
while i < n:
|
||||
Tok = Tokens[i]
|
||||
if Tok.type == tokenize.NAME and Tok.string in _EXPORT_EXTERN_MODIFIERS:
|
||||
NameIdx: int = _NextSignificantTokenIndex(Tokens, i)
|
||||
if NameIdx >= 0 and Tokens[NameIdx].type == tokenize.NAME:
|
||||
ColonIdx: int = _NextSignificantTokenIndex(Tokens, NameIdx)
|
||||
if ColonIdx >= 0 and Tokens[ColonIdx].string == ':':
|
||||
NameTok = Tokens[NameIdx]
|
||||
TypeStart: int = _NextSignificantTokenIndex(Tokens, ColonIdx)
|
||||
Line: int = Tok.start[0]
|
||||
Snippet: str = Lines0[Line - 1]
|
||||
if TypeStart < 0 or Tokens[TypeStart].start[0] != Line:
|
||||
raise _ExportExternSyntaxError(
|
||||
'缺少类型注解', Line, Tok.start[1] + 1, Snippet)
|
||||
TypeEnd: int = _ScanAnnotationTypeEnd(Tokens, TypeStart, n)
|
||||
if TypeEnd <= TypeStart:
|
||||
raise _ExportExternSyntaxError(
|
||||
'缺少类型注解', Line, Tok.start[1] + 1, Snippet)
|
||||
IsExtern: bool = Tok.string == 'extern'
|
||||
AfterIdx: int = _NextSignificantTokenIndex(Tokens, TypeEnd - 1)
|
||||
if (IsExtern and AfterIdx >= 0
|
||||
and Tokens[AfterIdx].string == '='):
|
||||
raise _ExportExternSyntaxError(
|
||||
'extern 变量声明不能带初始值(符号定义在外部)',
|
||||
Line, Tok.start[1] + 1, Snippet)
|
||||
# 编辑 1:删掉修饰符及其后的空白(保留缩进;只删 `export` 会
|
||||
# 在顶格行留下前导空格 ⇒ IndentationError)。
|
||||
DelStart: int = Tok.start[1]
|
||||
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, ''))
|
||||
i = TypeEnd
|
||||
continue
|
||||
i += 1
|
||||
if not Edits:
|
||||
return Code
|
||||
return _ApplySameLineEdits(Code, Edits)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 注解位置的 C 风格 `__attribute__(...)` 描述符(与 TPV
|
||||
# includes/ast/parser.vp 的 _IsMagicAttributeCall / _MakeTAttrMarker 同源书写法,
|
||||
@@ -1290,7 +1415,7 @@ def EnumMemberCountMismatchError(ClassName: str, Visible: list[tuple[str, object
|
||||
)
|
||||
|
||||
|
||||
# ExpandSoftKeywords 是 Code 的纯函数(全程无全局可变状态,见其"八种展开"实现):
|
||||
# ExpandSoftKeywords 是 Code 的纯函数(全程无全局可变状态,见其"九种展开"实现):
|
||||
# 同一文件内容在一次编译里会被多处重复展开(Phase1 / Phase2 / 依赖扫描),
|
||||
# 缓存结果避免重复正则替换与 tokenize(cProfile:_ExpandTypeDescriptors 里的
|
||||
# tokenize.generate_tokens 全程 ~590 万次 TokenInfo._make)。纯函数缓存不改输出;有界防膨胀。
|
||||
@@ -1328,7 +1453,12 @@ def ExpandSoftKeywords(Code: str) -> str:
|
||||
**同一 AST/同一注册路径**(见 _ExpandRenumBlocks)。成员为普通类体(嵌套
|
||||
`class 变体:` + 无载荷赋值)。行首 `renum` 的非 `renum 名字:` 形态**响亮失败**
|
||||
(该词不在任何源码中作标识符)。
|
||||
八种展开都同行替换(长度可增,不增删换行),AST 行号映射保持有效。
|
||||
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` 带初值**响亮失败**(外部定义不写初值)。
|
||||
九种展开都同行替换(长度可增,不增删换行),AST 行号映射保持有效。
|
||||
"""
|
||||
if not Code:
|
||||
return Code
|
||||
@@ -1371,6 +1501,12 @@ def _ExpandSoftKeywordsImpl(Code: str) -> str:
|
||||
# `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:
|
||||
Code = _ExpandExportExternVar(Code)
|
||||
return Code
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user