feat(preprocess): ExpandSoftKeywords 增加 new 生命周期软关键字展开

TPV 的 new [描述符...] T(args) 出现在共享 includes(w32/fileio.vp 的 return new File(...))后会打断 TPC 引导编译(TPC 把它当普通名字 → NameError)。新增第 10 种展开 _ExpandNewExprs:把 new + [stack|heap|hlife|slife|memgr(...)] + 类型名 + ( 删成等价裸构造 T(args),TPC 无需理解生命周期语义;new = 1 / new.x / new(1) / for new in 仍作标识符,跨行不处理。
This commit is contained in:
TermiNexus committed 2026-10-10 15:24:09 +08:00
1 parent 04acaa3dd5
commit 18d753999d
1 file changed
+83
+83
View File
@@ -1614,6 +1614,10 @@ def ExpandSoftKeywords(Code: str) -> str:
后者由 vast.Parser._ParseStaticDef 处理)不受影响;
`extern` 带初值**响亮失败**(外部定义不写初值)。
九种展开都同行替换(长度可增,不增删换行),AST 行号映射保持有效。
10) `new [描述符...] T(args)` → `T(args)`(见 _ExpandNewExprs):TPV 的生命周期
分配软关键字,TPC 不解其语义,展开成等价裸构造(TPC 的常规分配路径)即可;
只有"new + [描述符] + 类型名 + (" 形态命中,`new = 1` / `new.x` / `new(1)` /
`for new in` 仍是标识符。
"""
if not Code:
return Code
@@ -1627,9 +1631,88 @@ def ExpandSoftKeywords(Code: str) -> str:
return Result
# ---------------------------------------------------------------------------
# `new` 生命周期表达式(TPV 软关键字)的 TPC 容忍层
# ---------------------------------------------------------------------------
# TPV 用 `new [描述符...] T(args)`(见 includes/ast/parser.vp)表达"分配 + 生命周期";
# 共享 includes(如 includes/w32/fileio.vp 的 `return new File(...)`)会带上它,但 TPC 不认
# `new`(当普通名字 → NameError),于是 TPC 引导编译 TransPyV 时中断。
# 本层把它展开成等价的裸构造 `T(args)`(TPC 的常规分配路径,与展开前 include 源码一致);
# 只认"new + [描述符] + 类型名 + (" 这一形态——`new = 1` / `new.x` / `new(1)` / `for new in`
# 仍是标识符(与 TPV parser 的软关键字判据同口径)。跨行 new 表达式不处理(保持原样,
# 由后续 parse 响亮失败)。
_NEW_LIFE_DESCRIPTORS: frozenset[str] = frozenset({'stack', 'heap', 'hlife', 'slife'})
def _ExpandNewExprs(Code: str) -> str:
"""`new [stack|heap|hlife|slife|memgr(...)] T(args)` → `T(args)`(TPC 容忍展开)。
仅命中"new + [描述符...] + 类型名 + '('"形态;其余 `new`(标识符)原样保留。
命中后删除 `[new .. 类型名)` 这一段(同行),保留类型名与其后的调用。
"""
if 'new' 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]
i += 1
if Tok.type != tokenize.NAME or Tok.string != 'new':
continue
# 跳过描述符(顺序无关;memgr 带一个括号组)
j: int = _NextSignificantTokenIndex(Tokens, i - 1)
while j >= 0:
Tj = Tokens[j]
if Tj.type == tokenize.NAME and Tj.string in _NEW_LIFE_DESCRIPTORS:
j = _NextSignificantTokenIndex(Tokens, j)
continue
if Tj.type == tokenize.NAME and Tj.string == 'memgr':
k: int = _NextSignificantTokenIndex(Tokens, j)
if k >= 0 and Tokens[k].type == tokenize.OP and Tokens[k].string == '(':
depth: int = 0
m: int = k
while m < n:
if Tokens[m].type == tokenize.OP and Tokens[m].string == '(':
depth += 1
elif Tokens[m].type == tokenize.OP and Tokens[m].string == ')':
depth -= 1
if depth == 0:
break
m += 1
j = _NextSignificantTokenIndex(Tokens, m) if m < n else -1
continue
break
if j < 0:
continue
TypeTok = Tokens[j]
# 类型名:NAME 且本身不是描述符(`new heap` 这种缺类型的不命中)
if TypeTok.type != tokenize.NAME or TypeTok.string in _NEW_LIFE_DESCRIPTORS:
continue
k2: int = _NextSignificantTokenIndex(Tokens, j)
if k2 < 0 or Tokens[k2].type != tokenize.OP or Tokens[k2].string != '(':
continue
# 命中:删除 `[new .. 类型名)`(须同行)
if Tok.start[0] != TypeTok.start[0]:
continue
StartCol: int = Tok.start[1]
EndCol: int = TypeTok.start[1]
Line0: str = Lines0[Tok.start[0] - 1]
Edits.append((Tok.start[0], StartCol, EndCol, '', Line0[StartCol:EndCol]))
return _ApplySameLineEdits(Code, Edits)
def _ExpandSoftKeywordsImpl(Code: str) -> str:
"""ExpandSoftKeywords 的实现体(无缓存,供缓存未命中时调用)。"""
Code = _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code)
# `new` 生命周期软关键字(TPV):尽早展开成裸构造,后续各层不再看到 descriptors。
if 'new' in Code:
Code = _ExpandNewExprs(Code)
if 'enum' in Code:
Code = _ExpandEnumBlocks(Code)
if 'union' in Code: