全部整理上传
This commit is contained in:
1 parent
f2b33f5e9b
commit
593332636f
28 files changed
+5828
-675
No files matched your search
+159
-19
@@ -4,7 +4,7 @@ import ast
|
||||
import string
|
||||
import memhub
|
||||
import viperlib
|
||||
|
||||
import stdlib
|
||||
|
||||
# ============================================================
|
||||
# StubGen.Converter - vpi 存根文件生成器
|
||||
@@ -57,8 +57,8 @@ def _eval_binop_valid(node: ast.AST | t.CPtr) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def _eval_binop_int(node: ast.AST | t.CPtr) -> int:
|
||||
"""递归计算 BinOp 节点的整数值"""
|
||||
def _eval_binop_int(node: ast.AST | t.CPtr) -> t.CInt64T:
|
||||
"""递归计算 BinOp 节点的整数值(64 位,避免大整数 CDefine 截断)"""
|
||||
if node is None:
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
@@ -80,16 +80,30 @@ def _eval_binop_int(node: ast.AST | t.CPtr) -> int:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
if bop.left is None or bop.right is None:
|
||||
return 0
|
||||
lv: int = _eval_binop_int(bop.left)
|
||||
rv: int = _eval_binop_int(bop.right)
|
||||
lv: t.CInt64T = _eval_binop_int(bop.left)
|
||||
rv: t.CInt64T = _eval_binop_int(bop.right)
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
return lv | rv
|
||||
if bop.op == ast.OpKind.BitAnd:
|
||||
return lv & rv
|
||||
if bop.op == ast.OpKind.BitXor:
|
||||
return lv ^ rv
|
||||
if bop.op == ast.OpKind.Add:
|
||||
return lv + rv
|
||||
if bop.op == ast.OpKind.Sub:
|
||||
return lv - rv
|
||||
if bop.op == ast.OpKind.Mult:
|
||||
return lv * rv
|
||||
if bop.op == ast.OpKind.Div:
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.FloorDiv:
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.Mod:
|
||||
return lv % rv
|
||||
if bop.op == ast.OpKind.LShift:
|
||||
return lv << rv
|
||||
if bop.op == ast.OpKind.RShift:
|
||||
return lv >> rv
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
@@ -103,12 +117,38 @@ def _eval_binop_int(node: ast.AST | t.CPtr) -> int:
|
||||
# 避免循环依赖,使用弱引用
|
||||
_g_pyi_cdefine_found: int = 0
|
||||
|
||||
# 本文件 CDefine 值缓存(vpi 生成专用):
|
||||
# Phase1 生成 .vpi(L1614)早于翻译阶段的 CDefine 注册(L1629+),此时
|
||||
# HandlesType 全局表为空 → BinOp 内 Name 引用查表失败退化为 0(ZDEFLATE
|
||||
# WINDOW_SIZE = 1<<0 = 1、MASK = 0-1 = -1,跨模块读回错误常量根因)。
|
||||
# _GeneratePyiFromAst 开头按声明顺序注册到本缓存,Name 引用先查缓存。
|
||||
# 值缓存用 C 数组(t.CInt64T*)而非 list[int]:TPC 对 list[int].get 会误解析为
|
||||
# list[str].get(返回元素指针 i8*)→ ptrtoint 返回元素地址而非值 → MASK 变成
|
||||
# 20323785277439(地址-1)。C 数组索引 [i] 直接返回 i64 值,可靠。
|
||||
_g_pyi_cdef_names: list[str] | t.CPtr = None
|
||||
_g_pyi_cdef_vals: t.CInt64T | t.CPtr = None
|
||||
_g_pyi_cdef_count: t.CInt = 0
|
||||
|
||||
def _lookup_cdefine_for_pyi(name: str) -> int:
|
||||
"""从本地 CDefine 表查找常量值(用于 .vpi 生成时的 BinOp 计算)"""
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
|
||||
def _lookup_cdefine_for_pyi(name: str) -> t.CInt64T:
|
||||
"""从本文件缓存 / 本地 CDefine 表查找常量值(用于 .vpi 生成时的 BinOp 计算)"""
|
||||
global _g_pyi_cdefine_found
|
||||
val: int = HandlesType.lookup_cdefine_constant(name)
|
||||
# 优先查本文件 CDefine 缓存(vpi 生成早于翻译阶段注册,全局表为空)
|
||||
if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None:
|
||||
# 循环上限用 _g_pyi_cdef_count 而非 len(_g_pyi_cdef_names):
|
||||
# list[str] | t.CPtr 联合类型下 TPV 的 len() 回退 strlen(把 list 对象
|
||||
# 指针当字符串算长度 → 垃圾小值 → 靠后注册项查不到,ZDEFLATE_HASH_MASK
|
||||
# = lookup(HASH_SIZE) 失败 = 0-1 = -1 根因;WINDOW_MASK 查位置 1 恰好
|
||||
# 在 strlen 结果内所以碰巧正确)。
|
||||
pn: t.CSizeT = t.CSizeT(_g_pyi_cdef_count)
|
||||
pi: t.CSizeT
|
||||
for pi in range(pn):
|
||||
pnm: str = _g_pyi_cdef_names.get(pi)
|
||||
if pnm is not None and string.strcmp(pnm, name) == 0:
|
||||
_g_pyi_cdefine_found = 1
|
||||
return _g_pyi_cdef_vals[pi]
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
val: t.CInt64T = HandlesType.lookup_cdefine_constant(name)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
_g_pyi_cdefine_found = 1
|
||||
return val
|
||||
@@ -116,6 +156,36 @@ def _lookup_cdefine_for_pyi(name: str) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def _eval_cdefine_value_cache(node: ast.AST | t.CPtr) -> t.CInt64T:
|
||||
"""求值 CDefine 值(Constant/UnaryOp/BinOp/Call/Name),供 vpi 预处理注册缓存"""
|
||||
if node is None:
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
if cn_c.const_kind == ast.CONST_INT:
|
||||
return cn_c.int_val
|
||||
if cn_c.const_kind == ast.CONST_BOOL:
|
||||
return cn_c.int_val
|
||||
# STR/FLOAT/NONE 不参与整数 BinOp 引用(注册 0 无害)
|
||||
return 0
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
return _eval_binop_int(node)
|
||||
if k == ast.ASTKind.BinOp:
|
||||
return _eval_binop_int(node)
|
||||
if k == ast.ASTKind.Call:
|
||||
cl_c: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl_c.args is not None and cl_c.args.__len__() > 0:
|
||||
return _eval_cdefine_value_cache(cl_c.args.get(0))
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm_c: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm_c.id is not None:
|
||||
return _lookup_cdefine_for_pyi(nm_c.id)
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
def _pyi_cdefine_found() -> int:
|
||||
"""返回上次 _lookup_cdefine_for_pyi 的查找结果状态"""
|
||||
return _g_pyi_cdefine_found
|
||||
@@ -510,6 +580,56 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
|
||||
pos: t.CSizeT = 0
|
||||
|
||||
# 预处理:按声明顺序注册本文件 CDefine 到 _g_pyi 缓存(供 BinOp 求值)
|
||||
# vpi 生成(Phase1 L1614)早于翻译阶段的 CDefine 注册(L1629+),直接查
|
||||
# HandlesType 全局表为空 → BinOp 内 Name 引用退化为 0(ZDEFLATE_WINDOW_SIZE
|
||||
# = 1<<0 = 1、MASK = 0-1 = -1 → 跨模块读回错误常量 → 索引越界崩溃根因)。
|
||||
# 必须 global 声明:TPV 语义下函数内对模块级变量赋值无 global 时创建局部
|
||||
# 变量(_lookup_cdefine_for_pyi 读到的仍是模块级 None → 缓存永不命中,
|
||||
# 追加58 首版失效根因)。
|
||||
global _g_pyi_cdef_names
|
||||
global _g_pyi_cdef_vals
|
||||
global _g_pyi_cdef_count
|
||||
if tree.children is not None:
|
||||
pre_children: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
pcn: t.CSizeT = pre_children.__len__()
|
||||
# 第一遍:数本文件 t.CDefine 声明数(C 数组需先定长分配)
|
||||
_g_pyi_cdef_count = 0
|
||||
pci0: t.CSizeT = 0
|
||||
while pci0 < pcn:
|
||||
stmt_pc0: ast.AST | t.CPtr = pre_children.get(pci0)
|
||||
if stmt_pc0 is not None and stmt_pc0.kind() == ast.ASTKind.AnnAssign:
|
||||
aa_pc0: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt_pc0)
|
||||
if aa_pc0.target is not None and aa_pc0.target.kind() == ast.ASTKind.Name \
|
||||
and aa_pc0.annotation is not None:
|
||||
tgt_pc0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_pc0.target)
|
||||
if tgt_pc0.id is not None and aa_pc0.annotation.kind() == ast.ASTKind.Attribute:
|
||||
ann_pc0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa_pc0.annotation)
|
||||
if ann_pc0.attr is not None and string.strcmp(ann_pc0.attr, "CDefine") == 0:
|
||||
_g_pyi_cdef_count += 1
|
||||
pci0 += 1
|
||||
if _g_pyi_cdef_count > 0:
|
||||
_g_pyi_cdef_names = list[str](mb, t.CSizeT(_g_pyi_cdef_count))
|
||||
_g_pyi_cdef_vals = (t.CInt64T | t.CPtr)(mb.alloc(t.CSizeT(_g_pyi_cdef_count) * 8))
|
||||
# 第二遍:按声明顺序注册(BinOp 内 Name 引用依赖先前注册项)
|
||||
pci: t.CSizeT = 0
|
||||
cdi: t.CInt = 0
|
||||
while pci < pcn:
|
||||
stmt_pc: ast.AST | t.CPtr = pre_children.get(pci)
|
||||
if stmt_pc is not None and stmt_pc.kind() == ast.ASTKind.AnnAssign:
|
||||
aa_pc: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt_pc)
|
||||
if aa_pc.target is not None and aa_pc.target.kind() == ast.ASTKind.Name \
|
||||
and aa_pc.annotation is not None:
|
||||
tgt_pc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_pc.target)
|
||||
if tgt_pc.id is not None and aa_pc.annotation.kind() == ast.ASTKind.Attribute:
|
||||
ann_pc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa_pc.annotation)
|
||||
if ann_pc.attr is not None and string.strcmp(ann_pc.attr, "CDefine") == 0:
|
||||
if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None:
|
||||
_g_pyi_cdef_names.append(tgt_pc.id)
|
||||
_g_pyi_cdef_vals[cdi] = _eval_cdefine_value_cache(aa_pc.value)
|
||||
cdi += 1
|
||||
pci += 1
|
||||
|
||||
# 文件头
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\"\"\"Auto-generated Python stub file\"\"\"\n\n")
|
||||
|
||||
@@ -645,13 +765,33 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
|
||||
num_buf: bytes = mb.alloc(32)
|
||||
if cv.const_kind == ast.CONST_INT and num_buf is not None:
|
||||
viperlib.snprintf(num_buf, 32, " = %d", cv.int_val)
|
||||
viperlib.snprintf(num_buf, 32, " = %lld", cv.int_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, num_buf)
|
||||
elif cv.const_kind == ast.CONST_FLOAT:
|
||||
# 浮点 CDefine(numpy 的 pi/e 等):stub 必须输出值。
|
||||
# 否则读回端"vpi 中任一 CDefine 带值 → 不读源文件"
|
||||
# 的启发式会被同模块 int CDefine(如 MAX_NDIM=4)
|
||||
# 挡住,无值的 pi 解析不到 → 退化 @pi 全局指针 →
|
||||
# float<->ptr 报错(NumpyTest 根因)。%.17g 保证
|
||||
# double 全精度往返(与读回端缓存格式一致)。
|
||||
fbuf_c: bytes = mb.alloc(64)
|
||||
if fbuf_c is not None:
|
||||
viperlib.snprintf(fbuf_c, 64, " = %.17g", cv.float_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, fbuf_c)
|
||||
elif cv.const_kind == ast.CONST_BOOL:
|
||||
if cv.int_val != 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = True")
|
||||
else:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = False")
|
||||
elif cv.const_kind == ast.CONST_STR:
|
||||
# 字符串 CDefine(pyzlib.ZLIB_VERSION = "1.3.2" 等):
|
||||
# stub 必须输出值(同 CONST_FLOAT 追加44 教训——读回端
|
||||
# 按目标名判定会回退源文件可工作,但 stub 应自包含)
|
||||
sbuf_c: bytes = mb.alloc(string.strlen(cv.str_val) + 6)
|
||||
if sbuf_c is not None:
|
||||
viperlib.snprintf(sbuf_c, string.strlen(cv.str_val) + 6,
|
||||
" = \"%s\"", cv.str_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, sbuf_c)
|
||||
elif cv.const_kind == ast.CONST_NONE:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = None")
|
||||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.UnaryOp:
|
||||
@@ -663,8 +803,8 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
and uop_cv.operand.kind() == ast.ASTKind.Constant:
|
||||
uop_const: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_cv.operand)
|
||||
if uop_const.const_kind == ast.CONST_INT and num_buf_u is not None:
|
||||
neg_val: int = -uop_const.int_val
|
||||
viperlib.snprintf(num_buf_u, 32, " = %d", neg_val)
|
||||
neg_val: t.CInt64T = -uop_const.int_val
|
||||
viperlib.snprintf(num_buf_u, 32, " = %lld", neg_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, num_buf_u)
|
||||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.Call:
|
||||
# 处理类型构造函数常量(如 t.CUnsignedLong(-11))
|
||||
@@ -680,7 +820,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
ca_cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg)
|
||||
num_buf_c: bytes = mb.alloc(32)
|
||||
if ca_cv.const_kind == ast.CONST_INT and num_buf_c is not None:
|
||||
viperlib.snprintf(num_buf_c, 32, " = %d", ca_cv.int_val)
|
||||
viperlib.snprintf(num_buf_c, 32, " = %lld", ca_cv.int_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, num_buf_c)
|
||||
elif arg_kind == ast.ASTKind.UnaryOp:
|
||||
uop_ca: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(first_arg)
|
||||
@@ -689,26 +829,26 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
||||
and uop_ca.operand.kind() == ast.ASTKind.Constant:
|
||||
uoc: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_ca.operand)
|
||||
if uoc.const_kind == ast.CONST_INT and num_buf_cu is not None:
|
||||
neg_c_val: int = -uoc.int_val
|
||||
viperlib.snprintf(num_buf_cu, 32, " = %d", neg_c_val)
|
||||
neg_c_val: t.CInt64T = -uoc.int_val
|
||||
viperlib.snprintf(num_buf_cu, 32, " = %lld", neg_c_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, num_buf_cu)
|
||||
elif arg_kind == ast.ASTKind.BinOp:
|
||||
# Call 内部的 BinOp(如 t.CUnsignedLong(A | B))
|
||||
# 递归计算 BinOp 值
|
||||
binop_val_bo: int = _eval_binop_int(first_arg)
|
||||
binop_val_bo: t.CInt64T = _eval_binop_int(first_arg)
|
||||
num_buf_bo: bytes = mb.alloc(32)
|
||||
if (binop_val_bo != 0 or _eval_binop_valid(first_arg) != 0) \
|
||||
and num_buf_bo is not None:
|
||||
viperlib.snprintf(num_buf_bo, 32, " = %d", binop_val_bo)
|
||||
viperlib.snprintf(num_buf_bo, 32, " = %lld", binop_val_bo)
|
||||
pos = _PyiEmit(buf, buf_size, pos, num_buf_bo)
|
||||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.BinOp:
|
||||
# 处理 BinOp 常量(如 FOREGROUND_COMBO = FOREGROUND_RED | FOREGROUND_GREEN)
|
||||
# 递归计算 BinOp 值并输出
|
||||
binop_val_av: int = _eval_binop_int(aa.value)
|
||||
binop_val_av: t.CInt64T = _eval_binop_int(aa.value)
|
||||
if binop_val_av != 0 or _eval_binop_valid(aa.value) != 0:
|
||||
num_buf_b: bytes = mb.alloc(32)
|
||||
if num_buf_b is not None:
|
||||
viperlib.snprintf(num_buf_b, 32, " = %d", binop_val_av)
|
||||
viperlib.snprintf(num_buf_b, 32, " = %lld", binop_val_av)
|
||||
pos = _PyiEmit(buf, buf_size, pos, num_buf_b)
|
||||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.Name:
|
||||
# 处理 Name 引用常量(如 ALIAS = OTHER_CONST)
|
||||
|
||||
@@ -456,6 +456,13 @@ def _resolve_single_vpi_type_str(pool: memhub.MemBuddy | t.CPtr,
|
||||
return llvmlite.Double(pool)
|
||||
if string.strcmp(seg, "void") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
# vpi 源文本中 `-> None` 被原样缓存为 "None"(_cache_vpi_return_annots_text
|
||||
# 提取 arrow_pos 后到 ':' 前的内容)。此前无 "None" 分支 → 解析返回 None →
|
||||
# `-> None` 的跨模块方法(如 AssignGenMixin._register_cdefine_from_value)vpi
|
||||
# 缓存命中也解析不出 void → 方法返回类型 fail-fast 误报(追加80e 断点 B)。
|
||||
# None 与 void 同义,归一到 Void。
|
||||
if string.strcmp(seg, "None") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
# t.XXX / c.XXX 内置类型映射
|
||||
if string.strncmp(seg, "t.", 2) == 0 or string.strncmp(seg, "c.", 2) == 0:
|
||||
attr_nm: str = seg + 2
|
||||
@@ -591,6 +598,11 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy | t.CPtr,
|
||||
if first_ty is not None:
|
||||
return llvmlite.Ptr(pool, first_ty)
|
||||
return i8_ptr_ty
|
||||
if has_cvoid != 0:
|
||||
# t.CVoid | t.State:State 是装饰器标记(编译侧忽略),t.CVoid → void。
|
||||
# 此前缺此分支 → first_ty=None → 返回 None → 跨模块函数返回类型
|
||||
# fail-fast(CPythonTest Py_Initialize() -> t.CVoid | t.State 根因)。
|
||||
return llvmlite.Void(pool)
|
||||
if first_ty is not None:
|
||||
return first_ty
|
||||
return None
|
||||
@@ -1022,8 +1034,17 @@ def _inject_global_variable_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
match resolved_v:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
gv_ty_v = llvmlite.Ptr(pool, resolved_v)
|
||||
case llvmlite.LLVMType.Array(aelem_v, _):
|
||||
gv_ty_v = llvmlite.Ptr(pool, aelem_v)
|
||||
case llvmlite.LLVMType.Array(aelem_v, acount_v):
|
||||
# 定长数组(CArray[T, N]):保留完整数组类型 [N x T],与定义端
|
||||
# handle_module_level_var 生成的 global [N x T] 一致——此前一律
|
||||
# 衰减为元素指针 i32*,链接后引用端 load 把数组前 8 字节当指针
|
||||
# 读 → 垃圾地址 → zdeflate_len_to_symbol 读 NULL/垃圾崩溃
|
||||
# (zdeflate_len_base 跨模块数组根因)。
|
||||
if acount_v > 0:
|
||||
gv_ty_v = resolved_v
|
||||
else:
|
||||
# 不定长数组(CArray[T, None]):元素指针(C 数组衰减)
|
||||
gv_ty_v = llvmlite.Ptr(pool, aelem_v)
|
||||
case _:
|
||||
gv_ty_v = resolved_v
|
||||
gv_v: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gname_v, gv_ty_v)
|
||||
@@ -1261,6 +1282,16 @@ def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr,
|
||||
param_ty = resolved_ty
|
||||
llvmlite.add_param(pool, func, param_ty, pname)
|
||||
|
||||
# OOP iter 协议:__next__ 方法 stub 声明带隐藏 __stop_iter_flag__(i1*),
|
||||
# 与 _translate_method 的 define 签名一致(对齐 TPC HandlesFunctions.py
|
||||
# L703-705)。for x in obj 循环会以 2 个实参调用 __next__(self, flag)。
|
||||
if m_fd.name is not None and string.strcmp(m_fd.name, "__next__") == 0:
|
||||
i1_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||||
if i1_ty_si is not None:
|
||||
i1_ptr_ty_si: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_si)
|
||||
if i1_ptr_ty_si is not None:
|
||||
llvmlite.add_param(pool, func, i1_ptr_ty_si, "__stop_iter_flag__")
|
||||
|
||||
# 注册到函数表(用裸名 ClassName.method,与调用方 lookup_name 一致)
|
||||
# ParamCount 不含 self(方法首参 self/cls 不计入,与 _translate_method 的
|
||||
# md_param_count = args.__len__() - 1 保持一致)——默认参数填充按非 self
|
||||
|
||||
@@ -116,8 +116,6 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
ast._lexer_init(lx, src_buf, mb)
|
||||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||||
# OOM 诊断:parse 后主池用量(区分 parse/translate/dump 阶段)
|
||||
stdio.printf("[MEM] TFGT parse后 used=%zu chk_depth=%zu\n", mb.used_bytes(), mb.chk_depth)
|
||||
# parse 完成后 AST 树已独立,释放源代码缓冲区(避免 1MB/文件泄漏)
|
||||
stdlib.free(src_buf)
|
||||
if tree is None:
|
||||
@@ -216,11 +214,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
# 0xffffffffffffffff 崩溃),docstring 提取与翻译状态无关,提前安全。
|
||||
if gen is not None:
|
||||
gen.extract_module_docstrings(tree, sha1_val)
|
||||
# OOM 诊断:translate 前主池用量
|
||||
stdio.printf("[MEM] TFGT translate前 used=%zu chk_depth=%zu\n", mb.used_bytes(), mb.chk_depth)
|
||||
ret: int = tr.translate(tree)
|
||||
# OOM 诊断:translate 后主池用量(对比 translate 前 → translate 内部增长量)
|
||||
stdio.printf("[MEM] TFGT translate后 used=%zu chk_depth=%zu\n", mb.used_bytes(), mb.chk_depth)
|
||||
if ret != 0:
|
||||
fb_tf: str = VLogger.fmt_buf()
|
||||
if fb_tf is not None:
|
||||
@@ -397,12 +391,12 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
||||
asan_path: str = build_sliced_path(output_dir, module_name, "asan.ll")
|
||||
if asan_path is None:
|
||||
return 1
|
||||
opt_cmd_len: t.CSizeT = string.strlen(asan_path) + string.strlen(ir_path) + 96
|
||||
opt_cmd_len: t.CSizeT = string.strlen(asan_path) + string.strlen(ir_path) + 192
|
||||
opt_cmd: bytes = _mbuddy.alloc(opt_cmd_len)
|
||||
if opt_cmd is None:
|
||||
return 1
|
||||
viperlib.snprintf(opt_cmd, opt_cmd_len,
|
||||
"opt -passes=asan -asan-globals=false -o %s %s",
|
||||
"opt -passes=forceattrs,asan -force-attribute=sanitize_address -asan-globals=false -o %s %s",
|
||||
asan_path, ir_path)
|
||||
opt_ret: int = stdlib.system(opt_cmd)
|
||||
if opt_ret != 0:
|
||||
|
||||
@@ -74,8 +74,12 @@ class AssignGenMixin:
|
||||
# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数
|
||||
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
|
||||
# ============================================================
|
||||
def extract_cdefine_int_value(self, val_node: ast.AST | t.CPtr) -> int:
|
||||
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp)"""
|
||||
def extract_cdefine_int_value(self, val_node: ast.AST | t.CPtr) -> t.CInt64T:
|
||||
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp)
|
||||
|
||||
64 位返回:大整数 CDefine(如 sys.maxsize=9223372036854775807)
|
||||
必须全精度提取,否则 int(32 位) 截断成 -1(SysLibTest maxsize FAIL 根因)。
|
||||
"""
|
||||
if val_node is None:
|
||||
return 0
|
||||
k: int = val_node.kind()
|
||||
@@ -83,6 +87,10 @@ class AssignGenMixin:
|
||||
# Case 1: Constant(INT) — 如 0x0002
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||||
# True/False 布尔常量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理,
|
||||
# 如 SHADOW_ENABLED: t.CDefine = False)
|
||||
if cn.const_kind == ast.CONST_BOOL:
|
||||
return 1 if cn.int_val != 0 else 0
|
||||
if cn.const_kind != ast.CONST_INT:
|
||||
# 非 INT 常量:直接报错终止(fail-fast)
|
||||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
@@ -91,8 +99,8 @@ class AssignGenMixin:
|
||||
# Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN、(1 << ZDEFLATE_WINDOW_BITS)
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(val_node)
|
||||
left_val: int = self.extract_cdefine_int_value(bop.left)
|
||||
right_val: int = self.extract_cdefine_int_value(bop.right)
|
||||
left_val: t.CInt64T = self.extract_cdefine_int_value(bop.left)
|
||||
right_val: t.CInt64T = self.extract_cdefine_int_value(bop.right)
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
return left_val | right_val
|
||||
if bop.op == ast.OpKind.BitAnd:
|
||||
@@ -109,6 +117,9 @@ class AssignGenMixin:
|
||||
return left_val - right_val
|
||||
if bop.op == ast.OpKind.Mult:
|
||||
return left_val * right_val
|
||||
if bop.op == ast.OpKind.Div:
|
||||
# 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355)
|
||||
return left_val // right_val
|
||||
if bop.op == ast.OpKind.FloorDiv:
|
||||
return left_val // right_val
|
||||
if bop.op == ast.OpKind.Mod:
|
||||
@@ -116,11 +127,16 @@ class AssignGenMixin:
|
||||
# 未知 BinOp 运算符:直接报错终止(fail-fast)
|
||||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
|
||||
# Case 3: Name — 引用已注册的 CDefine 常量
|
||||
# Case 3: Name — 引用已注册的 CDefine 常量,或 True/False 布尔字面量
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||||
if nm.id is not None:
|
||||
looked_up: int = HandlesType.lookup_cdefine_constant(nm.id)
|
||||
# True/False 布尔字面量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理)
|
||||
if string.strcmp(nm.id, "True") == 0:
|
||||
return 1
|
||||
if string.strcmp(nm.id, "False") == 0:
|
||||
return 0
|
||||
looked_up: t.CInt64T = HandlesType.lookup_cdefine_constant(nm.id)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
return looked_up
|
||||
# 引用未注册:直接报错终止(fail-fast)
|
||||
@@ -134,7 +150,7 @@ class AssignGenMixin:
|
||||
cl_args_list: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
if cl_args_list is not None and len(cl_args_list) > 0:
|
||||
first_arg: ast.AST | t.CPtr = cl_args_list.get(0)
|
||||
arg_val: int = self.extract_cdefine_int_value(first_arg)
|
||||
arg_val: t.CInt64T = self.extract_cdefine_int_value(first_arg)
|
||||
return arg_val
|
||||
# Call 无参数:直接报错终止(fail-fast)
|
||||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
@@ -142,7 +158,7 @@ class AssignGenMixin:
|
||||
# Case 5: UnaryOp — 如 -11
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(val_node)
|
||||
operand_val: int = self.extract_cdefine_int_value(uop.operand)
|
||||
operand_val: t.CInt64T = self.extract_cdefine_int_value(uop.operand)
|
||||
if uop.op == ast.OpKind.USub:
|
||||
return -operand_val
|
||||
if uop.op == ast.OpKind.UAdd:
|
||||
@@ -154,6 +170,9 @@ class AssignGenMixin:
|
||||
|
||||
# 未知节点类型:直接报错终止(fail-fast)
|
||||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||||
# 追加89 块设计:fatal_error 调用后补显式 return(运行时不可达,
|
||||
# 保证函数末尾块被正确 terminated,不做 noreturn 函数名白名单)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别)
|
||||
@@ -167,6 +186,17 @@ class AssignGenMixin:
|
||||
"""注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数)"""
|
||||
if pool is None or name is None:
|
||||
return
|
||||
# Call 包装的常量:如 PI: t.CDefine = float(3.14159...) /
|
||||
# t.CFloat64T(2.5) / t.CDouble(1.0)。取第一个参数作为真实值节点,
|
||||
# 再按 Constant 分支处理(浮点 → register_cdefine_double)。
|
||||
if val_node is not None and val_node.kind() == ast.ASTKind.Call:
|
||||
cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
|
||||
if cl_cd is not None and cl_cd.args is not None:
|
||||
cl_args_cd: list[ast.AST | t.CPtr] | t.CPtr = cl_cd.args
|
||||
if cl_args_cd.__len__() > 0:
|
||||
first_arg_cd: ast.AST | t.CPtr = cl_args_cd.get(0)
|
||||
if first_arg_cd is not None and first_arg_cd.kind() == ast.ASTKind.Constant:
|
||||
val_node = first_arg_cd
|
||||
if val_node is not None and val_node.kind() == ast.ASTKind.Constant:
|
||||
cn_fp: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||||
if cn_fp.const_kind == ast.CONST_STR:
|
||||
@@ -191,7 +221,7 @@ class AssignGenMixin:
|
||||
# CDefine 声明缺少值节点:直接报错终止(fail-fast)
|
||||
HandlesType.fatal_error(None, f"CDefine 值提取失败:'{name}' 缺少初始值", "TypeError")
|
||||
return
|
||||
val_fp: int = self.extract_cdefine_int_value(val_node)
|
||||
val_fp: t.CInt64T = self.extract_cdefine_int_value(val_node)
|
||||
HandlesType.register_cdefine_constant(pool, name, val_fp)
|
||||
|
||||
# ============================================================
|
||||
|
||||
+1779
-125
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+673
-140
File diff suppressed because it is too large.
Load diff
@@ -285,6 +285,44 @@ class FuncGenMixin:
|
||||
return name
|
||||
return self._mangle_name(trans, name)
|
||||
|
||||
# ============================================================
|
||||
# _body_has_raise - 函数体是否含 raise(非 StopIteration)
|
||||
#
|
||||
# 对齐 TPC HandlesFunctions.py L216-243 _body_contains_raise:函数签名
|
||||
# 追加 __eh_msg_out__/__eh_code_out__ 输出参数的条件。v1 只扫函数体
|
||||
# 顶层 raise(嵌套 if/for/try 内的 raise 未覆盖,后续扩展)。
|
||||
# ============================================================
|
||||
def _body_has_raise(self, fd: ast.FunctionDef | t.CPtr) -> int:
|
||||
"""函数体顶层是否含 raise(非 StopIteration),1=是 / 0=否"""
|
||||
if fd is None or fd.children is None:
|
||||
return 0
|
||||
body_f: list[ast.AST | t.CPtr] | t.CPtr = fd.children
|
||||
bn_f: t.CSizeT = len(body_f)
|
||||
for bi_f in range(bn_f):
|
||||
stmt_f: ast.AST | t.CPtr = body_f.get(bi_f)
|
||||
if stmt_f is None:
|
||||
continue
|
||||
if stmt_f.kind() != ast.ASTKind.Raise:
|
||||
continue
|
||||
rn_f: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(stmt_f)
|
||||
if rn_f is None or rn_f.exc is None:
|
||||
continue
|
||||
ek_f: int = rn_f.exc.kind()
|
||||
is_stop_f: int = 0
|
||||
if ek_f == ast.ASTKind.Name:
|
||||
enm_f: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn_f.exc)
|
||||
if enm_f.id is not None and string.strcmp(enm_f.id, "StopIteration") == 0:
|
||||
is_stop_f = 1
|
||||
elif ek_f == ast.ASTKind.Call:
|
||||
ecl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn_f.exc)
|
||||
if ecl_f.func is not None and ecl_f.func.kind() == ast.ASTKind.Name:
|
||||
ecn_f: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl_f.func)
|
||||
if ecn_f.id is not None and string.strcmp(ecn_f.id, "StopIteration") == 0:
|
||||
is_stop_f = 1
|
||||
if is_stop_f == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明
|
||||
#
|
||||
@@ -539,6 +577,69 @@ class FuncGenMixin:
|
||||
has_export = 1
|
||||
if (has_extern != 0 or has_state != 0) and is_extern_decl == 0:
|
||||
is_extern_decl = 1
|
||||
# @t.TLS 一次性初始化标记(对齐 TPC HandlesFunctions.py L1223-1231)
|
||||
has_tls: int = 0
|
||||
if fd.decorator_list is not None:
|
||||
has_tls = HandlesClassDef._has_decorator(fd.decorator_list, "TLS")
|
||||
|
||||
# 自定义行为装饰器检测(@log/@skip/@repeat(3) 等):非 t 存储标记、
|
||||
# 非内置(staticmethod/property/classmethod)的 Name/Name(args) 装饰器。
|
||||
# 对齐 TPC HandlesFunctions.py L1161-1189 + DecoratorPass.py。首版取
|
||||
# decorator_list 中第一个自定义装饰器(Python 最外层),链式嵌套后续扩展。
|
||||
has_custom_decor: int = 0
|
||||
decor_handler: str = None
|
||||
decor_arg0: t.CInt64T = 0
|
||||
if fd.decorator_list is not None:
|
||||
ddn: t.CSizeT = len(fd.decorator_list)
|
||||
for ddi in range(ddn):
|
||||
deco: ast.AST | t.CPtr = fd.decorator_list.get(ddi)
|
||||
if deco is None:
|
||||
continue
|
||||
dk: int = deco.kind()
|
||||
dname: str = None
|
||||
if dk == ast.ASTKind.Name:
|
||||
dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(deco)
|
||||
dname = dnm.id
|
||||
elif dk == ast.ASTKind.Call:
|
||||
dcl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco)
|
||||
if dcl.func is not None and dcl.func.kind() == ast.ASTKind.Name:
|
||||
dnm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dcl.func)
|
||||
dname = dnm2.id
|
||||
# @repeat(3):取首个常量 int 参数(对齐 TPC L1182-1184)
|
||||
if dcl.args is not None and len(dcl.args) >= 1:
|
||||
da0: ast.AST | t.CPtr = dcl.args.get(0)
|
||||
if da0 is not None and da0.kind() == ast.ASTKind.Constant:
|
||||
dc0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(da0)
|
||||
if dc0.const_kind == ast.CONST_INT:
|
||||
decor_arg0 = dc0.int_val
|
||||
if dname is None:
|
||||
continue
|
||||
# 跳过内置装饰器
|
||||
if string.strcmp(dname, "staticmethod") == 0 \
|
||||
or string.strcmp(dname, "property") == 0 \
|
||||
or string.strcmp(dname, "classmethod") == 0:
|
||||
continue
|
||||
# 跳过 t 模块存储类标记(@t.CExport/@t.CExtern/@t.State/@t.TLS/
|
||||
# @t.CStatic/@t.CInline/@t.CVTable/@t.NoVTable/@t.Object/@t.CEnum
|
||||
# /@t.CUnion/@t.REnum/@t.CDefine 等裸名形式——Attribute 形式
|
||||
# @t.xxx 的 kind 是 Attribute,不进入本检测)
|
||||
if string.strcmp(dname, "CExport") == 0 \
|
||||
or string.strcmp(dname, "CExtern") == 0 \
|
||||
or string.strcmp(dname, "State") == 0 \
|
||||
or string.strcmp(dname, "TLS") == 0 \
|
||||
or string.strcmp(dname, "CStatic") == 0 \
|
||||
or string.strcmp(dname, "CInline") == 0 \
|
||||
or string.strcmp(dname, "CVTable") == 0 \
|
||||
or string.strcmp(dname, "NoVTable") == 0 \
|
||||
or string.strcmp(dname, "Object") == 0 \
|
||||
or string.strcmp(dname, "CEnum") == 0 \
|
||||
or string.strcmp(dname, "CUnion") == 0 \
|
||||
or string.strcmp(dname, "REnum") == 0 \
|
||||
or string.strcmp(dname, "CDefine") == 0:
|
||||
continue
|
||||
has_custom_decor = 1
|
||||
decor_handler = dname
|
||||
break
|
||||
|
||||
# SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名
|
||||
# (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference)
|
||||
@@ -707,6 +808,24 @@ class FuncGenMixin:
|
||||
if ags.vararg is not None:
|
||||
func.IsVarArg = 1
|
||||
|
||||
# try-except:函数体含 raise → 追加 __eh_msg_out__(i8**)/
|
||||
# __eh_code_out__(i32*)输出参数(对齐 TPC HandlesFunctions.py
|
||||
# L706-711;main 除外)。被调函数把异常编码/消息写入调用方传入
|
||||
# 的指针,调用方 _check_eh_return 检测。
|
||||
# 注意:必须在参数添加块(if args_node is not None:)外——无参函数
|
||||
# (def f())的 args_node 为 None,若放在其内会被跳过,导致函数体
|
||||
# store %__eh_code_out__ 但签名无此参数(llc: use of undefined value)。
|
||||
if string.strcmp(fd.name, "main") != 0:
|
||||
if self._body_has_raise(fd) != 0:
|
||||
i8_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_eh)
|
||||
i8_ptr_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_eh)
|
||||
i32_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i32_ptr_ty_eh: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty_eh)
|
||||
if i8_ptr_ptr_ty_eh is not None and i32_ptr_ty_eh is not None:
|
||||
llvmlite.add_param(pool, func, i8_ptr_ptr_ty_eh, "%__eh_msg_out__")
|
||||
llvmlite.add_param(pool, func, i32_ptr_ty_eh, "%__eh_code_out__")
|
||||
|
||||
# 参数添加完成,补全全局函数表的 TypeStr
|
||||
HandlesExprCall.update_global_func_typestr(trans.Pool, fd.name, func)
|
||||
|
||||
@@ -721,6 +840,72 @@ class FuncGenMixin:
|
||||
return 0
|
||||
llvmlite.position_at_end(func_builder, entry_blk)
|
||||
|
||||
# @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792):
|
||||
# 首次调用执行函数体并置全局标志 __tls_init_done_{name}=1,后续调用
|
||||
# 直接返回默认值。TPV 此前未实现 @t.TLS,_init_tls 每次 TlsAlloc 导致
|
||||
# provider 栈跨调用丢失(FakeDuckTest Test 9 注入失败根因)。
|
||||
if has_tls != 0:
|
||||
tls_flag_name: str = pool.alloc(128)
|
||||
if tls_flag_name is not None:
|
||||
viperlib.snprintf(tls_flag_name, 128, "__tls_init_done_%s", fd.name)
|
||||
tls_flag_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_int(
|
||||
pool, mod, tls_flag_name, 1, 0)
|
||||
if tls_flag_gv is not None:
|
||||
i1_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||||
if i1_ty_t is not None:
|
||||
# GlobalVariable 不是 Value 子类(字段布局不同),build_load/store
|
||||
# 按 Value 读 ptr.Ty/ptr.Name 会错位(Ty 读到 Name → void,Name 为空)。
|
||||
# 与 create_global_string 一致:构造 Value 视图(Ty=Ptr(i1), Name="@name")。
|
||||
tls_gv_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i1_ty_t)
|
||||
tls_ref_name: str = pool.alloc(64)
|
||||
if tls_ref_name is not None:
|
||||
viperlib.snprintf(tls_ref_name, 64, "@%s", tls_flag_name)
|
||||
tls_flag_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, tls_gv_ptr_ty, tls_ref_name)
|
||||
if tls_flag_ref is not None:
|
||||
tls_flag_ld: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
func_builder, i1_ty_t, tls_flag_ref)
|
||||
# 块名唯一化(create_block 不自动编号,同函数同名 label 冲突)
|
||||
lc_t: int = trans._label_counter
|
||||
trans._label_counter = lc_t + 1
|
||||
tls_bb_buf: str = pool.alloc(64)
|
||||
if tls_bb_buf is not None:
|
||||
viperlib.snprintf(tls_bb_buf, 64, "tls.skip.%d", lc_t)
|
||||
tls_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, func, tls_bb_buf)
|
||||
viperlib.snprintf(tls_bb_buf, 64, "tls.cont.%d", lc_t)
|
||||
tls_cont_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, func, tls_bb_buf)
|
||||
if tls_skip_bb is not None and tls_cont_bb is not None:
|
||||
llvmlite.build_cond_br(
|
||||
func_builder, tls_flag_ld, tls_skip_bb, tls_cont_bb)
|
||||
# skip 块:按返回类型生成默认值直接返回
|
||||
llvmlite.position_at_end(func_builder, tls_skip_bb)
|
||||
match ret_ty:
|
||||
case llvmlite.LLVMType.Void():
|
||||
llvmlite.build_ret_void(func_builder)
|
||||
case llvmlite.LLVMType.Int(_):
|
||||
tlz0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||||
pool, ret_ty, 0, "0")
|
||||
if tlz0 is not None:
|
||||
llvmlite.build_ret(func_builder, tlz0)
|
||||
case llvmlite.LLVMType.Float(_):
|
||||
tlf0: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(
|
||||
pool, ret_ty, 0.0)
|
||||
if tlf0 is not None:
|
||||
llvmlite.build_ret(func_builder, tlf0)
|
||||
case _:
|
||||
tln0: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
|
||||
pool, ret_ty, "null")
|
||||
if tln0 is not None:
|
||||
llvmlite.build_ret(func_builder, tln0)
|
||||
# cont 块:置标志=1,继续函数体
|
||||
llvmlite.position_at_end(func_builder, tls_cont_bb)
|
||||
tlone: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||||
pool, i1_ty_t, 1, "1")
|
||||
if tlone is not None:
|
||||
llvmlite.build_store(func_builder, tlone, tls_flag_ref)
|
||||
|
||||
# 进入函数作用域(嵌套符号表)
|
||||
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
|
||||
|
||||
@@ -777,10 +962,11 @@ class FuncGenMixin:
|
||||
if alloca is not None:
|
||||
HandlesVar.define_var(trans.SymTab, arg2.arg, alloca)
|
||||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||||
# 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复)
|
||||
cls_nm: str = None
|
||||
if arg2.annotation is not None:
|
||||
cls_nm = HandlesType.extract_class_name_from_annotation(
|
||||
arg2.annotation, imported_modules)
|
||||
arg2.annotation, imported_modules, pool)
|
||||
if cls_nm is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
trans.SymTab, arg2.arg, cls_nm)
|
||||
@@ -791,37 +977,68 @@ class FuncGenMixin:
|
||||
pool, param_ty2, pname2)
|
||||
llvmlite.build_store(func_builder, param_val, alloca)
|
||||
|
||||
# *args 变长参数:创建 va_list 缓冲区 + 调用 va_start + 注册到符号表
|
||||
# 生成 IR:
|
||||
# %args_va = alloca [24 x i8], align 16 ; va_list 缓冲区(Win64 __va_list_tag)
|
||||
# %args = bitcast [24 x i8]* %args_va to i8*
|
||||
# call void @llvm.va_start(i8* %args) ; 初始化 va_list
|
||||
# 用户函数体内可通过 args 名字读取 va_list 地址(i8*),或用 arg(type) 糖函数
|
||||
if ags2.vararg is not None:
|
||||
vararg_node: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(ags2.vararg)
|
||||
if vararg_node is not None and vararg_node.arg is not None:
|
||||
vararg_name_str: str = vararg_node.arg
|
||||
# va_list 缓冲区 24 字节(Win64 的 __va_list_tag = {i32,i32,i8*,i8*})+ 16 对齐
|
||||
# (对齐 TPC HandlesFunctions.py:1739-1741)
|
||||
i8_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_va)
|
||||
va_buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty_va, 24)
|
||||
va_list_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca_aligned(
|
||||
func_builder, va_buf_ty, 16)
|
||||
if va_list_alloca is not None:
|
||||
# i8* 地址(指向 24 字节 va_list 缓冲区)——vararg 名的值语义
|
||||
va_list_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
func_builder, va_list_alloca, i8_ptr_ty_va)
|
||||
if va_list_addr is not None:
|
||||
# 注册到符号表(translate_name_value 对 vararg 名特殊处理返回地址)
|
||||
HandlesVar.define_var(trans.SymTab, vararg_name_str, va_list_alloca)
|
||||
# 调用 @llvm.va_start(i8* %va_list_addr)
|
||||
void_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
llvmlite.build_call(func_builder, "llvm.va_start",
|
||||
va_list_addr, 1, void_ty_va, 0)
|
||||
# 保存到 trans 供 arg(type) 糖函数与 vararg 名翻译使用
|
||||
trans._va_list_ptr = va_list_addr
|
||||
trans._vararg_name = vararg_name_str
|
||||
# *args 变长参数:创建 va_list 缓冲区 + 调用 va_start + 注册到符号表
|
||||
# 生成 IR:
|
||||
# %args_va = alloca [24 x i8], align 16 ; va_list 缓冲区(Win64 __va_list_tag)
|
||||
# %args = bitcast [24 x i8]* %args_va to i8*
|
||||
# call void @llvm.va_start(i8* %args) ; 初始化 va_list
|
||||
# 用户函数体内可通过 args 名字读取 va_list 地址(i8*),或用 arg(type) 糖函数
|
||||
# 注意:必须在参数 alloca 段(if args_node is not None:)内但 EH 块外——
|
||||
# 无 raise 的函数(viperlib.sprintf 等)同样有 *args,若放在 EH 块内
|
||||
# 会被跳过,args 未注册到符号表 → NameError: 未定义名称 'args'。
|
||||
if ags2.vararg is not None:
|
||||
vararg_node: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(ags2.vararg)
|
||||
if vararg_node is not None and vararg_node.arg is not None:
|
||||
vararg_name_str: str = vararg_node.arg
|
||||
# va_list 缓冲区 24 字节(Win64 的 __va_list_tag = {i32,i32,i8*,i8*})+ 16 对齐
|
||||
# (对齐 TPC HandlesFunctions.py:1739-1741)
|
||||
i8_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_va)
|
||||
va_buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty_va, 24)
|
||||
va_list_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca_aligned(
|
||||
func_builder, va_buf_ty, 16)
|
||||
if va_list_alloca is not None:
|
||||
# i8* 地址(指向 24 字节 va_list 缓冲区)——vararg 名的值语义
|
||||
va_list_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
func_builder, va_list_alloca, i8_ptr_ty_va)
|
||||
if va_list_addr is not None:
|
||||
# 注册到符号表(translate_name_value 对 vararg 名特殊处理返回地址)
|
||||
HandlesVar.define_var(trans.SymTab, vararg_name_str, va_list_alloca)
|
||||
# 调用 @llvm.va_start(i8* %va_list_addr)
|
||||
void_ty_va: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
llvmlite.build_call(func_builder, "llvm.va_start",
|
||||
va_list_addr, 1, void_ty_va, 0)
|
||||
# 保存到 trans 供 arg(type) 糖函数与 vararg 名翻译使用
|
||||
trans._va_list_ptr = va_list_addr
|
||||
trans._vararg_name = vararg_name_str
|
||||
|
||||
# try-except:新函数作用域 EH 状态从零开始。必须先保存外层函数
|
||||
# (调用方/包围函数)的 EH 输出参数,翻译完本函数后再恢复——否则
|
||||
# 下方设置本函数 EH 参数会覆盖外层值,恢复时 old_eh_* 拿到的是
|
||||
# 本函数自身参数(嵌套函数/多函数链 EH 状态错乱)。
|
||||
old_eh_msg_out: llvmlite.Value | t.CPtr = trans._eh_msg_out_param
|
||||
old_eh_code_out: llvmlite.Value | t.CPtr = trans._eh_code_out_param
|
||||
old_cur_func_has_eh: int = trans._cur_func_has_eh
|
||||
trans._eh_msg_out_param = None
|
||||
trans._eh_code_out_param = None
|
||||
trans._cur_func_has_eh = 0
|
||||
|
||||
# try-except:保存当前函数的 EH 输出参数(__eh_msg_out__/__eh_code_out__)
|
||||
# 供 translate_raise / UnhandledBB 写入并向上传播。无 EH 参数的函数置空。
|
||||
if string.strcmp(fd.name, "main") != 0 and self._body_has_raise(fd) != 0:
|
||||
i8_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_eh2)
|
||||
i8_ptr_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_eh2)
|
||||
i32_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i32_ptr_ty_eh2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty_eh2)
|
||||
if i8_ptr_ptr_ty_eh2 is not None and i32_ptr_ty_eh2 is not None:
|
||||
msg_out_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, i8_ptr_ptr_ty_eh2, "%__eh_msg_out__")
|
||||
code_out_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, i32_ptr_ty_eh2, "%__eh_code_out__")
|
||||
trans._eh_msg_out_param = msg_out_ref
|
||||
trans._eh_code_out_param = code_out_ref
|
||||
trans._cur_func_has_eh = 1
|
||||
|
||||
# 保存模块级作用域状态(仅非变量表相关)
|
||||
old_func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
@@ -872,39 +1089,89 @@ class FuncGenMixin:
|
||||
|
||||
# 如果函数体最后一条语句不是 Return,添加隐式 ret
|
||||
last_is_return: int = 0
|
||||
# 追加89:bn3 提前初始化,避免 body is None 时下方 fail-fast 分支
|
||||
# 引用未定义的 bn3(追加81 同款 NameError 风险)
|
||||
bn3: t.CSizeT = 0
|
||||
if body is not None:
|
||||
bn3: t.CSizeT = len(body)
|
||||
bn3 = len(body)
|
||||
if bn3 > 0:
|
||||
last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1)
|
||||
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
|
||||
last_is_return = 1
|
||||
if last_is_return == 0:
|
||||
if llvmlite.builder_cur_block_is_terminated(func_builder) == 0:
|
||||
# 根据返回类型生成正确的零值返回
|
||||
# 必须覆盖浮点返回类型:double/float 函数生成 ConstFloat(0.0),
|
||||
# 否则默认 ret i32 0 类型不匹配(llc: value doesn't match function result type)
|
||||
# 追加89:编译器不替代码发明返回值——函数流程真实掉出末尾而
|
||||
# 未显式 return 时 fail-fast(要求补 return,Python traceback
|
||||
# 风格定位到函数)。三种合法收尾:
|
||||
# ① void 函数掉出末尾 → ret void(无值可发明,Python 语义)
|
||||
# ② 末句是控制流语句(match/if 全分支 return)且当前块
|
||||
# 未 terminated → merge 块结构性不可达 → unreachable
|
||||
# ③ 无返回类型注解的函数(fd.returns is None,如
|
||||
# ast/base.vp _set_pos 过程风格赋值函数)→ 视为无返回值
|
||||
# 函数,默认生成零值返回(用户决策:没有返回值默认不用
|
||||
# return;ConstZero 按推断出的 ret_ty 构造,类型匹配)
|
||||
# 有 -> 注解且末句是普通语句掉出末尾 → fail-fast(不得替代码
|
||||
# 发明返回值,也不做 noreturn 函数名白名单——错误终止路径
|
||||
# 也必须在源码层面保证块收尾,如显式 return 样板)
|
||||
# 末句是否为控制流语句(If/Match/While/For/Try/With):
|
||||
# 控制流语句翻译后当前块未 terminated 表示 merge 块结构性
|
||||
# 不可达(所有分支均已 return/terminated)——对非 void 函数
|
||||
# 生成 unreachable 而非 fail-fast(GCC/Clang 对 fall-through
|
||||
# 视为 UB 同语义;追加89 修正 get_struct_name 全 case return
|
||||
# 被错判"不可能抵达")
|
||||
last_is_ctrl: int = 0
|
||||
if bn3 > 0:
|
||||
last_stmt3: ast.AST | t.CPtr = body.get(bn3 - 1)
|
||||
if last_stmt3 is not None:
|
||||
k3: int = last_stmt3.kind()
|
||||
if k3 == ast.ASTKind.If or k3 == ast.ASTKind.While or \
|
||||
k3 == ast.ASTKind.For or k3 == ast.ASTKind.Try or \
|
||||
k3 == ast.ASTKind.With or k3 == ast.ASTKind.Match:
|
||||
last_is_ctrl = 1
|
||||
_is_void: int = 0
|
||||
_is_ptr: int = 0
|
||||
_is_float: int = 0
|
||||
if ret_ty is not None:
|
||||
match ret_ty:
|
||||
case llvmlite.LLVMType.Void():
|
||||
_is_void = 1
|
||||
case llvmlite.LLVMType.Ptr(_pe):
|
||||
_is_ptr = 1
|
||||
case llvmlite.LLVMType.Float(_fb):
|
||||
_is_float = 1
|
||||
case _:
|
||||
pass
|
||||
if _is_void != 0:
|
||||
llvmlite.build_ret_void(func_builder)
|
||||
elif _is_ptr != 0:
|
||||
_null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
|
||||
llvmlite.build_ret(func_builder, _null_val)
|
||||
elif _is_float != 0:
|
||||
_zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0)
|
||||
llvmlite.build_ret(func_builder, _zero_f)
|
||||
elif last_is_ctrl != 0:
|
||||
# 非 void 函数末句是控制流且块未 terminated:merge 块
|
||||
# 结构性不可达(不可能抵达),LLVM 语义 unreachable
|
||||
llvmlite.build_unreachable(func_builder)
|
||||
elif fd.returns is None:
|
||||
# 无返回类型注解 → 无返回值过程函数,默认零值返回
|
||||
if ret_ty is not None:
|
||||
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty)
|
||||
if zero_val is not None:
|
||||
llvmlite.build_ret(func_builder, zero_val)
|
||||
else:
|
||||
HandlesType.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
|
||||
else:
|
||||
HandlesType.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
|
||||
else:
|
||||
_zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
llvmlite.build_ret(func_builder, _zero_val)
|
||||
# fail-fast:有 -> 注解但流程真实掉出末尾(定位到函数定义
|
||||
# 节点,fatal_error 输出 traceback 风格错误)
|
||||
if ret_ty is not None:
|
||||
# llvmlite 无 type_get_name API,类型序列化用真实接口
|
||||
# TypePrint(buf, size, ty, pool)(追加89 修正)
|
||||
rt_name: str = pool.alloc(64)
|
||||
if rt_name is not None:
|
||||
llvmlite.TypePrint(rt_name, 64, ret_ty, pool)
|
||||
if rt_name[0] == '\0':
|
||||
rt_name = "?"
|
||||
err_fn: str = pool.alloc(256)
|
||||
if err_fn is not None:
|
||||
viperlib.snprintf(
|
||||
err_fn, 256,
|
||||
"函数 '%s' 流程掉出函数末尾但未显式 return(返回类型 %s),"
|
||||
"请补显式 return(如 return 0 / return null)", fd.name, rt_name)
|
||||
HandlesType.fatal_error(node, err_fn, "TypeError")
|
||||
HandlesType.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
|
||||
else:
|
||||
HandlesType.fatal_error(node, "函数流程掉出末尾但未显式 return", "TypeError")
|
||||
|
||||
# 恢复模块级作用域(退出函数作用域)
|
||||
if tp_names_fn is not None:
|
||||
@@ -917,9 +1184,348 @@ class FuncGenMixin:
|
||||
trans._closure_env_count = old_env_count
|
||||
trans._va_list_ptr = old_va_list_ptr
|
||||
trans._vararg_name = old_vararg_name
|
||||
# 恢复外层函数(调用方)的 EH 输出参数——本函数体内的 raise 传播
|
||||
# 使用本函数参数,翻译结束必须交还外层作用域,否则嵌套函数/链式
|
||||
# 调用后 EH 状态残留导致 raise 写入错误的 out 指针。
|
||||
trans._eh_msg_out_param = old_eh_msg_out
|
||||
trans._eh_code_out_param = old_eh_code_out
|
||||
trans._cur_func_has_eh = old_cur_func_has_eh
|
||||
|
||||
# 自定义装饰器:注册 + 生成 wrapper(对齐 TPC DecoratorPass.run)。
|
||||
# 仅模块级函数(fd 是顶层定义);wrapper 名 __decor_wrap_{裸函数名}。
|
||||
# 调用点重写经 lookup_decor_wrapper(translate_call 拦截原函数名)。
|
||||
if has_custom_decor != 0:
|
||||
wb_name: str = pool.alloc(128)
|
||||
if wb_name is not None:
|
||||
viperlib.snprintf(wb_name, 128, "__decor_wrap_%s", fd.name)
|
||||
HandlesClassDef.register_decorator(pool, fd.name, wb_name, decor_arg0)
|
||||
self._gen_decor_wrapper(
|
||||
trans, pool, mod, func, fd.name, wb_name,
|
||||
decor_handler, decor_arg0)
|
||||
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _gen_decor_wrapper - 生成装饰器 wrapper 函数(对齐 TPC DecoratorPass.py
|
||||
# _generate_single_wrapper v4)
|
||||
#
|
||||
# v4 Wrapper 结构(最外层含递归保护):
|
||||
# entry → 递归保护检查(最外层)
|
||||
# recursive_call → 递归时直接调用原函数,跳过所有装饰
|
||||
# decorated_entry → 置递归标志,分配 ctx/args/ret,调用 handler 前置
|
||||
# loop_header → 计数器 i < n_calls(TPV 用 alloca 计数器替代 phi)
|
||||
# loop.body → 从 args_struct 读回参数,调用原函数
|
||||
# post → 调用 handler 后置,清递归标志,返回结果
|
||||
#
|
||||
# handler 调用约定:i32 decor(i8* ctx, i8* func_name, i32 phase,
|
||||
# i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr)
|
||||
# 前置返回:0=跳过原函数,1=调用一次,N=循环 N 次
|
||||
# ============================================================
|
||||
def _gen_decor_wrapper(self, trans: HT.Translator | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
func: llvmlite.Function | t.CPtr,
|
||||
func_name: str,
|
||||
wrapper_name: str,
|
||||
handler_name: str,
|
||||
decor_arg0: t.CInt64T) -> llvmlite.Function | t.CPtr:
|
||||
"""生成装饰器 wrapper 函数,返回 wrapper 或 None"""
|
||||
if trans is None or pool is None or mod is None or func is None:
|
||||
return None
|
||||
if func_name is None or wrapper_name is None or handler_name is None:
|
||||
return None
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func)
|
||||
if ret_ty is None:
|
||||
return None
|
||||
orig_call_name: str = llvmlite.function_get_name(func)
|
||||
if orig_call_name is None:
|
||||
return None
|
||||
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
# ---- 收集原函数参数类型(按位置,最多 16 个)----
|
||||
n_params: int = 0
|
||||
param_tys: t.CSizeT | t.CPtr = pool.alloc(16 * 8)
|
||||
if param_tys is None:
|
||||
return None
|
||||
string.memset(param_tys, 0, 16 * 8)
|
||||
pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
|
||||
while pp is not None:
|
||||
pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp)
|
||||
if pty is not None and n_params < 16:
|
||||
param_tys[n_params] = t.CSizeT(pty)
|
||||
n_params += 1
|
||||
pp = llvmlite.param_get_next(pp)
|
||||
|
||||
# ---- 创建 wrapper 函数并添加参数(名字 %a0..%aN)----
|
||||
wrapper: llvmlite.Function | t.CPtr = llvmlite.create_function(
|
||||
pool, mod, wrapper_name, ret_ty)
|
||||
if wrapper is None:
|
||||
return None
|
||||
pi: int = 0
|
||||
for pi in range(n_params):
|
||||
pname_w: str = pool.alloc(16)
|
||||
if pname_w is not None:
|
||||
viperlib.snprintf(pname_w, 16, "%%a%d", pi)
|
||||
llvmlite.add_param(pool, wrapper, (llvmlite.LLVMType | t.CPtr)(
|
||||
t.CVoid(param_tys[pi], t.CPtr)), pname_w)
|
||||
|
||||
# ---- 创建块 ----
|
||||
entry_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "entry")
|
||||
loop_h_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "loop.header")
|
||||
loop_b_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "loop.body")
|
||||
post_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "post")
|
||||
if entry_bb is None or loop_h_bb is None or loop_b_bb is None or post_bb is None:
|
||||
return None
|
||||
|
||||
# 递归保护标志(最外层):@__decor_rec_{wrapper} = global i8 0
|
||||
rec_flag_ref: llvmlite.Value | t.CPtr = None
|
||||
rec_flag_name: str = pool.alloc(128)
|
||||
if rec_flag_name is not None:
|
||||
viperlib.snprintf(rec_flag_name, 128, "__decor_rec_%s", wrapper_name)
|
||||
llvmlite.create_global_int(pool, mod, rec_flag_name, 8, 0)
|
||||
rec_ref_nm: str = pool.alloc(96)
|
||||
if rec_ref_nm is not None:
|
||||
viperlib.snprintf(rec_ref_nm, 96, "@%s", rec_flag_name)
|
||||
rec_flag_ref = llvmlite.SSAValue(pool, llvmlite.Ptr(pool, i8_ty), rec_ref_nm)
|
||||
|
||||
wb: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, wrapper)
|
||||
if wb is None:
|
||||
return None
|
||||
|
||||
# 返回类型分类
|
||||
ret_is_void: int = 0
|
||||
match ret_ty:
|
||||
case llvmlite.LLVMType.Void():
|
||||
ret_is_void = 1
|
||||
case _:
|
||||
pass
|
||||
|
||||
# ---- entry:递归保护检查(最外层)----
|
||||
llvmlite.position_at_end(wb, entry_bb)
|
||||
loop_pred_bb: llvmlite.BasicBlock | t.CPtr = entry_bb
|
||||
if rec_flag_ref is not None:
|
||||
rec_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "recursive_call")
|
||||
dec_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, wrapper, "decorated_entry")
|
||||
if rec_bb is None or dec_bb is None:
|
||||
return None
|
||||
rec_val: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, i8_ty, rec_flag_ref)
|
||||
rec_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 0, "0")
|
||||
rec_is: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
wb, llvmlite.ICMP_NE, rec_val, rec_zero)
|
||||
llvmlite.build_cond_br(wb, rec_is, rec_bb, dec_bb)
|
||||
# recursive_call:直接调用原函数返回(跳过所有装饰逻辑)
|
||||
llvmlite.position_at_end(wb, rec_bb)
|
||||
rec_args: llvmlite.Value | t.CPtr = None
|
||||
ri: int = 0
|
||||
for ri in range(n_params):
|
||||
an_r: str = pool.alloc(16)
|
||||
if an_r is None:
|
||||
continue
|
||||
viperlib.snprintf(an_r, 16, "%%a%d", ri)
|
||||
av_r: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, (llvmlite.LLVMType | t.CPtr)(t.CVoid(param_tys[ri], t.CPtr)), an_r)
|
||||
if av_r is not None:
|
||||
llvmlite.value_set_next(av_r, None)
|
||||
if rec_args is None:
|
||||
rec_args = av_r
|
||||
else:
|
||||
# 链尾追加
|
||||
rt: llvmlite.Value | t.CPtr = rec_args
|
||||
while rt.Next is not None:
|
||||
rt = rt.Next
|
||||
llvmlite.value_set_next(rt, av_r)
|
||||
if ret_is_void != 0:
|
||||
llvmlite.build_call(wb, orig_call_name, rec_args, n_params, ret_ty, 0)
|
||||
llvmlite.build_ret_void(wb)
|
||||
else:
|
||||
rc_res: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||||
wb, orig_call_name, rec_args, n_params, ret_ty, 0)
|
||||
if rc_res is not None:
|
||||
llvmlite.build_ret(wb, rc_res)
|
||||
else:
|
||||
llvmlite.build_ret_void(wb)
|
||||
# decorated_entry:置递归标志,继续装饰路径
|
||||
llvmlite.position_at_end(wb, dec_bb)
|
||||
rec_one: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 1, "1")
|
||||
if rec_one is not None:
|
||||
llvmlite.build_store(wb, rec_one, rec_flag_ref)
|
||||
loop_pred_bb = dec_bb
|
||||
|
||||
# ---- 公共装饰路径(entry 或 decorated_entry)----
|
||||
# 1. ctx = alloca [32 x i8]; ctx_ptr = bitcast i8*
|
||||
ctx_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, 32)
|
||||
ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(wb, ctx_ty)
|
||||
ctx_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(wb, ctx_alloca, i8_ptr_ty)
|
||||
|
||||
# 2. 打包函数参数到结构体 {param_types}(装饰器可读写 args_ptr)
|
||||
args_alloca: llvmlite.Value | t.CPtr = None
|
||||
args_ptr: llvmlite.Value | t.CPtr = None
|
||||
if n_params > 0:
|
||||
fields_head: llvmlite.ParamNode | t.CPtr = None
|
||||
fk: int = 0
|
||||
for fk in range(n_params - 1, -1, -1):
|
||||
pn_n: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(
|
||||
pool, (llvmlite.LLVMType | t.CPtr)(t.CVoid(param_tys[fk], t.CPtr)))
|
||||
if pn_n is not None:
|
||||
pn_n.Next = fields_head
|
||||
fields_head = pn_n
|
||||
args_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(
|
||||
pool, fields_head, n_params, None)
|
||||
if args_ty is not None:
|
||||
args_alloca = llvmlite.build_alloca(wb, args_ty)
|
||||
fi2: int = 0
|
||||
for fi2 in range(n_params):
|
||||
fld_ty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(
|
||||
t.CVoid(param_tys[fi2], t.CPtr))
|
||||
fld_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
wb, args_ty, fld_ty, args_alloca, fi2)
|
||||
if fld_ptr is not None:
|
||||
fld_nm: str = pool.alloc(16)
|
||||
if fld_nm is not None:
|
||||
viperlib.snprintf(fld_nm, 16, "%%a%d", fi2)
|
||||
fld_v: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, fld_ty, fld_nm)
|
||||
if fld_v is not None:
|
||||
llvmlite.build_store(wb, fld_v, fld_ptr)
|
||||
args_ptr = llvmlite.build_bitcast(wb, args_alloca, i8_ptr_ty)
|
||||
else:
|
||||
args_ptr = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||||
|
||||
# 3. 返回值存储(零初始化;跳过原函数时返回安全默认值)
|
||||
ret_alloca: llvmlite.Value | t.CPtr = None
|
||||
if ret_is_void == 0:
|
||||
ret_alloca = llvmlite.build_alloca(wb, ret_ty)
|
||||
ret_zero: llvmlite.Value | t.CPtr = None
|
||||
match ret_ty:
|
||||
case llvmlite.LLVMType.Int(_):
|
||||
ret_zero = llvmlite.ConstInt(pool, ret_ty, 0, "0")
|
||||
case llvmlite.LLVMType.Float(_):
|
||||
ret_zero = llvmlite.ConstFloat(pool, ret_ty, 0.0)
|
||||
case _:
|
||||
ret_zero = llvmlite.ConstNull(pool, ret_ty, "null")
|
||||
if ret_zero is not None and ret_alloca is not None:
|
||||
llvmlite.build_store(wb, ret_zero, ret_alloca)
|
||||
|
||||
# 4. 函数名字符串常量
|
||||
fn_str: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string(
|
||||
wb, pool, mod, func_name, trans)
|
||||
if fn_str is None:
|
||||
fn_str = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||||
|
||||
# 5. handler 声明(未翻译时 declare,固定签名 i32 (i8*,i8*,i32,i8*,i8*,i8*))
|
||||
if HandlesExprCall.find_func_in_module(mod, handler_name) is None:
|
||||
handler_d: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, handler_name, i32_ty)
|
||||
if handler_d is not None:
|
||||
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "ctx")
|
||||
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "func_name")
|
||||
llvmlite.add_param(pool, handler_d, i32_ty, "phase")
|
||||
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "args_ptr")
|
||||
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "ret_ptr")
|
||||
llvmlite.add_param(pool, handler_d, i8_ptr_ty, "decor_args_ptr")
|
||||
|
||||
# 6. 前置阶段:handler 返回调用次数 n_calls
|
||||
ph0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 0, "0")
|
||||
null_ret: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||||
null_dec: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||||
# 参数链表(6 个独立值):ctx_ptr → fn_str → 0 → args_ptr → null → null
|
||||
# 注意:不能 self 链接(null.Next = null 会让 build_call 遍历死循环)
|
||||
if ctx_ptr is not None:
|
||||
llvmlite.value_set_next(ctx_ptr, fn_str)
|
||||
if fn_str is not None:
|
||||
llvmlite.value_set_next(fn_str, ph0)
|
||||
if ph0 is not None:
|
||||
llvmlite.value_set_next(ph0, args_ptr)
|
||||
if args_ptr is not None:
|
||||
llvmlite.value_set_next(args_ptr, null_ret)
|
||||
if null_ret is not None:
|
||||
llvmlite.value_set_next(null_ret, null_dec)
|
||||
n_calls: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||||
wb, handler_name, ctx_ptr, 6, i32_ty, 0)
|
||||
|
||||
# 7. 计数器 alloca(TPV 用 alloca 计数器替代 phi)
|
||||
cnt_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(wb, i32_ty)
|
||||
cnt_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 0, "0")
|
||||
if cnt_alloca is not None and cnt_zero is not None:
|
||||
llvmlite.build_store(wb, cnt_zero, cnt_alloca)
|
||||
llvmlite.build_br(wb, loop_h_bb)
|
||||
|
||||
# 8. loop.header:cur = load cnt; cur < n_calls → body / post
|
||||
llvmlite.position_at_end(wb, loop_h_bb)
|
||||
cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, i32_ty, cnt_alloca)
|
||||
loop_cond: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
wb, llvmlite.ICMP_SLT, cur_i, n_calls)
|
||||
llvmlite.build_cond_br(wb, loop_cond, loop_b_bb, post_bb)
|
||||
|
||||
# 9. loop.body:读回参数(装饰器可能已修改)→ 调用原函数 → store ret
|
||||
llvmlite.position_at_end(wb, loop_b_bb)
|
||||
call_args: llvmlite.Value | t.CPtr = None
|
||||
if n_params > 0:
|
||||
k: int = 0
|
||||
for k in range(n_params):
|
||||
fld_ty_k: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(
|
||||
t.CVoid(param_tys[k], t.CPtr))
|
||||
fld_pk: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
wb, args_ty, fld_ty_k, args_alloca, k)
|
||||
if fld_pk is None:
|
||||
continue
|
||||
fld_vk: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, fld_ty_k, fld_pk)
|
||||
if fld_vk is not None:
|
||||
llvmlite.value_set_next(fld_vk, None)
|
||||
if call_args is None:
|
||||
call_args = fld_vk
|
||||
else:
|
||||
ct: llvmlite.Value | t.CPtr = call_args
|
||||
while ct.Next is not None:
|
||||
ct = ct.Next
|
||||
llvmlite.value_set_next(ct, fld_vk)
|
||||
res_v: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||||
wb, orig_call_name, call_args, n_params, ret_ty, 0)
|
||||
if ret_alloca is not None and res_v is not None:
|
||||
llvmlite.build_store(wb, res_v, ret_alloca)
|
||||
nxt_i: llvmlite.Value | t.CPtr = llvmlite.build_add(
|
||||
wb, cur_i, llvmlite.ConstInt(pool, i32_ty, 1, "1"))
|
||||
if nxt_i is not None and cnt_alloca is not None:
|
||||
llvmlite.build_store(wb, nxt_i, cnt_alloca)
|
||||
llvmlite.build_br(wb, loop_h_bb)
|
||||
|
||||
# 10. post:handler 后置 → 清递归标志 → 返回结果
|
||||
llvmlite.position_at_end(wb, post_bb)
|
||||
ret_ptr: llvmlite.Value | t.CPtr = null_ret
|
||||
if ret_alloca is not None:
|
||||
ret_ptr = llvmlite.build_bitcast(wb, ret_alloca, i8_ptr_ty)
|
||||
ph1: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i32_ty, 1, "1")
|
||||
# 后置参数链:ctx_ptr → fn_str → 1 → args_ptr → ret_ptr → null
|
||||
if ctx_ptr is not None:
|
||||
llvmlite.value_set_next(ctx_ptr, fn_str)
|
||||
if fn_str is not None:
|
||||
llvmlite.value_set_next(fn_str, ph1)
|
||||
if ph1 is not None:
|
||||
llvmlite.value_set_next(ph1, args_ptr)
|
||||
if args_ptr is not None:
|
||||
llvmlite.value_set_next(args_ptr, ret_ptr)
|
||||
if ret_ptr is not None:
|
||||
llvmlite.value_set_next(ret_ptr, null_dec)
|
||||
llvmlite.build_call(wb, handler_name, ctx_ptr, 6, i32_ty, 0)
|
||||
if rec_flag_ref is not None:
|
||||
rec_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i8_ty, 0, "0")
|
||||
if rec_zero2 is not None:
|
||||
llvmlite.build_store(wb, rec_zero2, rec_flag_ref)
|
||||
if ret_is_void != 0:
|
||||
llvmlite.build_ret_void(wb)
|
||||
else:
|
||||
final_v: llvmlite.Value | t.CPtr = llvmlite.build_load(wb, ret_ty, ret_alloca)
|
||||
if final_v is not None:
|
||||
llvmlite.build_ret(wb, final_v)
|
||||
else:
|
||||
llvmlite.build_ret_void(wb)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
# ============================================================
|
||||
# translate_nested_function_def - 嵌套函数提升 + 闭包创建
|
||||
#
|
||||
@@ -1048,7 +1654,7 @@ class FuncGenMixin:
|
||||
HandlesVar.define_var(trans.SymTab, arg_p.arg, p_alloca)
|
||||
if arg_p.annotation is not None:
|
||||
cls_nm_p: str = HandlesType.extract_class_name_from_annotation(
|
||||
arg_p.annotation, imported_modules)
|
||||
arg_p.annotation, imported_modules, pool)
|
||||
if cls_nm_p is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
trans.SymTab, arg_p.arg, cls_nm_p)
|
||||
|
||||
@@ -13,6 +13,7 @@ import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
@@ -91,14 +92,6 @@ class StmtGenMixin:
|
||||
"""翻译单条语句,返回新增的变量数"""
|
||||
if node is None:
|
||||
return 0
|
||||
# OOM 语句级诊断:每 10 语句打印主池用量+行号——定位单文件翻译
|
||||
# (NewAstTest main.vp)从 6.4MB 暴涨到 1.6GB 发生在哪一行
|
||||
self.DiagStmtCount += 1
|
||||
if (self.DiagStmtCount % 10) == 1:
|
||||
pool_diag: memhub.MemBuddy | t.CPtr = CompilerFactory.get_pool()
|
||||
stdio.printf("[MEM] stmt %d line %d used=%zu chk_depth=%zu\n",
|
||||
self.DiagStmtCount, node.lineno,
|
||||
pool_diag.used_bytes(), pool_diag.chk_depth)
|
||||
k: int = node.kind()
|
||||
|
||||
if k == ast.ASTKind.Expr:
|
||||
@@ -143,6 +136,8 @@ class StmtGenMixin:
|
||||
return self.translate_delete(trans, node)
|
||||
elif k == ast.ASTKind.Raise:
|
||||
return self.translate_raise(trans, node)
|
||||
elif k == ast.ASTKind.Try:
|
||||
return self.translate_try(trans, node)
|
||||
elif k == ast.ASTKind.With:
|
||||
return self.translate_with(trans, node)
|
||||
# 未知语句类型:直接报错终止(fail-fast),暴露上游解析问题
|
||||
@@ -173,22 +168,421 @@ class StmtGenMixin:
|
||||
if del_at is not None:
|
||||
HandlesExprCall._try_property_deleter(
|
||||
pool, builder, mod, del_at, trans)
|
||||
# del obj[key] → __delitem__(obj, key)
|
||||
# (对齐 TPC HandlesDelete.py L14-25;此前 Subscript 目标被静默
|
||||
# 忽略,HashTableTest Test 11 的 del ht3[del_buf] 未执行 → len 不变)
|
||||
elif tgt.kind() == ast.ASTKind.Subscript:
|
||||
dl_sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(tgt)
|
||||
if dl_sub is not None and dl_sub.value is not None and dl_sub.slice is not None:
|
||||
dl_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, dl_sub.value, None, 0, trans)
|
||||
dl_idx: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, dl_sub.slice, None, 0, trans)
|
||||
if dl_obj is not None and dl_idx is not None:
|
||||
dl_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(
|
||||
dl_obj)
|
||||
if dl_st is not None:
|
||||
dl_cls: str = HandlesStruct.get_class_name_by_type(pool, dl_st)
|
||||
if dl_cls is not None:
|
||||
dl_lookup: str = pool.alloc(128)
|
||||
if dl_lookup is not None:
|
||||
viperlib.snprintf(dl_lookup, 128, "%s.__delitem__", dl_cls)
|
||||
dl_fn: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(
|
||||
mod, dl_lookup)
|
||||
if dl_fn is not None:
|
||||
dl_ret: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(dl_fn)
|
||||
dl_fn_name: str = llvmlite.function_get_name(dl_fn)
|
||||
if dl_ret is not None and dl_fn_name is not None:
|
||||
# self 参数(容器)按 __delitem__ 首参类型对齐
|
||||
dl_self: llvmlite.Value | t.CPtr = dl_obj
|
||||
dl_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(dl_fn)
|
||||
if dl_first is not None:
|
||||
dl_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(dl_first)
|
||||
if dl_self_ty is not None:
|
||||
dl_self = llvmlite.build_bitcast(builder, dl_obj, dl_self_ty)
|
||||
if dl_self is not None:
|
||||
# 参数链表: self → key(独立 null 结尾)
|
||||
dl_self.Next = dl_idx
|
||||
dl_idx.Next = None
|
||||
llvmlite.build_call(
|
||||
builder, dl_fn_name, dl_self, 2, dl_ret, 0)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# translate_try - try/except 语句翻译
|
||||
#
|
||||
# 对齐 TPC HandlesTry.py L59-214(v1 迁移)。异常 = (i32 code, i8* msg)
|
||||
# 二元组;except X 编译期静态展开 X 及全部子孙异常类编码。布局:
|
||||
# pre → TryBB → DispatchBB(编码检查链)→ MatchBB → ExceptBB → AfterBB
|
||||
# try 体正常结束 → store 0 →(else 若有)→ AfterBB
|
||||
# DispatchBB 无匹配 → UnhandledBB:函数有 EH 输出参数则写入并返回
|
||||
# (向上传播),否则 store 0 → AfterBB(吞掉)
|
||||
# try 上下文(DispatchBB + 两个 alloca)写入 trans._eh_*,translate_raise
|
||||
# 与调用侧 EH 检测(CallGenMixin._emit_eh_guarded_call)据此重定向;
|
||||
# 退出时恢复外层上下文(嵌套 try 支持)。
|
||||
# v1 未实现 finalbody(TestFBProject 未使用;finally+return 交互复杂,
|
||||
# 后续按 TPC HandlesTry.py L188-214 的 pending_ret 方案扩展)。
|
||||
# ============================================================
|
||||
def translate_try(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 try/except 语句,返回 0"""
|
||||
if trans is None or node is None:
|
||||
return 0
|
||||
tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node)
|
||||
if tr is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
if pool is None or builder is None or func is None:
|
||||
return 0
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
|
||||
return 0
|
||||
|
||||
# ---- 1. 异常编码/消息 alloca(当前 try 上下文)----
|
||||
i32_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_t)
|
||||
if i32_ty_t is None or i8_ptr_ty_t is None:
|
||||
return 0
|
||||
exception_code: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i32_ty_t)
|
||||
eh_message: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty_t)
|
||||
if exception_code is None or eh_message is None:
|
||||
return 0
|
||||
init_code_t: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
init_msg_t: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_t, "null")
|
||||
if init_code_t is not None:
|
||||
llvmlite.build_store(builder, init_code_t, exception_code)
|
||||
if init_msg_t is not None:
|
||||
llvmlite.build_store(builder, init_msg_t, eh_message)
|
||||
|
||||
# ---- 2. 块布局(块名唯一化,create_block 不自动编号)----
|
||||
lc_t: int = trans._label_counter
|
||||
trans._label_counter = lc_t + 1
|
||||
bb_buf_t: str = pool.alloc(64)
|
||||
if bb_buf_t is None:
|
||||
return 0
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.dispatch.%d", lc_t)
|
||||
dispatch_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.after.%d", lc_t)
|
||||
after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.unhandled.%d", lc_t)
|
||||
unhandled_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.body.%d", lc_t)
|
||||
try_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
if dispatch_bb is None or after_bb is None or unhandled_bb is None or try_bb is None:
|
||||
return 0
|
||||
else_bb: llvmlite.BasicBlock | t.CPtr = None
|
||||
if tr.orelse is not None and len(tr.orelse) > 0:
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.else.%d", lc_t)
|
||||
else_bb = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
n_handlers_t: t.CSizeT = 0
|
||||
if tr.handlers is not None:
|
||||
n_handlers_t = len(tr.handlers)
|
||||
# 注意:list[ptr](pool, N) 第二参数是 elem_size 不是容量!
|
||||
# 指针元素必须显式传 8(T.__sizeof__ 对联合类型不可靠),
|
||||
# 否则 append 按 N 字节步长错位存取 → 读出垃圾指针(崩溃)。
|
||||
except_bbs: list[llvmlite.BasicBlock | t.CPtr] | t.CPtr = \
|
||||
list[llvmlite.BasicBlock | t.CPtr](pool, 8)
|
||||
match_bbs: list[llvmlite.BasicBlock | t.CPtr] | t.CPtr = \
|
||||
list[llvmlite.BasicBlock | t.CPtr](pool, 8)
|
||||
if except_bbs is None or match_bbs is None:
|
||||
return 0
|
||||
for i_t in range(n_handlers_t):
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.except.%d.%d", lc_t, i_t)
|
||||
eb_t: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.match.%d.%d", lc_t, i_t)
|
||||
mb_t: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
except_bbs.append(eb_t)
|
||||
match_bbs.append(mb_t)
|
||||
|
||||
# ---- 3. 保存外层 try 上下文,设置本 try 上下文 ----
|
||||
old_dispatch_t: llvmlite.BasicBlock | t.CPtr = trans._eh_dispatch_bb
|
||||
old_code_t: llvmlite.Value | t.CPtr = trans._eh_code_ptr
|
||||
old_msg_t: llvmlite.Value | t.CPtr = trans._eh_msg_ptr
|
||||
trans._eh_dispatch_bb = dispatch_bb
|
||||
trans._eh_code_ptr = exception_code
|
||||
trans._eh_msg_ptr = eh_message
|
||||
|
||||
# ---- 4. Try 体 ----
|
||||
llvmlite.build_br(builder, try_bb)
|
||||
llvmlite.position_at_end(builder, try_bb)
|
||||
if tr.children is not None:
|
||||
tb_n: t.CSizeT = len(tr.children)
|
||||
for tbi in range(tb_n):
|
||||
stmt_t: ast.AST | t.CPtr = tr.children.get(tbi)
|
||||
if stmt_t is not None:
|
||||
self.translate_stmt(trans, stmt_t)
|
||||
# 正常走完 try 体:清异常码,进 else(若有)或 After
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
if init_code_t is not None:
|
||||
llvmlite.build_store(builder, init_code_t, exception_code)
|
||||
if else_bb is not None:
|
||||
llvmlite.build_br(builder, else_bb)
|
||||
else:
|
||||
llvmlite.build_br(builder, after_bb)
|
||||
|
||||
# ---- 5. DispatchBB:编码检查链 ----
|
||||
llvmlite.position_at_end(builder, dispatch_bb)
|
||||
if n_handlers_t == 0:
|
||||
# 无 except(非法 try,防御):直接吞掉
|
||||
llvmlite.build_br(builder, unhandled_bb)
|
||||
else:
|
||||
eh_code_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i32_ty_t, exception_code)
|
||||
next_check_t: llvmlite.BasicBlock | t.CPtr = None
|
||||
for i_t in range(n_handlers_t):
|
||||
hdr_t: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(
|
||||
tr.handlers.get(i_t))
|
||||
match_bb_t: llvmlite.BasicBlock | t.CPtr = match_bbs.get(i_t)
|
||||
if i_t > 0 and next_check_t is not None:
|
||||
llvmlite.position_at_end(builder, next_check_t)
|
||||
eh_code_val = llvmlite.build_load(
|
||||
builder, i32_ty_t, exception_code)
|
||||
if hdr_t is None or hdr_t.type is None:
|
||||
# 裸 except:无条件匹配
|
||||
llvmlite.build_br(builder, match_bb_t)
|
||||
else:
|
||||
# 展开匹配编码集(handler.type 自身 + 全部子孙异常类)
|
||||
hname_t: str = None
|
||||
htype_t: ast.AST | t.CPtr = hdr_t.type
|
||||
if htype_t.kind() == ast.ASTKind.Name:
|
||||
hname_t = ((ast.Name | t.CPtr)(htype_t)).id
|
||||
elif htype_t.kind() == ast.ASTKind.Attribute:
|
||||
hname_t = ((ast.Attribute | t.CPtr)(htype_t)).attr
|
||||
# 匹配编码缓冲:必须是 t.CInt*(i32 步长)——collect_descendant_codes
|
||||
# 按 out_codes[i](4 字节)写入;若用 t.CSizeT*(8 字节)读,
|
||||
# 多码时读出 (code[i+1]<<32)|code[i] 的 64 位拼接垃圾(单码时
|
||||
# 高位恰为 0 掩盖;Test 2/3/8 父类多码捕获失败的根因)。
|
||||
codes_buf_t: t.CInt | t.CPtr = pool.alloc(64 * 4)
|
||||
if codes_buf_t is None:
|
||||
return 0
|
||||
n_codes_t: int = 0
|
||||
if hname_t is not None and HandlesClassDef.is_exception_name(hname_t) != 0:
|
||||
n_codes_t = HandlesClassDef.collect_descendant_codes(
|
||||
hname_t, codes_buf_t, 64)
|
||||
else:
|
||||
c0_t: int = 1
|
||||
if hname_t is not None:
|
||||
c0_t = HandlesClassDef.lookup_exception_code(hname_t)
|
||||
if c0_t == 0:
|
||||
c0_t = 1
|
||||
codes_buf_t[0] = c0_t
|
||||
n_codes_t = 1
|
||||
match_cond_t: llvmlite.Value | t.CPtr = None
|
||||
for ci_t in range(n_codes_t):
|
||||
code_val_t: llvmlite.Value | t.CPtr = llvmlite.const_int32(
|
||||
pool, codes_buf_t[ci_t])
|
||||
is_match_t: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_EQ, eh_code_val, code_val_t)
|
||||
if match_cond_t is None:
|
||||
match_cond_t = is_match_t
|
||||
elif is_match_t is not None:
|
||||
match_cond_t = llvmlite.build_or(
|
||||
builder, match_cond_t, is_match_t)
|
||||
if i_t < n_handlers_t - 1:
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.check.%d.%d", lc_t, i_t)
|
||||
next_check_t = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
else:
|
||||
next_check_t = unhandled_bb
|
||||
llvmlite.build_cond_br(
|
||||
builder, match_cond_t, match_bb_t, next_check_t)
|
||||
# MatchBB:绑定 handler 变量(e = 消息指针),跳 ExceptBB
|
||||
llvmlite.position_at_end(builder, match_bb_t)
|
||||
if hdr_t is not None and hdr_t.name is not None and hdr_t.name[0] != '\0':
|
||||
# 同名 handler 变量复用函数入口 alloca(find_var 首条命中、
|
||||
# 重复 define_var 不 shadow——多 try 共用 `as e` 时各 MatchBB
|
||||
# 各自 store 消息,各 ExceptBB 读同一入口 alloca,避免
|
||||
# 非支配 alloca 触发 "does not dominate all uses")。
|
||||
h_ent_t: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
trans.SymTab, hdr_t.name)
|
||||
if h_ent_t is not None and h_ent_t.Alloca is not None:
|
||||
h_alloca_t: llvmlite.Value | t.CPtr = h_ent_t.Alloca
|
||||
else:
|
||||
h_alloca_t = HandlesVar._alloca_at_entry(builder, i8_ptr_ty_t)
|
||||
if h_alloca_t is not None:
|
||||
HandlesVar.define_var(trans.SymTab, hdr_t.name, h_alloca_t)
|
||||
if h_alloca_t is not None:
|
||||
h_msg_t: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i8_ptr_ty_t, eh_message)
|
||||
if h_msg_t is not None:
|
||||
llvmlite.build_store(builder, h_msg_t, h_alloca_t)
|
||||
except_bb_t: llvmlite.BasicBlock | t.CPtr = except_bbs.get(i_t)
|
||||
llvmlite.build_br(builder, except_bb_t)
|
||||
|
||||
# ---- 6. UnhandledBB:无 except 匹配 → 向上传播或吞掉 ----
|
||||
llvmlite.position_at_end(builder, unhandled_bb)
|
||||
if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \
|
||||
and trans._eh_code_out_param is not None:
|
||||
un_msg_t: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i8_ptr_ty_t, eh_message)
|
||||
un_code_t: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i32_ty_t, exception_code)
|
||||
if un_msg_t is not None:
|
||||
llvmlite.build_store(builder, un_msg_t, trans._eh_msg_out_param)
|
||||
if un_code_t is not None:
|
||||
llvmlite.build_store(builder, un_code_t, trans._eh_code_out_param)
|
||||
self._eh_ret_default(trans, pool, builder)
|
||||
else:
|
||||
if init_code_t is not None:
|
||||
llvmlite.build_store(builder, init_code_t, exception_code)
|
||||
llvmlite.build_br(builder, after_bb)
|
||||
|
||||
# ---- 7. Except 体 ----
|
||||
for i_t in range(n_handlers_t):
|
||||
hdr2_t: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(
|
||||
tr.handlers.get(i_t))
|
||||
except_bb2_t: llvmlite.BasicBlock | t.CPtr = except_bbs.get(i_t)
|
||||
llvmlite.position_at_end(builder, except_bb2_t)
|
||||
if hdr2_t is not None and hdr2_t.children is not None:
|
||||
hn2_t: t.CSizeT = len(hdr2_t.children)
|
||||
for hi2 in range(hn2_t):
|
||||
stmt2_t: ast.AST | t.CPtr = hdr2_t.children.get(hi2)
|
||||
if stmt2_t is not None:
|
||||
self.translate_stmt(trans, stmt2_t)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, after_bb)
|
||||
|
||||
# ---- 8. Else 体 ----
|
||||
if else_bb is not None:
|
||||
llvmlite.position_at_end(builder, else_bb)
|
||||
if tr.orelse is not None:
|
||||
en_t: t.CSizeT = len(tr.orelse)
|
||||
for ei in range(en_t):
|
||||
stmt3_t: ast.AST | t.CPtr = tr.orelse.get(ei)
|
||||
if stmt3_t is not None:
|
||||
self.translate_stmt(trans, stmt3_t)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, after_bb)
|
||||
|
||||
# ---- 9. AfterBB + 恢复外层 try 上下文 ----
|
||||
llvmlite.position_at_end(builder, after_bb)
|
||||
trans._eh_dispatch_bb = old_dispatch_t
|
||||
trans._eh_code_ptr = old_code_t
|
||||
trans._eh_msg_ptr = old_msg_t
|
||||
return 0
|
||||
|
||||
def translate_raise(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 raise 语句,返回 0
|
||||
|
||||
Viper 无异常传播机制:raise 统一按"终止当前函数并返回零值"处理,
|
||||
对齐 TPC HandlesRaise 的 StopIteration 语义——迭代器 __next__ 用
|
||||
null/0 表示迭代结束(如 dict.__next__ 的 `raise StopIteration`)。
|
||||
非 StopIteration 的 raise 同样返回零值(异常消息忽略)。
|
||||
对齐 TPC HandlesRaise.py 的 try-except 语义(v1 迁移):
|
||||
- StopIteration:置 __stop_iter_flag__ = 1 后返回默认值(迭代结束协议)
|
||||
- 非 StopIteration:
|
||||
1. 处于 try(trans._eh_dispatch_bb 非空):异常编码/消息写入当前
|
||||
try 的 eh_code/eh_message alloca,分支到 DispatchBB 由 except 链裁决
|
||||
2. 函数有 EH 输出参数(_cur_func_has_eh):编码/消息写入
|
||||
__eh_code_out__/__eh_msg_out__,返回默认值(异常向调用方传播)
|
||||
3. 两者皆无:仅返回默认值(v1 语义:异常被吞掉)
|
||||
"""
|
||||
if trans is None or node is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
if pool is None or builder is None:
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
if pool is None or builder is None or mod is None:
|
||||
return 0
|
||||
rn: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(node)
|
||||
if rn is None or rn.exc is None:
|
||||
# bare raise(无 exc):v1 无活动异常可再抛,仅返回默认值
|
||||
self._eh_ret_default(trans, pool, builder)
|
||||
return 0
|
||||
|
||||
# OOP iter 协议:raise StopIteration → 置 __stop_iter_flag__ = 1
|
||||
# (对齐 TPC HandlesRaise.py L76-100),随后按迭代结束返回默认值。
|
||||
ek: int = rn.exc.kind()
|
||||
is_stop_iter: int = 0
|
||||
if ek == ast.ASTKind.Name:
|
||||
enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn.exc)
|
||||
if enm.id is not None and string.strcmp(enm.id, "StopIteration") == 0:
|
||||
is_stop_iter = 1
|
||||
elif ek == ast.ASTKind.Call:
|
||||
ecl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn.exc)
|
||||
if ecl.func is not None and ecl.func.kind() == ast.ASTKind.Name:
|
||||
ecn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl.func)
|
||||
if ecn.id is not None and string.strcmp(ecn.id, "StopIteration") == 0:
|
||||
is_stop_iter = 1
|
||||
if is_stop_iter != 0:
|
||||
if trans._stop_iter_flag_ptr is not None:
|
||||
i1_ty_r: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||||
if i1_ty_r is not None:
|
||||
one_i1_r: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||||
pool, i1_ty_r, 1, "1")
|
||||
if one_i1_r is not None:
|
||||
llvmlite.build_store(
|
||||
builder, one_i1_r, trans._stop_iter_flag_ptr)
|
||||
self._eh_ret_default(trans, pool, builder)
|
||||
return 0
|
||||
|
||||
# ---- 非 StopIteration:计算异常编码与消息 ----
|
||||
exc_code: int = 1
|
||||
exc_msg: llvmlite.Value | t.CPtr = None
|
||||
if ek == ast.ASTKind.Constant:
|
||||
cst_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rn.exc)
|
||||
if cst_r is not None and cst_r.const_kind == ast.CONST_INT:
|
||||
exc_code = cst_r.int_val
|
||||
elif ek == ast.ASTKind.Name:
|
||||
enm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn.exc)
|
||||
if enm2.id is not None:
|
||||
exc_code = HandlesClassDef.lookup_exception_code(enm2.id)
|
||||
if exc_code == 0:
|
||||
exc_code = 1
|
||||
elif ek == ast.ASTKind.Call:
|
||||
ecl2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn.exc)
|
||||
if ecl2.func is not None and ecl2.func.kind() == ast.ASTKind.Name:
|
||||
ecn2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl2.func)
|
||||
if ecn2.id is not None:
|
||||
exc_code = HandlesClassDef.lookup_exception_code(ecn2.id)
|
||||
if exc_code == 0:
|
||||
exc_code = 1
|
||||
if ecl2.args is not None and len(ecl2.args) > 0:
|
||||
exc_msg = HandlesExpr.translate_value(
|
||||
builder, pool, mod, ecl2.args.get(0), None, 0, trans)
|
||||
|
||||
# ---- 异常分发 ----
|
||||
# 1. try 内:写入 try 的 eh_code/eh_message alloca,分支 DispatchBB
|
||||
if trans._eh_dispatch_bb is not None and trans._eh_code_ptr is not None:
|
||||
code_val_r: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, exc_code)
|
||||
if code_val_r is not None:
|
||||
llvmlite.build_store(builder, code_val_r, trans._eh_code_ptr)
|
||||
if exc_msg is None:
|
||||
exc_msg = llvmlite.ConstNull(
|
||||
pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null")
|
||||
if exc_msg is not None and trans._eh_msg_ptr is not None:
|
||||
llvmlite.build_store(builder, exc_msg, trans._eh_msg_ptr)
|
||||
llvmlite.build_br(builder, trans._eh_dispatch_bb)
|
||||
return 0
|
||||
# 2. 函数有 EH 输出参数:写入 out 参数(异常向调用方传播)
|
||||
if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \
|
||||
and trans._eh_code_out_param is not None:
|
||||
code_val_r2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, exc_code)
|
||||
if code_val_r2 is not None:
|
||||
llvmlite.build_store(builder, code_val_r2, trans._eh_code_out_param)
|
||||
if exc_msg is None:
|
||||
exc_msg = llvmlite.ConstNull(
|
||||
pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null")
|
||||
if exc_msg is not None:
|
||||
llvmlite.build_store(builder, exc_msg, trans._eh_msg_out_param)
|
||||
self._eh_ret_default(trans, pool, builder)
|
||||
return 0
|
||||
# 3. 无 try 无 EH 参数:仅返回默认值
|
||||
self._eh_ret_default(trans, pool, builder)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _eh_ret_default - 异常路径返回当前函数的默认零值
|
||||
#
|
||||
# 对齐 TPC HandlesTry.py UnhandledBB / HandlesRaise.py 的返回生成
|
||||
# (void→ret_void,ptr→null,float→0.0,其余→零值)。当前块已
|
||||
# 终结(前一条是 raise/return)时跳过,避免在终止块后插指令。
|
||||
# ============================================================
|
||||
def _eh_ret_default(self, trans: HT.Translator | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr) -> int:
|
||||
"""异常路径返回当前函数默认零值,返回 0"""
|
||||
if trans is None or builder is None:
|
||||
return 0
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
|
||||
return 0
|
||||
cur_func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
if cur_func is None:
|
||||
@@ -327,6 +721,20 @@ class StmtGenMixin:
|
||||
if cls_name is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
trans.SymTab, asname, cls_name)
|
||||
# FakeDuck: __provides__ 元数据 → 生成 _push_provider 调用
|
||||
# (对齐 TPC HandlesWith.py L138-159;经 gen 单例委托 CallGenMixin。
|
||||
# 类名去模块前缀后查 __provides__ 表,如 memhub.MemBuddy → MemBuddy)
|
||||
fd_cls_bare: str = cls_name
|
||||
if cls_name is not None:
|
||||
fd_dot: str = string.strrchr(cls_name, '.')
|
||||
if fd_dot is not None:
|
||||
fd_cls_bare = fd_dot + 1
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g_fd6: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||||
if g_fd6 is not None and fd_cls_bare is not None:
|
||||
g_fd6._emit_provider_push(
|
||||
trans, pool, builder, mod, fd_cls_bare, ctx_val)
|
||||
|
||||
# 2. 翻译 body
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = wt.children
|
||||
@@ -337,6 +745,24 @@ class StmtGenMixin:
|
||||
if st is not None:
|
||||
self.translate_stmt(trans, st)
|
||||
|
||||
# 2.5 FakeDuck: __provides__ 元数据 → 生成 _pop_provider 调用
|
||||
# (对齐 TPC HandlesWith.py L167-174;逆序弹栈,经 gen 单例委托)
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g_fd6b: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||||
if g_fd6b is not None:
|
||||
for pi_pop in range(n):
|
||||
if ctx_class_buf[pi_pop] != 0:
|
||||
cls_pop: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[pi_pop], t.CPtr))
|
||||
fd_cls_bare_p: str = cls_pop
|
||||
if cls_pop is not None:
|
||||
fd_dot_p: str = string.strrchr(cls_pop, '.')
|
||||
if fd_dot_p is not None:
|
||||
fd_cls_bare_p = fd_dot_p + 1
|
||||
if fd_cls_bare_p is not None:
|
||||
g_fd6b._emit_provider_pop(
|
||||
trans, pool, builder, mod, fd_cls_bare_p)
|
||||
|
||||
# 3. 逆序调用 __exit__()(Python with 语义:后进先出)
|
||||
for i in range(n):
|
||||
ci: int = n - 1 - i
|
||||
@@ -789,6 +1215,12 @@ class StmtGenMixin:
|
||||
if bop.op == ast.OpKind.Add: return lv + rv
|
||||
if bop.op == ast.OpKind.Sub: return lv - rv
|
||||
if bop.op == ast.OpKind.Mult: return lv * rv
|
||||
if bop.op == ast.OpKind.Div:
|
||||
# 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355)
|
||||
if rv == 0:
|
||||
self.CifEvalOk = 0
|
||||
return 0
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.FloorDiv:
|
||||
if rv == 0:
|
||||
self.CifEvalOk = 0
|
||||
@@ -1207,6 +1639,15 @@ class StmtGenMixin:
|
||||
if enum_entry is None or member_name is None or member_ty is None:
|
||||
return -1
|
||||
|
||||
# 去重:同名成员已存在则跳过(跨模块同名枚举合并注册 / 同模块
|
||||
# 重复处理幂等——如 w32.fileio 与 fat32_types 都有 FRESULT)
|
||||
for ei_d in range(enum_entry.MemberCount):
|
||||
ex_d: HandlesEnum.EnumMember | t.CPtr = self._get_enum_member(
|
||||
enum_entry, ei_d)
|
||||
if ex_d is not None and ex_d.Name is not None:
|
||||
if string.strcmp(ex_d.Name, member_name) == 0:
|
||||
return ei_d
|
||||
|
||||
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
|
||||
fb_em: str = VLogger.fmt_buf()
|
||||
if fb_em is not None:
|
||||
|
||||
@@ -35,10 +35,12 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
# 常量(与 HandlesStruct 保持一致)
|
||||
# ============================================================
|
||||
STRUCT_MAX: t.CDefine = 512
|
||||
# 字段槽位上限制(与 HandlesStruct 一致:对象化后 Generator 50+ 字段)
|
||||
FIELD_MAX: t.CDefine = 64
|
||||
# 字段槽位上限制(与 HandlesStruct 保持一致;Generator 12 Mixin 展平 ~97 字段,
|
||||
# 2026-08-16 追加78:64 截断导致第 9+ 父类字段(StmtGenMixin.DiagStmtCount 等)
|
||||
# 丢失 → __init__ 写 self.DiagStmtCount "属性写入失败")
|
||||
FIELD_MAX: t.CDefine = 128
|
||||
FIELD_NAME_MAX: t.CDefine = 64
|
||||
PARENT_MAX: t.CDefine = 8
|
||||
PARENT_MAX: t.CDefine = 16
|
||||
MRO_MAX: t.CDefine = 16
|
||||
|
||||
|
||||
@@ -498,6 +500,33 @@ class StructGenMixin:
|
||||
# 无 SHA1:按类名查找第一个
|
||||
return self.find_struct(name)
|
||||
|
||||
def reset_module_methods_emitted(self, sha1: str) -> int:
|
||||
"""回滚指定模块注册类的 MethodsEmitted 标志(Phase A 重试前调用)
|
||||
|
||||
根因(追加87):Phase A 第 1 遍翻译类方法体时 _translate_oop_methods
|
||||
先置 MethodsEmitted=1(防重入)再发射方法;方法体内跨模块调用因依赖
|
||||
text.ll 未生成触发 trans._deps_pending → 整文件不写盘下遍重译。但
|
||||
MethodsEmitted 存于 perm_pool 分配的 StructEntry,跨 mb.reset_to(mark2)
|
||||
存活 → 第 2 遍 existing 分支被 _translate_oop_methods 的
|
||||
MethodsEmitted==1 防重复检查拦截 → 类方法(含 __before_init__)永不
|
||||
发射 → 链接 undefined symbol(模块级函数不受此标志保护所以正常,
|
||||
AssignGenMixin text.ll 空 / HandlesTranslator 有模块函数缺类方法)。
|
||||
按本文件 ModuleSha1 精确回滚,不影响其他已写盘文件的 MethodsEmitted。
|
||||
"""
|
||||
if sha1 is None or self.StructTable is None:
|
||||
return 0
|
||||
if self.StructCount < 0 or self.StructCount > 200000:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (reset_module_methods_emitted)", "STRUCT")
|
||||
return 0
|
||||
reset_count: int = 0
|
||||
for i in range(self.StructCount):
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||||
if entry is not None and entry.ModuleSha1 is not None:
|
||||
if string.strcmp(entry.ModuleSha1, sha1) == 0:
|
||||
entry.MethodsEmitted = 0
|
||||
reset_count += 1
|
||||
return reset_count
|
||||
|
||||
def find_struct_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> HandlesStruct.StructEntry | t.CPtr:
|
||||
"""按类型指针查找结构体(指针值比较),返回 StructEntry 或 None
|
||||
|
||||
@@ -641,6 +670,37 @@ class StructGenMixin:
|
||||
if fe is not None and fe.Name is not None:
|
||||
if string.strcmp(fe.Name, field_name) == 0:
|
||||
return fe
|
||||
# REnum 变体字段别名回退:REnum 类(如 LLVMType)的变体内部字段
|
||||
# (Ptr.Pointee 等)不是普通字段,而是 _p1/_p2 槽位别名。此前在调用方
|
||||
# (ExprGenMixin 按需过滤 L5046/L5500)回退,但本函数字段未找到的
|
||||
# VLogger.error 立即 sys.exit(1),调用方回退永远执行不到("LLVMType 已注册
|
||||
# 但字段 Pointee 未找到"四次依旧的根因)。此处直接查变体别名,所有调用方
|
||||
# 统一受益。注意:_lookup_renum_field_alias 用 class_name 指针值比较,
|
||||
# 必须传 entry.Name(register_struct 复制 + _update_renum_alias_class_ptr
|
||||
# 统一后的池指针),传调用方 class_name(AnnotClassName 等不同指针)
|
||||
# 恒不匹配 → 返回 -1 → 回退失效。
|
||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
rn_cls_l: str = entry.Name
|
||||
if rn_cls_l is None:
|
||||
rn_cls_l = class_name
|
||||
rn_is_renum_l: int = HandlesClassDef._is_renum_class_name(class_name)
|
||||
if rn_is_renum_l == 0 and rn_cls_l is not None:
|
||||
# 类名可能是模块限定名("mod.LLVMType"),REnum 表存裸名,双保险
|
||||
rn_is_renum_l = HandlesClassDef._is_renum_class_name(rn_cls_l)
|
||||
rn_alias_l: int = -1
|
||||
if rn_is_renum_l != 0:
|
||||
rn_alias_l = HandlesClassDef._lookup_renum_field_alias(
|
||||
rn_cls_l, field_name)
|
||||
if rn_alias_l < 1 and class_name is not rn_cls_l:
|
||||
# 双保险:别名表可能仍持有旧 AST 指针(_update_renum_alias_class_ptr
|
||||
# 未执行/多模块重复注册场景),用调用方 class_name 再试一次
|
||||
rn_alias_l = HandlesClassDef._lookup_renum_field_alias(
|
||||
class_name, field_name)
|
||||
if rn_alias_l >= 1:
|
||||
rn_fe_l: HandlesStruct.FieldEntry | t.CPtr = \
|
||||
HandlesStruct._get_field_entry(entry, rn_alias_l)
|
||||
if rn_fe_l is not None and rn_fe_l.Ty is not None:
|
||||
return rn_fe_l
|
||||
# 诊断:找到结构体但字段确实未找到,打印字段表
|
||||
# 注意:VLogger.error 会立即退出进程,字段表须在 error 之前用 warning 打印
|
||||
for fi in range(entry.FieldCount):
|
||||
@@ -655,9 +715,19 @@ class StructGenMixin:
|
||||
VLogger.warning(fb_fn, "STRUCT")
|
||||
fb_fields: str = VLogger.fmt_buf()
|
||||
if fb_fields is not None:
|
||||
viperlib.snprintf(fb_fields, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d) 但字段 '%s' 未找到",
|
||||
class_name, entry.FieldCount, field_name)
|
||||
if rn_is_renum_l != 0:
|
||||
# 报错友好化:REnum 类直接说明是"变体字段别名查找失败",并附
|
||||
# entry.Name 与别名槽位结果,一眼可辨"别名未注册"(槽位=-1)
|
||||
# 还是"class_name 指针未统一"(已注册但传错指针查不到)
|
||||
viperlib.snprintf(fb_fields, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 是 REnum 类(FieldCount=%d),"
|
||||
"变体字段 '%s' 别名查找失败(entry.Name='%s',别名槽位=%d,"
|
||||
"请检查该变体字段是否已注册别名,或 class_name 指针是否统一)",
|
||||
class_name, entry.FieldCount, field_name, rn_cls_l, rn_alias_l)
|
||||
else:
|
||||
viperlib.snprintf(fb_fields, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d) 但字段 '%s' 未找到",
|
||||
class_name, entry.FieldCount, field_name)
|
||||
VLogger.error(fb_fields, "STRUCT")
|
||||
# 诊断:找到结构体但字段未找到
|
||||
return None
|
||||
@@ -1204,7 +1274,15 @@ class StructGenMixin:
|
||||
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
|
||||
case llvmlite.LLVMType.Array(elem_ty, acount):
|
||||
# 数组类型:元素如果是值类型结构体,需要完整定义
|
||||
# (如 zhuff_decode_tree = {MemManager*, [576 x zhuff_decode_node],
|
||||
# i32, i32}——Array 元素 node 只递归字段不发射定义 → llc "use of
|
||||
# undefined type named '...zhuff_decode_node'",ZlibTest 根因)
|
||||
if elem_ty is not None:
|
||||
match elem_ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
self.ensure_struct_def_in_module(pool, mod, elem_ty)
|
||||
case _:
|
||||
pass
|
||||
self._ensure_field_types_in_module(pool, mod, elem_ty)
|
||||
case _:
|
||||
pass
|
||||
|
||||
@@ -44,7 +44,7 @@ import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
# ============================================================
|
||||
# 常量(与 HandlesTranslator 保持一致)
|
||||
# ============================================================
|
||||
MAX_VARS: t.CDefine = 256
|
||||
MAX_VARS: t.CDefine = 1024
|
||||
MAX_FUNCS: t.CDefine = 1024
|
||||
MAX_GLOBAL_NAMES: t.CDefine = 32
|
||||
|
||||
@@ -282,6 +282,50 @@ class TranslatorGenMixin:
|
||||
viperlib.snprintf(buf + pos, buf_size - pos, "]")
|
||||
return buf
|
||||
|
||||
# ============================================================
|
||||
# _build_string_array_initializer_text - 字符串字面量初始化数组全局
|
||||
#
|
||||
# t.CArray[t.CChar, N] = "..." → [i8 b0, i8 b1, ..., i8 0, ...]
|
||||
# (字符串字节 + 零填充到数组长度;空串返回 zeroinitializer)。
|
||||
# 此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] <ptr>
|
||||
# 类型不匹配(llc constant expression type mismatch,
|
||||
# pyzlib_error_msg = global [512 x i8] <GEP ptr> 根因)。
|
||||
# ============================================================
|
||||
def _build_string_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
var_ty: llvmlite.LLVMType | t.CPtr,
|
||||
str_val: str) -> str:
|
||||
"""字符串字面量初始化数组全局,返回初始化器文本或 None"""
|
||||
if var_ty is None or str_val is None:
|
||||
return None
|
||||
arr_count: t.CInt = 0
|
||||
match var_ty:
|
||||
case llvmlite.LLVMType.Array(_, cnt):
|
||||
arr_count = cnt
|
||||
if arr_count <= 0:
|
||||
return None
|
||||
slen: t.CSizeT = string.strlen(str_val)
|
||||
if slen == 0:
|
||||
return "zeroinitializer"
|
||||
buf_size: t.CSizeT = 64 + t.CSizeT(arr_count) * 16
|
||||
buf: str = pool.alloc(buf_size)
|
||||
if buf is None:
|
||||
return None
|
||||
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
|
||||
pos: t.CSizeT = t.CSizeT(written)
|
||||
i: t.CSizeT = 0
|
||||
while i < t.CSizeT(arr_count):
|
||||
if i > 0:
|
||||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||||
pos += t.CSizeT(written)
|
||||
bv: t.CInt64T = 0
|
||||
if i < slen:
|
||||
bv = t.CInt64T(str_val[i])
|
||||
written = viperlib.snprintf(buf + pos, buf_size - pos, "i8 %lld", bv)
|
||||
pos += t.CSizeT(written)
|
||||
i += 1
|
||||
viperlib.snprintf(buf + pos, buf_size - pos, "]")
|
||||
return buf
|
||||
|
||||
# ============================================================
|
||||
# _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量
|
||||
#
|
||||
@@ -423,6 +467,16 @@ class TranslatorGenMixin:
|
||||
if var_name is None:
|
||||
return 0
|
||||
|
||||
# __all__ 是 Python 模块元数据(公开名列表),无运行时语义:
|
||||
# StubGen 的 .vpi 不为其生成 stub 声明(无注解模块级赋值不产出 vpi
|
||||
# 条目),此处同样跳过全局创建——否则无注解 list-of-strings 全局
|
||||
# 类型推断缺失(var_ty 默认 i32)→ _build_array_initializer_text
|
||||
# 返回 None → fail-fast "初始化器构建失败" 误报
|
||||
# (Projectrans/__init__.vp 追加83 根因)。与 CDefine/CTypedef
|
||||
# 同类:编译期/元数据实体不落入 LLVM 全局。
|
||||
if string.strcmp(var_name, "__all__") == 0:
|
||||
return 0
|
||||
|
||||
# 检查是否已注册
|
||||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||||
trans.SymTab, var_name)
|
||||
@@ -457,13 +511,33 @@ class TranslatorGenMixin:
|
||||
# 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer
|
||||
HandlesType.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||||
elif init_kind == 3:
|
||||
# 字符串字面量 → 创建字符串常量全局 + GEP 引用
|
||||
str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val)
|
||||
if str_init is not None:
|
||||
gv.Initializer = str_init
|
||||
# 字符串字面量初始化
|
||||
# 数组类型(t.CArray[t.CChar, N]):字节数组初始化器(字符串内容 + 零填充)
|
||||
# ——此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] <ptr> 类型
|
||||
# 不匹配(llc constant expression type mismatch,pyzlib_error_msg 根因)
|
||||
is_arr_g: int = 0
|
||||
match var_ty:
|
||||
case llvmlite.LLVMType.Array(_, _):
|
||||
is_arr_g = 1
|
||||
case _:
|
||||
pass
|
||||
if is_arr_g != 0:
|
||||
arr_str_init: str = self._build_string_array_initializer_text(
|
||||
pool, var_ty, init_str_val)
|
||||
if arr_str_init is not None:
|
||||
gv.Initializer = arr_str_init
|
||||
else:
|
||||
HandlesType.fatal_error(
|
||||
node, f"模块级数组变量 '{var_name}' 字符串初始化器构建失败", "TypeError")
|
||||
else:
|
||||
# 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer
|
||||
HandlesType.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||||
# 指针类型(如 b64_tab: t.CArray[t.CChar, None] = "ABC..."):
|
||||
# 创建字符串常量全局 + GEP 引用
|
||||
str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val)
|
||||
if str_init is not None:
|
||||
gv.Initializer = str_init
|
||||
else:
|
||||
HandlesType.fatal_error(
|
||||
node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||||
else:
|
||||
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
|
||||
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
|
||||
@@ -484,7 +558,7 @@ class TranslatorGenMixin:
|
||||
aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa_ml is not None and aa_ml.annotation is not None:
|
||||
cls_nm_ml: str = HandlesType.extract_class_name_from_annotation(
|
||||
aa_ml.annotation, trans._imported_modules)
|
||||
aa_ml.annotation, trans._imported_modules, pool)
|
||||
if cls_nm_ml is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
trans.SymTab, var_name, cls_nm_ml)
|
||||
|
||||
@@ -14,6 +14,7 @@ import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesEnum as HandlesEnum
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
|
||||
|
||||
@@ -38,7 +39,6 @@ import lib.core.Handles.HandlesType as HandlesType
|
||||
# ============================================================
|
||||
TRACE_MAX: t.CDefine = 32
|
||||
MAX_CTYPEDEF_DEPTH: t.CDefine = 10
|
||||
_SRC_BUF_SIZE: t.CDefine = 262144
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -212,11 +212,13 @@ class TypeGenMixin:
|
||||
pass
|
||||
|
||||
def register_cdefine_constant(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, value: int) -> None:
|
||||
name: str, value: t.CInt64T) -> None:
|
||||
"""注册 CDefine 编译期常量到本地表
|
||||
|
||||
值以十进制字符串存储。注意:value 是 32 位有符号整数,
|
||||
0xFFFFFFFF 会存储为 "-1",lookup 时用 found 标志区分"未找到"和值为 -1。
|
||||
值以十进制字符串存储(64 位 %lld)。大整数 CDefine(如
|
||||
sys.maxsize = 9223372036854775807)必须全精度保存,否则 %d 32 位截断
|
||||
成 -1(0xFFFFFFFF)→ 读回 4294967295(SysLibTest maxsize FAIL 根因)。
|
||||
0xFFFFFFFF 仍存为 "4294967295",常量生成端 const_int32 内部截断回 -1。
|
||||
"""
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
@@ -226,7 +228,7 @@ class TypeGenMixin:
|
||||
self.CDefineNames.append(name)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
viperlib.snprintf(val_buf, 32, "%d", value)
|
||||
viperlib.snprintf(val_buf, 32, "%lld", value)
|
||||
self.CDefineValues.append(val_buf)
|
||||
else:
|
||||
self.CDefineValues.append("0")
|
||||
@@ -261,7 +263,6 @@ class TypeGenMixin:
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.append(0)
|
||||
# fail-fast:CDefine 值缓冲区分配失败必须终止编译,
|
||||
# 绝不以 "(null)" 掩盖内存分配异常。
|
||||
if val_buf is None:
|
||||
VLogger.error("CDefine 浮点值缓冲区分配失败", "CDEF-DBG")
|
||||
HandlesType.fatal_error(None, "CDefine 浮点值缓冲区分配失败", "MemoryError")
|
||||
@@ -295,6 +296,14 @@ class TypeGenMixin:
|
||||
self.CDefineDoubleFlags.append(0)
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.append(1)
|
||||
# 同步设置"最近注册/查表结果为字符串"标志(is_cdefine_str() 读取)。
|
||||
# 跨模块字符串 CDefine 读回(_lookup_cross_module_cdefine 字符串分支只调
|
||||
# 本函数 + 尾部 set_cdefine_found,无 lookup_cdefine_string 回查)→ 若此处
|
||||
# 不设标志,属性路径 is_cdefine_str()==0 → 退化为整数分支返回 0 →
|
||||
# IR 生成 inttoptr i32 0(NULL)→ 运行时报 (null-) + strlen(NULL-) 崩溃
|
||||
# (test_pyzlib.vp pyzlib.ZLIB_VERSION 根因)。
|
||||
self.CDefineIsStr = 1
|
||||
self.CDefineFound = 1
|
||||
|
||||
# ============================================================
|
||||
# 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用)
|
||||
@@ -370,10 +379,11 @@ class TypeGenMixin:
|
||||
return val_str
|
||||
return None
|
||||
|
||||
def lookup_cdefine_constant(self, name: str) -> int:
|
||||
def lookup_cdefine_constant(self, name: str) -> t.CInt64T:
|
||||
"""查找 CDefine 编译期常量
|
||||
|
||||
返回找到的值。由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1),
|
||||
返回找到的值(64 位,大整数 CDefine 如 sys.maxsize 全精度)。
|
||||
由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1),
|
||||
用全局 _g_cdefine_found 标志区分"未找到"和值为 -1。
|
||||
调用方应在调用后检查 _g_cdefine_found。
|
||||
浮点 CDefine 项返回整数部分(与 _g_cdefine_is_double 标志配合)。
|
||||
@@ -398,8 +408,8 @@ class TypeGenMixin:
|
||||
return 0
|
||||
if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1:
|
||||
self.CDefineIsDouble = 1
|
||||
return string.atoi(val_str)
|
||||
return string.atoi(val_str)
|
||||
return string.atoll(val_str)
|
||||
return string.atoll(val_str)
|
||||
return 0
|
||||
|
||||
def lookup_cdefine_double(self, name: str) -> double:
|
||||
@@ -428,7 +438,7 @@ class TypeGenMixin:
|
||||
self.CDefineIsDouble = 1
|
||||
ret_d: double = string.atof(val_str)
|
||||
return ret_d
|
||||
ret_i2: double = double(string.atoi(val_str))
|
||||
ret_i2: double = double(string.atoll(val_str))
|
||||
return ret_i2
|
||||
return 0.0
|
||||
|
||||
@@ -754,6 +764,13 @@ class TypeGenMixin:
|
||||
if bop.op == ast.OpKind.Mult:
|
||||
self.ConstEvalOk = 1
|
||||
return lv * rv
|
||||
if bop.op == ast.OpKind.Div:
|
||||
# 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355)
|
||||
if rv == 0:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
self.ConstEvalOk = 1
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.FloorDiv:
|
||||
if rv == 0:
|
||||
self.ConstEvalOk = 0
|
||||
@@ -986,11 +1003,19 @@ class TypeGenMixin:
|
||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
return None
|
||||
buf: bytes = stdlib.malloc(_SRC_BUF_SIZE)
|
||||
# 按文件实际大小分配缓冲区:固定 256KB 会截断大源文件,末尾行号读不到 →
|
||||
# 误报"文件不存在或行号超出范围"(如 CallGenMixin.vp 555KB/9236 行的第
|
||||
# 8390 行)。64MB 上限防御异常超大文件整体读取。
|
||||
fsize: LONGLONG = f.size()
|
||||
if fsize <= 0 or fsize > 67108864:
|
||||
f.close()
|
||||
return None
|
||||
src_size: t.CSizeT = t.CSizeT(fsize)
|
||||
buf: bytes = stdlib.malloc(src_size + 1)
|
||||
if buf is None:
|
||||
f.close()
|
||||
return None
|
||||
bytes_read: LONG = f.read_all(buf, _SRC_BUF_SIZE)
|
||||
bytes_read: LONG = f.read_all(buf, ULONG(src_size + 1))
|
||||
f.close()
|
||||
if bytes_read <= 0:
|
||||
stdlib.free(buf)
|
||||
@@ -1077,6 +1102,18 @@ class TypeGenMixin:
|
||||
file_name: str = self.CurrentFile
|
||||
if file_name is None:
|
||||
file_name = "<unknown>"
|
||||
# 行号兜底:克隆/构造节点 lineno 可能为 0(如泛型特化 _clone_arguments 的
|
||||
# ast.Arg 构造器硬编码 0,astaux.vp L139)。此时回退到 trace 栈最后一个
|
||||
# 有效帧(文件+行号)作为出错位置,避免输出误导性的 "line 0"。
|
||||
if lineno <= 0 and self.TraceCount > 0:
|
||||
ti_b: int = self.TraceCount - 1
|
||||
while ti_b >= 0:
|
||||
tfb: HandlesType.TraceFrame | t.CPtr = self._get_trace_frame(ti_b)
|
||||
if tfb is not None and tfb.file_name is not None and tfb.lineno > 0:
|
||||
file_name = tfb.file_name
|
||||
lineno = tfb.lineno
|
||||
break
|
||||
ti_b -= 1
|
||||
# 行号合理性防御:先读取该行源码,验证 node.lineno 是否落在当前文件内。
|
||||
# 若读不到(文件不存在或行号超出范围),说明文件/行号归属不可信
|
||||
# (如 AST 树被内存复用/串扰后跨文件报错),打印警告而非误导性行号。
|
||||
@@ -1473,6 +1510,28 @@ class TypeGenMixin:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _is_cptr_subscript(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""检测节点是否为 t.CPtr[T] 下标指针类型(t.CPtr[t.CPtr] / t.CPtr[t.CInt] 等)
|
||||
|
||||
用于联合类型 X | t.CPtr[T] 的指针层级合并(TPC 联合合并规则:
|
||||
CPtr 侧贡献 PtrCount,另一侧提供 BaseType)。t.CPtr[...] 不是
|
||||
普通 CPtr 标记(_is_cptr_marker 只认 t.CPtr/CPtr 裸形式)。
|
||||
"""
|
||||
if node is None or node.kind() != ast.ASTKind.Subscript:
|
||||
return 0
|
||||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub.value is None or sub.value.kind() != ast.ASTKind.Attribute:
|
||||
return 0
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value)
|
||||
if at.attr is None or string.strcmp(at.attr, "CPtr") != 0:
|
||||
return 0
|
||||
if at.value is None or at.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if nm.id is None or string.strcmp(nm.id, "t") != 0:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def _is_cvoid_marker(self, node: ast.AST | t.CPtr,
|
||||
imported_modules: str) -> int:
|
||||
"""检测节点是否为 CVoid 指针标记,返回 1=是 / 0=否"""
|
||||
@@ -1818,7 +1877,13 @@ class TypeGenMixin:
|
||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
gen_spec_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(gen_mangled)
|
||||
if gen_spec_entry is not None and gen_spec_entry.MethodsEmitted == 0:
|
||||
# 错误定位:压入触发特化的调用方帧(注解所在文件+行号),
|
||||
# 使特化方法体报错(如参数类型解析失败)能追溯到用户代码
|
||||
# (如 devfs copy.vp 的 list[devfs_directory,MAX_DIRECTORIES] 注解)
|
||||
gen_cur_f: str = HandlesType.get_current_file()
|
||||
HandlesType.push_trace(gen_cur_f, sub.lineno)
|
||||
HandlesClassDef._specialize_generic_class(trans, gen_cls_name, gen_arg_names)
|
||||
HandlesType.pop_trace()
|
||||
return gen_spec_ty
|
||||
# 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐)
|
||||
# 当 trans 可用时,检查是否是泛型模板并触发特化
|
||||
@@ -1830,8 +1895,12 @@ class TypeGenMixin:
|
||||
type_args_chk: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(
|
||||
pool, sub.slice)
|
||||
if type_args_chk is not None and len(type_args_chk) > 0:
|
||||
# 错误定位:压入触发特化的调用方帧(注解所在文件+行号)
|
||||
gen_cur_f2: str = HandlesType.get_current_file()
|
||||
HandlesType.push_trace(gen_cur_f2, sub.lineno)
|
||||
spec_name_chk: str = HandlesClassDef._specialize_generic_class(
|
||||
trans, gen_cls_name, type_args_chk)
|
||||
HandlesType.pop_trace()
|
||||
if spec_name_chk is not None:
|
||||
gen_spec_ty = HandlesStruct.get_struct_type(gen_mangled)
|
||||
if gen_spec_ty is not None:
|
||||
@@ -1861,6 +1930,12 @@ class TypeGenMixin:
|
||||
# Constant 节点: 字符串注解(如 'MemManager'),当作无引号的 Name/Attribute/BinOp 处理
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
# -> None 无返回值注解 → Void(追加89:-> None 被 parser 解析为
|
||||
# CONST_NONE 常量而非 Name('None'),此前直接 return None → ret_ty
|
||||
# 回退 i32 → 掉出末尾被 fail-fast 误杀,BuildPipeline.set_asan_mode
|
||||
# "依旧"根因;Name 分支的 "None" 归一为字符串注解形式的双保险)
|
||||
if cn.const_kind == ast.CONST_NONE:
|
||||
return llvmlite.Void(pool)
|
||||
if cn.const_kind == ast.CONST_STR and cn.str_val is not None:
|
||||
sub_node: ast.AST | t.CPtr = self._parse_type_string(pool, cn.str_val, ast.ASTCtx.Load)
|
||||
if sub_node is not None:
|
||||
@@ -1908,6 +1983,11 @@ class TypeGenMixin:
|
||||
# str = bytes = str = i8*
|
||||
if string.strcmp(nm.id, "str") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# -> None 无返回值注解 → Void(追加89:与 VpiReader "None"→Void
|
||||
# 归一对齐;缺失时 -> None 解析失败回退 i32,函数掉出末尾被
|
||||
# fail-fast 误杀,BuildPipeline.set_asan_mode 根因)
|
||||
elif string.strcmp(nm.id, "None") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
elif string.strcmp(nm.id, "int") == 0:
|
||||
return llvmlite.Int32(pool)
|
||||
elif string.strcmp(nm.id, "bytes") == 0:
|
||||
@@ -1949,6 +2029,10 @@ class TypeGenMixin:
|
||||
if nm_has_new_s != 0:
|
||||
return llvmlite.Ptr(pool, struct_ty)
|
||||
return struct_ty
|
||||
# 枚举类(t.CEnum)裸名注解 → 底层整数类型
|
||||
# 如 fat32_types.vp 内部 `res: FRESULT = ...`(FRESULT 是枚举非结构体)
|
||||
if HandlesEnum.is_enum_class(nm.id) == 1:
|
||||
return HandlesEnum.get_enum_base_type(nm.id)
|
||||
# CTypedef 动态查表:查动态 CTypedef 表,递归解析类型表达式
|
||||
# 用户自定义 CTypedef(如 MyHandle: t.CTypedef = VOIDPTR)在此解析
|
||||
# 递归深度限制 MAX_CTYPEDEF_DEPTH 防止无限递归,循环检测防止 A→B→A
|
||||
@@ -2004,6 +2088,31 @@ class TypeGenMixin:
|
||||
mod_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(at.attr)
|
||||
if mod_struct_ty is not None:
|
||||
return mod_struct_ty
|
||||
# 模块限定枚举类型:Module.EnumClass(如 fat32_types.FRESULT,
|
||||
# t.CEnum 枚举类非结构体,get_struct_type 查不到)
|
||||
if HandlesEnum.is_enum_class(at.attr) == 1:
|
||||
return HandlesEnum.get_enum_base_type(at.attr)
|
||||
# 模块限定 typedef(posix.DIR = t.CTypedef = t.CVoid|t.CPtr 等):
|
||||
# 与 Name 分支(L1986-2009)同一套 lookup_ctypedef + 递归解析。
|
||||
# 追加20只补了嵌套 Attribute(mod.sub.Typedef);单层
|
||||
# Module.Typedef(value=Name 非 t/c)同样缺失——shutil.vp
|
||||
# L190 `dirp: posix.DIR` 变量注解解析失败根因。
|
||||
if self.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH:
|
||||
mod_td_str: str = self.lookup_ctypedef(at.attr)
|
||||
if mod_td_str is not None and self.CTypedefFound != 0:
|
||||
if self._ctypedef_push_visiting(pool, at.attr) == 0:
|
||||
mod_td_inner: ast.AST | t.CPtr = self._parse_type_string(
|
||||
pool, mod_td_str, at.ctx)
|
||||
if mod_td_inner is not None:
|
||||
self.CTypedefResolveDepth += 1
|
||||
mod_td_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, mod_td_inner, imported_modules, from_imports, trans)
|
||||
self.CTypedefResolveDepth -= 1
|
||||
self._ctypedef_pop_visiting()
|
||||
if mod_td_ty is not None:
|
||||
return mod_td_ty
|
||||
else:
|
||||
self._ctypedef_pop_visiting()
|
||||
return None
|
||||
# 嵌套 Attribute: w32.win32base.SECURITY_ATTRIBUTES 等三级及以上限定名
|
||||
# at.value 是 Attribute 而非 Name,递归提取最终类名(at.attr)查结构体表
|
||||
@@ -2012,6 +2121,32 @@ class TypeGenMixin:
|
||||
nested_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(at.attr)
|
||||
if nested_struct_ty is not None:
|
||||
return nested_struct_ty
|
||||
# 嵌套模块限定的枚举类(fat32_types.FRESULT 三级名):查枚举基类型
|
||||
if HandlesEnum.is_enum_class(at.attr) == 1:
|
||||
return HandlesEnum.get_enum_base_type(at.attr)
|
||||
# 嵌套模块限定的 typedef(w32.win32base.HANDLE = t.CTypedef = VOIDPTR):
|
||||
# 与 Name 分支(L1986-2009)同一套 lookup_ctypedef + 递归 + map_t_type 兜底。
|
||||
# 此前只查 struct/enum → w32.win32base.HANDLE 解析失败(fail-fast 报
|
||||
# NameError: 'w32.win32base.HANDLE' is not defined,FileIoTest 根因)。
|
||||
if self.CTypedefResolveDepth < MAX_CTYPEDEF_DEPTH:
|
||||
nested_td_str: str = self.lookup_ctypedef(at.attr)
|
||||
if nested_td_str is not None and self.CTypedefFound != 0:
|
||||
if self._ctypedef_push_visiting(pool, at.attr) == 0:
|
||||
nested_inner: ast.AST | t.CPtr = self._parse_type_string(
|
||||
pool, nested_td_str, at.ctx)
|
||||
if nested_inner is not None:
|
||||
self.CTypedefResolveDepth += 1
|
||||
nested_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, nested_inner, imported_modules, from_imports, trans)
|
||||
self.CTypedefResolveDepth -= 1
|
||||
self._ctypedef_pop_visiting()
|
||||
if nested_ty is not None:
|
||||
return nested_ty
|
||||
else:
|
||||
self._ctypedef_pop_visiting()
|
||||
mapped_ty_na: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, at.attr)
|
||||
if mapped_ty_na is not None:
|
||||
return mapped_ty_na
|
||||
return None
|
||||
|
||||
# BinOp 节点: 联合类型注解 A | B
|
||||
@@ -2124,6 +2259,44 @@ class TypeGenMixin:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
return llvmlite.Ptr(pool, other_ty)
|
||||
|
||||
# t.CPtr[...] 下标指针标记(t.CPtr[T] 非普通 CPtr 标记,_is_cptr_marker
|
||||
# 不识别 Subscript): X | t.CPtr[T] → 指针层级合并(对齐 TPC 联合合并
|
||||
# 规则 HandlesTypeMerge.py L864-884:CPtr 侧贡献 PtrCount,另一侧提供
|
||||
# BaseType)。如 t.CUInt8T | t.CPtr[t.CPtr] → u8**。此前左右都不是
|
||||
# CPtr 标记 → 落下方"无 CPtr 标记"分支返回左值 i8 → c.Deref(out) 报
|
||||
# "参数不是指针类型"(zdeflate.vp compress out 根因)。
|
||||
cptr_sub_side: ast.AST | t.CPtr = None
|
||||
cptr_other: ast.AST | t.CPtr = None
|
||||
if self._is_cptr_subscript(bop.left) != 0:
|
||||
cptr_sub_side = bop.left
|
||||
cptr_other = bop.right
|
||||
elif self._is_cptr_subscript(bop.right) != 0:
|
||||
cptr_sub_side = bop.right
|
||||
cptr_other = bop.left
|
||||
if cptr_sub_side is not None and cptr_other is not None:
|
||||
cptr_sub_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, cptr_sub_side, imported_modules, from_imports, trans)
|
||||
cptr_other_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, cptr_other, imported_modules, from_imports, trans)
|
||||
if cptr_sub_ty is not None and cptr_other_ty is not None:
|
||||
# 计算 CPtr 侧外层 Ptr 嵌套数(如 t.CPtr[t.CPtr]=i8** → 2 层)
|
||||
cptr_level: int = 0
|
||||
cur_lvl: llvmlite.LLVMType | t.CPtr = cptr_sub_ty
|
||||
while cur_lvl is not None:
|
||||
match cur_lvl:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
cptr_level += 1
|
||||
cur_lvl = cur_lvl.Pointee
|
||||
case _:
|
||||
break
|
||||
# 结果 = 另一侧类型外包 N 层 Ptr
|
||||
res_ty: llvmlite.LLVMType | t.CPtr = cptr_other_ty
|
||||
li2: int = 0
|
||||
while li2 < cptr_level:
|
||||
res_ty = llvmlite.Ptr(pool, res_ty)
|
||||
li2 += 1
|
||||
return res_ty
|
||||
|
||||
# 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略)
|
||||
left_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, bop.left, imported_modules, from_imports, trans)
|
||||
@@ -2210,6 +2383,19 @@ class TypeGenMixin:
|
||||
if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.fatal_type_error(node, "t.Callable 模块未导入")
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# 指针类型: t.CPtr[T] → Ptr(T)(指向 T 的指针,T 自身可含指针层级)
|
||||
# t.CPtr[t.CPtr] → Ptr(Ptr(CPtr=i8*)) = i8**(双指针)
|
||||
# t.CPtr[t.CInt] → i32*(DeclarationGenerator.py L1014-1016 文档化语法)。
|
||||
# 此前缺失 → t.CUInt8T | t.CPtr[t.CPtr] 联合退化为左值 i8 →
|
||||
# c.Deref(out) 报"参数不是指针类型"(zdeflate.vp compress out 根因)
|
||||
if string.strcmp(arr_at.attr, "CPtr") == 0:
|
||||
if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
self.fatal_type_error(node, "t.CPtr 模块未导入")
|
||||
inner_cptr_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
|
||||
pool, sub.slice, imported_modules, from_imports, trans)
|
||||
if inner_cptr_ty is None:
|
||||
self.fatal_type_error(sub.slice, "t.CPtr[?] 元素类型解析失败")
|
||||
return llvmlite.Ptr(pool, inner_cptr_ty)
|
||||
if string.strcmp(arr_at.attr, "CArray") != 0:
|
||||
self.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)")
|
||||
if HandlesImports.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
@@ -2263,6 +2449,9 @@ class TypeGenMixin:
|
||||
|
||||
# 未知 AST kind:fail-fast,不宽容返回 None
|
||||
self.fatal_type_error(node, "不支持的类型注解语法")
|
||||
# 追加89 块设计:fatal_type_error 调用后补显式 return(运行时不可达,
|
||||
# 保证方法末尾块被正确 terminated,不做 noreturn 函数名白名单)
|
||||
return None
|
||||
|
||||
def has_decorator_marker(self, node: ast.AST | t.CPtr,
|
||||
marker_name: str) -> int:
|
||||
|
||||
@@ -4,6 +4,7 @@ import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -40,7 +41,9 @@ SCOPE_FUNCTION: t.CDefine = 1
|
||||
SCOPE_BLOCK: t.CDefine = 2
|
||||
|
||||
# 每个作用域最大变量数
|
||||
MAX_VARS: t.CDefine = 256
|
||||
# 256 太小:NewAstTest main() 有 289 个局部变量(几十个测试用例),
|
||||
# add_var 超限静默失败导致变量未注册,后续使用报"未定义名称"(NameError)。
|
||||
MAX_VARS: t.CDefine = 1024
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -388,5 +391,13 @@ class VarGenMixin:
|
||||
alloca: llvmlite.Value | t.CPtr = self._alloca_at_entry(builder, ty)
|
||||
if alloca is None:
|
||||
return None
|
||||
self.define_var(symtab, name, alloca)
|
||||
if self.define_var(symtab, name, alloca) != 0:
|
||||
# fail-fast: 变量注册失败(如超过 MAX_VARS)必须立即终止。
|
||||
# 此前静默忽略返回值:alloca 已创建但未入符号表,后续读取该变量
|
||||
# 报"未定义名称"(NewAstTest main() 289 个局部变量 > MAX_VARS=256
|
||||
# 的 NameError 根因),误导排查。变量表超限暴露上游规模问题。
|
||||
HandlesType.fatal_error(
|
||||
None,
|
||||
f"变量 '{name}' 注册失败(作用域变量数超过上限 MAX_VARS)",
|
||||
"InternalCompilerError")
|
||||
return alloca
|
||||
@@ -78,7 +78,7 @@ def is_ctypedef_annotation(annot: ast.AST | t.CPtr) -> int:
|
||||
# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数
|
||||
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
|
||||
# ============================================================
|
||||
def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
|
||||
def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> t.CInt64T:
|
||||
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp,委托到 gen.extract_cdefine_int_value)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
@@ -397,9 +397,13 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
||||
if HandlesVar.define_var(
|
||||
self.Trans.SymTab, nm.id, alloca) == 0:
|
||||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||||
# 传 pool:泛型 Subscript 返回 mangled name(GSList[BasicBlock] → 特化
|
||||
# struct 名),否则 pool=None 只返回裸类名(GSList → 泛型模板未注册
|
||||
# → 属性访问 lookup_field_by_class("GSList") 报"类未注册",LLVMLiteTest
|
||||
# __function.vp blocks.Tail 根因;对齐 ClassGenMixin L3159 BUG 1 方案3)
|
||||
if annot is not None:
|
||||
cls_nm_ps: str = HandlesType.extract_class_name_from_annotation(
|
||||
annot, self.Trans._imported_modules)
|
||||
annot, self.Trans._imported_modules, pool)
|
||||
if cls_nm_ps is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
self.Trans.SymTab, nm.id, cls_nm_ps)
|
||||
@@ -420,9 +424,6 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
||||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa is None:
|
||||
return 0
|
||||
# OOM 诊断:AnnAssign 入口 used(定位 Constant 构造语句的注解/值翻译段)
|
||||
stdio.printf("[MEM] AnnAssign.Handle line %d used=%zu chk=%zu\n",
|
||||
node.lineno, self.Trans.Pool.used_bytes(), self.Trans.Pool.chk_depth)
|
||||
|
||||
target: ast.AST | t.CPtr = aa.target
|
||||
if target is None or target.kind() != ast.ASTKind.Name:
|
||||
@@ -556,10 +557,40 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
||||
aa,
|
||||
f"无法为变量 {nm.id} 创建存储",
|
||||
"TypeError")
|
||||
# FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储)
|
||||
# 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / t.CChar|t.CPtr 不创建。
|
||||
# a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段,
|
||||
# 属性读写(fd3)与方法调用(fd5)均通过该影子解析。
|
||||
fd_str_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
fd_meta_alloca: llvmlite.Value | t.CPtr = None
|
||||
fd_meta_name: str = None
|
||||
if annot is not None and annot.kind() == ast.ASTKind.Name:
|
||||
fd_annot: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
|
||||
if fd_annot is not None and fd_annot.id is not None:
|
||||
if string.strcmp(fd_annot.id, "str") == 0:
|
||||
fd_str_ty = HandlesStruct.get_struct_type("_str")
|
||||
if fd_str_ty is not None:
|
||||
# 确保 _str 完整类型定义在当前模块可用:跨模块结构体默认 opaque,
|
||||
# 直接 alloca opaque 类型 → llc "Cannot allocate unsized type"
|
||||
HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_str_ty)
|
||||
# 影子变量名必须用 pool 持久缓冲:f-string 生成栈缓冲,在 AnnAssign
|
||||
# 返回后被覆盖,符号表注册的名字内容损坏 → 后续 lookup 找不到。
|
||||
fd_meta_name = pool.alloc(256)
|
||||
if fd_meta_name is not None:
|
||||
viperlib.snprintf(fd_meta_name, 256, "%s__meta__", nm.id)
|
||||
fd_meta_alloca = HandlesVar.get_or_create_sym(
|
||||
self.Trans.SymTab, pool, builder, fd_meta_name, fd_str_ty)
|
||||
if fd_meta_alloca is None:
|
||||
# fail-fast: 影子存储创建失败,立即终止
|
||||
HandlesType.fatal_error(
|
||||
aa,
|
||||
f"无法为 str 影子变量 {fd_meta_name} 创建存储",
|
||||
"TypeError")
|
||||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||||
# 传 pool:泛型 Subscript 返回 mangled name(对齐 L401 同根因修复)
|
||||
if annot is not None:
|
||||
cls_nm_hd: str = HandlesType.extract_class_name_from_annotation(
|
||||
annot, self.Trans._imported_modules)
|
||||
annot, self.Trans._imported_modules, pool)
|
||||
if cls_nm_hd is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
self.Trans.SymTab, nm.id, cls_nm_hd)
|
||||
@@ -644,12 +675,48 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
||||
if target_ty is not None:
|
||||
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node)
|
||||
llvmlite.build_store(builder, rhs_val, alloca)
|
||||
# FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针
|
||||
# (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__)
|
||||
if fd_str_ty is not None and fd_meta_alloca is not None:
|
||||
fd_data_fe: HandlesStruct.FieldEntry | t.CPtr = \
|
||||
HandlesStruct.lookup_field(fd_str_ty, "__data__")
|
||||
if fd_data_fe is not None:
|
||||
fd_data_ptr: llvmlite.Value | t.CPtr = \
|
||||
llvmlite.build_gep_struct(
|
||||
builder, fd_str_ty, fd_data_fe.Ty,
|
||||
fd_meta_alloca, fd_data_fe.Index)
|
||||
if fd_data_ptr is not None:
|
||||
llvmlite.build_store(builder, rhs_val, fd_data_ptr)
|
||||
# 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该
|
||||
# AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的
|
||||
# c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。
|
||||
self.Trans.CurAssignAnnot = None
|
||||
self.Trans.CurAssignNode = None
|
||||
|
||||
# FakeDuck: __mbuddy__ 字段初始化为 NULL。
|
||||
# with 上下文提供的 __mbuddy__ 注入由 _inject_requires_fields(fd4)完成,
|
||||
# 此处仅确保影子结构体初始为空指针(对齐 TPC HandlesAnnAssign.py L667-670)。
|
||||
if fd_str_ty is not None and fd_meta_alloca is not None:
|
||||
fd_buddy_fe: HandlesStruct.FieldEntry | t.CPtr = \
|
||||
HandlesStruct.lookup_field(fd_str_ty, "__mbuddy__")
|
||||
if fd_buddy_fe is not None and fd_buddy_fe.Ty is not None:
|
||||
fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
|
||||
pool, fd_buddy_fe.Ty, "null")
|
||||
fd_buddy_ptr: llvmlite.Value | t.CPtr = \
|
||||
llvmlite.build_gep_struct(
|
||||
builder, fd_str_ty, fd_buddy_fe.Ty,
|
||||
fd_meta_alloca, fd_buddy_fe.Index)
|
||||
if fd_buddy_ptr is not None and fd_null is not None:
|
||||
llvmlite.build_store(builder, fd_null, fd_buddy_ptr)
|
||||
# FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)。
|
||||
# 经全局 gen 单例委托 CallGenMixin._inject_requires_fields。
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g_fda: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||||
t.CVoid(_g_gen, t.CPtr))
|
||||
if g_fda is not None:
|
||||
g_fda._inject_requires_fields(
|
||||
self.Trans, pool, builder, mod, fd_meta_alloca, "_str")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -67,6 +67,15 @@ class AssignHandle(HandlesBase.Mixin):
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, asgn.value, None, 0, self.Trans)
|
||||
if rhs_val is None:
|
||||
# Phase A 依赖未就绪(_deps_pending=1):跨模块函数/方法因 text.ll
|
||||
# 未生成返回类型退化为 void/None(CallGenMixin L4493
|
||||
# g_vta._resolve_attr_field_class 根因)。此时整文件不写盘、下遍重译
|
||||
# (Phase2.vp L590-599),跳过本语句不报错——否则 fatal 使多遍
|
||||
# 重试机制永远无法收敛(本语句只是"本遍保持默认类型"的退化结果,
|
||||
# 下遍依赖已生成即可精确解析)。依赖就绪时 _deps_pending=0,
|
||||
# 此处仍 fail-fast,不掩盖真实错误。
|
||||
if self.Trans is not None and self.Trans._deps_pending != 0:
|
||||
return 0
|
||||
# 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位
|
||||
fb: str = VLogger.fmt_buf()
|
||||
if fb is not None and asgn.value is not None:
|
||||
@@ -357,6 +366,49 @@ class AssignHandle(HandlesBase.Mixin):
|
||||
if HandlesExprCall._try_property_setter(
|
||||
pool, builder, mod, target, rhs_val, self.Trans) == 1:
|
||||
continue
|
||||
# FakeDuck: 影子结构体属性写入 (str 变量的 per-instance 字段)
|
||||
# a.__data__ = v → GEP {a}__meta__[field] 并 store
|
||||
# 对齐 TPC HandlesAssign.py L67-76:对象是 Name 变量且存在
|
||||
# {var}__meta__ 影子(fd2 创建)时,属性写入改走影子结构体。
|
||||
fd_an: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
|
||||
if fd_an is not None and fd_an.value is not None and fd_an.attr is not None:
|
||||
if fd_an.value.kind() == ast.ASTKind.Name:
|
||||
fd_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_an.value)
|
||||
if fd_obj_nm.id is not None:
|
||||
# pool 持久缓冲(f-string 栈缓冲在函数返回后失效)
|
||||
fd_meta_w: str = pool.alloc(256)
|
||||
if fd_meta_w is not None:
|
||||
viperlib.snprintf(fd_meta_w, 256, "%s__meta__", fd_obj_nm.id)
|
||||
fd_meta_vw: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
|
||||
self.Trans.SymTab, fd_meta_w)
|
||||
if fd_meta_vw is not None:
|
||||
fd_sty_w: llvmlite.LLVMType | t.CPtr = \
|
||||
HandlesStruct.get_struct_type("_str")
|
||||
if fd_sty_w is not None:
|
||||
fd_fe_w: HandlesStruct.FieldEntry | t.CPtr = \
|
||||
HandlesStruct.lookup_field(fd_sty_w, fd_an.attr)
|
||||
if fd_fe_w is not None and fd_fe_w.Ty is not None:
|
||||
fd_fp_w: llvmlite.Value | t.CPtr = \
|
||||
llvmlite.build_gep_struct(
|
||||
builder, fd_sty_w, fd_fe_w.Ty,
|
||||
fd_meta_vw, fd_fe_w.Index)
|
||||
if fd_fp_w is not None:
|
||||
sv_fd: llvmlite.Value | t.CPtr = \
|
||||
HandlesExpr.coerce_to_type(
|
||||
builder, rhs_val, fd_fe_w.Ty, node)
|
||||
llvmlite.build_store(builder, sv_fd, fd_fp_w)
|
||||
continue
|
||||
# VTABLE 直接写入:obj.method = func(serial0_file.open = serial0_open)
|
||||
# vtable 方法不是数据字段(FieldEntry),get_attribute_ptr 查不到会
|
||||
# fatal_error;此处对齐 TPC HandlesAssign.py L905-949 的写时复制,
|
||||
# 检测到 vtable 方法时直接生成槽位写入并跳过字段路径。
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g_vtw: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||||
if g_vtw is not None:
|
||||
if g_vtw._write_vtable_attr(
|
||||
builder, pool, mod, target, rhs_val, self.Trans) == 1:
|
||||
continue
|
||||
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||||
builder, pool, mod, target, self.Trans)
|
||||
if field_ptr is not None:
|
||||
@@ -368,6 +420,11 @@ class AssignHandle(HandlesBase.Mixin):
|
||||
llvmlite.build_store(builder, store_val, field_ptr)
|
||||
continue
|
||||
# 守卫:field_ptr 为 None → 构造详细错误信息
|
||||
# Phase A 依赖未就绪(_deps_pending):get_attribute_ptr 已因
|
||||
# 父类/依赖类未注册跳过字段,此处同样跳过不报错,整文件下遍重译
|
||||
# (对齐 HandlesAssign L69-78 与 get_attribute_ptr 的 pending 容忍)
|
||||
if self.Trans is not None and self.Trans._deps_pending != 0:
|
||||
continue
|
||||
attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
|
||||
attr_name: str = "(unknown)"
|
||||
obj_name: str = "(unknown)"
|
||||
@@ -535,6 +592,38 @@ class AssignHandle(HandlesBase.Mixin):
|
||||
return None
|
||||
obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans)
|
||||
if obj_cls is None:
|
||||
# 模块级函数调用(requests.get):ca.value 是已导入模块名
|
||||
# 而非对象变量(模块名 lookup_var_entry 返回 None → 上面
|
||||
# 对象类名推断失败)。从该模块 vpi 的返回注解缓存解析返回
|
||||
# 类名(键 {sha1}.{func},cls_name=None 即模块级函数,与
|
||||
# CallGenMixin 跨模块返回类型解析一致)。
|
||||
# WebTest resp = requests.get(...) 根因:无注解赋值变量
|
||||
# AnnotClassName 推断失败(annot=None)→ 属性访问按需过滤
|
||||
# (依赖 AnnotClassName)失效 → "属性访问失败: .status_code"。
|
||||
if ca.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm_rhs: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value)
|
||||
if mod_nm_rhs.id is not None:
|
||||
mod_sha1_rhs: str = HandlesExprCall._lookup_module_sha1(
|
||||
mod_nm_rhs.id)
|
||||
if mod_sha1_rhs is not None:
|
||||
import lib.StubGen.VpiReader as VpiReader
|
||||
temp_dir_rhs: str = None
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g_rhs: Generator.Generator | t.CPtr = (
|
||||
Generator.Generator | t.CPtr)(
|
||||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||||
if g_rhs is not None and g_rhs.TempDir is not None:
|
||||
temp_dir_rhs = g_rhs.TempDir
|
||||
if temp_dir_rhs is not None:
|
||||
VpiReader._ensure_vpi_ret_annot_loaded(
|
||||
mod_sha1_rhs, temp_dir_rhs)
|
||||
annot_rhs: str = VpiReader._lookup_vpi_ret_annot(
|
||||
mod_sha1_rhs, None, ca.attr)
|
||||
if annot_rhs is not None:
|
||||
ret_cls_rhs: str = self._extract_annot_class_name(
|
||||
pool, annot_rhs)
|
||||
if ret_cls_rhs is not None:
|
||||
return ret_cls_rhs
|
||||
return None
|
||||
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0:
|
||||
return None
|
||||
|
||||
@@ -163,6 +163,85 @@ def _has_decorator(decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
return 0
|
||||
|
||||
|
||||
def register_decorator(pool: memhub.MemBuddy | t.CPtr,
|
||||
func_name: str, wrapper_name: str,
|
||||
arg0: t.CInt64T) -> int:
|
||||
"""注册自定义装饰器函数(@log/@skip/@repeat(3) → __decor_wrap_{name},委托到 gen)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.register_decorator(pool, func_name, wrapper_name, arg0)
|
||||
return -1
|
||||
|
||||
|
||||
def lookup_decor_wrapper(func_name: str) -> str:
|
||||
"""按原函数名查装饰器 wrapper 名,未注册返回 None(委托到 gen)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.lookup_decor_wrapper(func_name)
|
||||
return None
|
||||
|
||||
|
||||
def lookup_decor_arg0(func_name: str) -> t.CInt64T:
|
||||
"""按原函数名查装饰器首个常量参数(无参数为 0,委托到 gen)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.lookup_decor_arg0(func_name)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 异常类注册表委托(try-except,对齐 TPC HandlesClassDef.py L47-61)
|
||||
# ============================================================
|
||||
def register_exception(class_name: str, parent_name: str) -> int:
|
||||
"""注册用户异常类并分配编码(幂等,委托到 gen)。返回编码或 -1"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.register_exception(class_name, parent_name)
|
||||
return -1
|
||||
|
||||
|
||||
def lookup_exception_code(name: str) -> int:
|
||||
"""查异常编码:内置表优先,其次用户异常表(委托到 gen)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.lookup_exception_code(name)
|
||||
return 0
|
||||
|
||||
|
||||
def is_exception_name(name: str) -> int:
|
||||
"""name 是否是内置或用户异常类名(委托到 gen)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.is_exception_name(name)
|
||||
return 0
|
||||
|
||||
|
||||
def collect_descendant_codes(name: str, out_codes: t.CInt | t.CPtr,
|
||||
max_codes: int) -> int:
|
||||
"""收集 name 及全部子孙异常编码(委托到 gen)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.collect_descendant_codes(name, out_codes, max_codes)
|
||||
return 0
|
||||
|
||||
|
||||
def register_exception_class_def(trans: HT.Translator | t.CPtr,
|
||||
cd: ast.ClassDef | t.CPtr) -> int:
|
||||
"""注册异常类定义(分配编码 + 记录父类,不生成 struct,委托到 gen)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._register_exception_class_def(trans, cd)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 方法元数据(装饰器)支持
|
||||
#
|
||||
@@ -699,12 +778,19 @@ def _lookup_renum_variant_in_class(class_name: str, variant_name: str) -> int:
|
||||
def _register_renum_field_alias(pool: memhub.MemBuddy | t.CPtr,
|
||||
class_name: str,
|
||||
field_name: str,
|
||||
payload_idx: int):
|
||||
"""注册 REnum 变体字段名别名到全局表(委托到 gen._register_renum_field_alias)"""
|
||||
payload_idx: int,
|
||||
field_ty: llvmlite.LLVMType | t.CPtr = None,
|
||||
variant_name: str = None):
|
||||
"""注册 REnum 变体字段名别名到全局表(委托到 gen._register_renum_field_alias)
|
||||
|
||||
field_ty: 变体成员实际 LLVM 类型(可选,供 match 绑定 bitcast)
|
||||
variant_name: 所属变体名(可选,match 绑定按 (class, 变体, 位置) 定位成员)
|
||||
"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g._register_renum_field_alias(pool, class_name, field_name, payload_idx)
|
||||
g._register_renum_field_alias(pool, class_name, field_name, payload_idx,
|
||||
field_ty, variant_name)
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -752,6 +838,46 @@ def _lookup_renum_field_alias(class_name: str, field_name: str) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _lookup_renum_field_alias_ty — 查找 REnum 变体成员的实际 LLVM 类型
|
||||
#
|
||||
# 与 _lookup_renum_field_alias 同表同键。供 match 绑定把槽位地址
|
||||
# bitcast 成成员真实类型(Struct.Name: i8* 而非槽位 i64)。
|
||||
#
|
||||
# 返回:
|
||||
# 成功: LLVMType(perm_pool 深拷贝,跨文件存活)
|
||||
# 失败: None
|
||||
# ============================================================
|
||||
def _lookup_renum_field_alias_ty(class_name: str,
|
||||
field_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None(委托到 gen._lookup_renum_field_alias_ty)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._lookup_renum_field_alias_ty(class_name, field_name)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _lookup_renum_member_ty — 按 (class, 变体名, payload 位置) 查找成员类型
|
||||
#
|
||||
# match 绑定用:同一 payload 位置跨变体类型不同,必须带变体名定位。
|
||||
#
|
||||
# 返回:
|
||||
# 成功: LLVMType(perm_pool 深拷贝,跨文件存活)
|
||||
# 失败: None
|
||||
# ============================================================
|
||||
def _lookup_renum_member_ty(class_name: str,
|
||||
variant_name: str,
|
||||
payload_idx: int) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""按 (class, 变体名, payload 位置) 查找变体成员实际类型,返回类型或 None(委托到 gen._lookup_renum_member_ty)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._lookup_renum_member_ty(class_name, variant_name, payload_idx)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# translate_class_def — 翻译 class 定义
|
||||
#
|
||||
|
||||
@@ -295,6 +295,24 @@ def create_global_string(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块引用 AST → 模块路径字符串(递归拼接 Attribute 链)
|
||||
# ============================================================
|
||||
def attr_module_path_str(pool: memhub.MemBuddy | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> str:
|
||||
"""把模块引用 AST 转成模块路径字符串(Name('sys')→"sys"、
|
||||
Attribute(Attribute(Name('os'),'_win32'))→"os._win32";非模块引用形态返回 None)
|
||||
|
||||
跨 mixin 委托:CallGenMixin 等不能 self. 直接调用 ExprGenMixin 的方法
|
||||
(@t.NoVTable 静态绑定会 mangle 成当前类名 → undefined reference)。
|
||||
"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._attr_module_path_str(pool, node)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译常量表达式
|
||||
# ============================================================
|
||||
@@ -511,8 +529,8 @@ def _build_source_path_from_sha1(sha1: str) -> str:
|
||||
def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str,
|
||||
from_imports: str,
|
||||
imported_modules: str = None) -> int:
|
||||
"""跨模块查找 CDefine 常量,返回值或 -1(未找到)(委托到 gen._lookup_cross_module_cdefine)"""
|
||||
imported_modules: str = None) -> t.CInt64T:
|
||||
"""跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到)(委托到 gen._lookup_cross_module_cdefine)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
|
||||
@@ -770,10 +770,6 @@ def _fail_method_ret_ty(method_name: str,
|
||||
# 行提取实际返回类型,避免指针截断(未命中时回退 vpi stub 缓存)。
|
||||
# ============================================================
|
||||
|
||||
# text.ll 读取缓冲区大小
|
||||
_TEXT_LL_READ_BUF_SIZE: t.CDefine = 262144
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SetTempDir - 设置 temp 目录路径
|
||||
#
|
||||
|
||||
@@ -12,6 +12,8 @@ import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesBody as HandlesBody
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -186,6 +188,33 @@ class ForHandle(HandlesBase.Mixin):
|
||||
if lst_val is not None and lst_val.Ty is not None \
|
||||
and HandlesExpr.is_ptr_type(lst_val.Ty) != 0:
|
||||
return self._handle_list_iter(for_node, var_name, lst_val)
|
||||
# OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 →
|
||||
# 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166
|
||||
# _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。
|
||||
ov_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, iter_node,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if ov_val is not None and ov_val.Ty is not None \
|
||||
and HandlesExpr.is_ptr_type(ov_val.Ty) != 0:
|
||||
ov_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(
|
||||
ov_val)
|
||||
if ov_st is not None:
|
||||
ov_cn: str = HandlesStruct.get_class_name_by_type(pool, ov_st)
|
||||
if ov_cn is not None:
|
||||
oi_lookup: str = pool.alloc(128)
|
||||
if oi_lookup is not None:
|
||||
viperlib.snprintf(oi_lookup, 128, "%s.__iter__", ov_cn)
|
||||
oi_fn: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(
|
||||
trans.Module, oi_lookup)
|
||||
if oi_fn is not None:
|
||||
on_lookup: str = pool.alloc(128)
|
||||
if on_lookup is not None:
|
||||
viperlib.snprintf(on_lookup, 128, "%s.__next__", ov_cn)
|
||||
on_fn: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(
|
||||
trans.Module, on_lookup)
|
||||
if on_fn is not None:
|
||||
return self._handle_oop_iter(
|
||||
for_node, var_name, ov_cn, ov_val)
|
||||
# 其它不支持的字面量:fast-fail 显式报错,
|
||||
# 避免 translate_value 触发 list[T] 特化崩溃或语义歧义。
|
||||
ik: int = iter_node.kind()
|
||||
@@ -245,6 +274,26 @@ class ForHandle(HandlesBase.Mixin):
|
||||
if step_val is None:
|
||||
# fail-fast: range 参数翻译失败
|
||||
HandlesType.fatal_error(args.get(2), "range 参数翻译失败", "TypeError")
|
||||
# step 为负数字面量时循环条件反转(对齐 TPC HandlesFor.py L86-94):
|
||||
# range(a, b, -1) → i > stop;range(a, b, +1) → i < stop。
|
||||
# TPC 仅识别负数字面量(UnaryOp USub 常量 / 负常量);变量 step 保守按正。
|
||||
# 修复 _find_provider 的 range(top-1, -1, -1) 循环体不执行(i < -1 恒假)。
|
||||
step_neg_const: int = 0
|
||||
if arg_count >= 3:
|
||||
step_arg_node: ast.AST | t.CPtr = args.get(2)
|
||||
if step_arg_node is not None:
|
||||
skn: int = step_arg_node.kind()
|
||||
if skn == ast.ASTKind.UnaryOp:
|
||||
uop_r: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(step_arg_node)
|
||||
if uop_r.op == ast.OpKind.USub and uop_r.operand is not None:
|
||||
if uop_r.operand.kind() == ast.ASTKind.Constant:
|
||||
uoc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_r.operand)
|
||||
if uoc_r.int_val > 0:
|
||||
step_neg_const = 1
|
||||
elif skn == ast.ASTKind.Constant:
|
||||
skc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(step_arg_node)
|
||||
if skc_r.int_val < 0:
|
||||
step_neg_const = 1
|
||||
|
||||
# 4. 创建/查找循环变量 alloca
|
||||
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
@@ -311,9 +360,19 @@ class ForHandle(HandlesBase.Mixin):
|
||||
if cur_bits < stop_bits:
|
||||
cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty)
|
||||
else:
|
||||
cmp_rhs = llvmlite.build_trunc(builder, stop_val, loop_var_ty)
|
||||
# 循环变量位宽 > stop 位宽(如 t.CSizeT 循环变量 + range(i32)):
|
||||
# 应把 cur_i 截断到 stop_val 类型(低向高才 sext/zext,高向低用
|
||||
# trunc)。原实现反了——把小的 stop_val trunc 到大的 loop_var_ty,
|
||||
# 生成 `trunc i32 to i64` 扩宽非法 IR,llc 报
|
||||
# "invalid cast opcode for cast from 'i32' to 'i64'"
|
||||
# (VpiReader.vp range(arg_count) 追加86 根因)。
|
||||
cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty)
|
||||
# step 为负时条件反转:i > stop(ICMP_SGT);正/缺省 step 保持 i < stop
|
||||
range_cmp_op: int = llvmlite.ICMP_SLT
|
||||
if step_neg_const != 0:
|
||||
range_cmp_op = llvmlite.ICMP_SGT
|
||||
cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_SLT, cmp_lhs, cmp_rhs)
|
||||
builder, range_cmp_op, cmp_lhs, cmp_rhs)
|
||||
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
|
||||
|
||||
# 9. body 块: 翻译循环体,跳到 incr
|
||||
@@ -943,6 +1002,189 @@ class ForHandle(HandlesBase.Mixin):
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
return new_vars
|
||||
|
||||
# ============================================================
|
||||
# _handle_oop_iter - OOP 迭代协议: for x in obj:
|
||||
# obj 的类有 __iter__/__next__ 方法时调用协议迭代
|
||||
# (对齐 TPC HandlesFor.py _HandleForIterLlvm L599-663)
|
||||
#
|
||||
# 生成 IR 结构:
|
||||
# %it = call {Class}.__iter__(obj)
|
||||
# %flag = alloca i1 ; store 0
|
||||
# br %cond
|
||||
# cond:
|
||||
# store 0, %flag
|
||||
# %v = call {Class}.__next__(%it, %flag)
|
||||
# %stop = load i1, %flag
|
||||
# br i1 %stop==0, %body, %end
|
||||
# body:
|
||||
# store %v, %var
|
||||
# ... 循环体 ...
|
||||
# br %step
|
||||
# step:
|
||||
# br %cond
|
||||
# end:
|
||||
#
|
||||
# __next__ 的隐藏参数 __stop_iter_flag__(i1*)由 ClassGenMixin
|
||||
# _translate_method 注入,raise StopIteration 时置 1(translate_raise);
|
||||
# VpiReader stub 声明同步该参数(_inject_method_declare)。
|
||||
# ============================================================
|
||||
def _handle_oop_iter(self, for_node: ast.For | t.CPtr,
|
||||
var_name: str,
|
||||
class_name: str,
|
||||
obj_val: llvmlite.Value | t.CPtr) -> int:
|
||||
"""OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代"""
|
||||
trans: HT.Translator | t.CPtr = self.Trans
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
|
||||
if builder is None or func is None or mod is None:
|
||||
return 0
|
||||
if obj_val is None or obj_val.Ty is None:
|
||||
HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知")
|
||||
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
|
||||
HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型")
|
||||
|
||||
# 1. 查找 {Class}.__iter__ 并调用,得到迭代器
|
||||
iter_lookup: str = pool.alloc(128)
|
||||
if iter_lookup is None:
|
||||
return 0
|
||||
viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name)
|
||||
iter_fn: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(
|
||||
mod, iter_lookup)
|
||||
if iter_fn is None:
|
||||
HandlesType.fatal_error(
|
||||
for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法")
|
||||
iter_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(iter_fn)
|
||||
iter_fn_name: str = llvmlite.function_get_name(iter_fn)
|
||||
if iter_ret_ty is None or iter_fn_name is None:
|
||||
return 0
|
||||
# self 参数按 __iter__ 首参类型对齐(stub 声明 self 可能是 i8*)
|
||||
iter_self: llvmlite.Value | t.CPtr = obj_val
|
||||
iter_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(iter_fn)
|
||||
if iter_first is not None:
|
||||
iter_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(iter_first)
|
||||
if iter_self_ty is not None:
|
||||
iter_self = llvmlite.build_bitcast(builder, obj_val, iter_self_ty)
|
||||
if iter_self is None:
|
||||
return 0
|
||||
iter_self.Next = None
|
||||
iter_result: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||||
builder, iter_fn_name, iter_self, 1, iter_ret_ty, 0)
|
||||
if iter_result is None:
|
||||
return 0
|
||||
|
||||
# 2. 查找 {Class}.__next__(带隐藏 __stop_iter_flag__ i1* 参数)
|
||||
next_lookup: str = pool.alloc(128)
|
||||
if next_lookup is None:
|
||||
return 0
|
||||
viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name)
|
||||
next_fn: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(
|
||||
mod, next_lookup)
|
||||
if next_fn is None:
|
||||
HandlesType.fatal_error(
|
||||
for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法")
|
||||
next_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(next_fn)
|
||||
next_fn_name: str = llvmlite.function_get_name(next_fn)
|
||||
if next_ret_ty is None or next_fn_name is None:
|
||||
return 0
|
||||
|
||||
# 3. 循环变量 alloca(元素类型 = __next__ 返回类型)
|
||||
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
trans.SymTab, var_name)
|
||||
new_vars: int = 0
|
||||
if var_alloca is None:
|
||||
var_alloca = HandlesVar._alloca_at_entry(builder, next_ret_ty)
|
||||
if var_alloca is not None:
|
||||
if HandlesVar.define_var(
|
||||
trans.SymTab, var_name, var_alloca) == 0:
|
||||
new_vars = 1
|
||||
|
||||
# 4. stop flag alloca(i1,初始 0)
|
||||
i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||||
flag_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i1_ty)
|
||||
if flag_alloca is None:
|
||||
return 0
|
||||
flag_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0")
|
||||
if flag_zero is not None:
|
||||
llvmlite.build_store(builder, flag_zero, flag_alloca)
|
||||
|
||||
# 5. 创建基本块: cond / body / step / end
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
name_buf: str = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "oop.cond.%d", cnt)
|
||||
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt)
|
||||
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt)
|
||||
step_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt)
|
||||
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
if cond_bb is None or body_bb is None or step_bb is None or end_bb is None:
|
||||
return 0
|
||||
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# 6. cond 块: 重置 flag → 调 __next__(iter, flag) → 检查 flag 判结束
|
||||
llvmlite.position_at_end(builder, cond_bb)
|
||||
if flag_zero is not None:
|
||||
llvmlite.build_store(builder, flag_zero, flag_alloca)
|
||||
# __next__ 参数 1:迭代器(按首参类型 bitcast)
|
||||
next_self: llvmlite.Value | t.CPtr = iter_result
|
||||
next_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(next_fn)
|
||||
if next_first is not None:
|
||||
next_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(next_first)
|
||||
if next_self_ty is not None and iter_result.Ty is not None:
|
||||
next_self = llvmlite.build_bitcast(builder, iter_result, next_self_ty)
|
||||
if next_self is None:
|
||||
return 0
|
||||
# 参数链表: arg1(iter).Next = arg2(flag);flag 独立 null 结尾防自链接
|
||||
next_self.Next = flag_alloca
|
||||
flag_alloca.Next = None
|
||||
next_val: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||||
builder, next_fn_name, next_self, 2, next_ret_ty, 0)
|
||||
if next_val is None:
|
||||
return 0
|
||||
stop_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i1_ty, flag_alloca)
|
||||
if stop_val is None:
|
||||
return 0
|
||||
flag_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0")
|
||||
continue_i1: llvmlite.Value | t.CPtr = None
|
||||
if flag_zero2 is not None:
|
||||
continue_i1 = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_EQ, stop_val, flag_zero2)
|
||||
if continue_i1 is None:
|
||||
return 0
|
||||
llvmlite.build_cond_br(builder, continue_i1, body_bb, end_bb)
|
||||
|
||||
# 7. body 块: store 元素 → 翻译循环体 → br step
|
||||
llvmlite.position_at_end(builder, body_bb)
|
||||
if var_alloca is not None:
|
||||
llvmlite.build_store(builder, next_val, var_alloca)
|
||||
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
|
||||
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = step_bb
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
|
||||
if body is not None:
|
||||
body_count: t.CSizeT = len(body)
|
||||
for bi in range(body_count):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
trans._break_bb = old_break
|
||||
trans._continue_bb = old_continue
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, step_bb)
|
||||
|
||||
# 8. step 块 → cond;定位到 end 块
|
||||
llvmlite.position_at_end(builder, step_bb)
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
return new_vars
|
||||
|
||||
# ============================================================
|
||||
# 多变量迭代(enumerate / zip)
|
||||
#
|
||||
|
||||
@@ -585,14 +585,21 @@ class MatchHandle(HandlesBase.Mixin):
|
||||
payload_idx: int = j + 1
|
||||
# 字段名查找作为回退(若字段名与 MatchAs 名一致可直接命中)
|
||||
if payload_idx >= renum_entry.FieldCount:
|
||||
# class_name 用 CSizeT 指针值比较:必须传 renum_entry.Name
|
||||
# (注册时 _update_renum_alias_class_ptr 统一后的 perm_pool
|
||||
# 指针);renum_name(AnnotClassName 等)是不同指针恒不匹配
|
||||
# → 恒 -1 → fail-fast 误报(追加73d 同款指针陷阱)
|
||||
alt_idx: int = HandlesClassDef._lookup_renum_field_alias(
|
||||
renum_name, bind_name)
|
||||
renum_entry.Name, bind_name)
|
||||
if alt_idx >= 1:
|
||||
payload_idx = alt_idx
|
||||
else:
|
||||
# fail-fast: payload 越界且别名查找失败
|
||||
# (node 在本函数不存在——参数是 pat/sub_pat,用 sub_pat
|
||||
# 定位到具体 MatchAs 模式;TPC Python 语义下未定义名只在
|
||||
# 运行时求值才报错,TPV 惰性编译方法体时即 NameError)
|
||||
HandlesType.fatal_error(
|
||||
node,
|
||||
sub_pat,
|
||||
f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败",
|
||||
"TypeError")
|
||||
# 获取字段类型
|
||||
@@ -619,6 +626,33 @@ class MatchHandle(HandlesBase.Mixin):
|
||||
sub_pat,
|
||||
f"REnum 变体字段 '{bind_name}' 地址计算失败",
|
||||
"TypeError")
|
||||
# 变体成员实际类型(对齐 TPC class_members L300-307/L376-382):
|
||||
# 注册时别名表存了成员注解解析出的类型(perm_pool 深拷贝)。
|
||||
# 用它把槽位地址 bitcast 成 Ptr(成员类型),使绑定变量按成员
|
||||
# 类型读 payload——Struct.Name: t.CChar|t.CPtr = i8*,否则按
|
||||
# 槽位 i64 读 → is 比较/下标/strlen 等字符串操作翻译失败
|
||||
# (CallGenMixin L4631 type_name_sp is not None 根因)。
|
||||
# 注意:必须按 (class, 变体名, 位置) 定位——MatchAs 名是局部
|
||||
# 变量名(type_name_sp),不是变体字段名(Name),按字段名
|
||||
# 查恒不匹配(追加76 第一次修复失效根因);同一 payload 位置
|
||||
# 跨变体类型也不同(Int.Bits=i32 vs Struct.Fields=Ptr)。
|
||||
# 自引用类型(如 Pointee: LLVMType|t.CPtr)注册期解析失败 →
|
||||
# 查不到类型 → 回退槽位类型(原始位宽在嵌套 match 中经
|
||||
# subject bitcast 仍可用)。
|
||||
mem_ty_m: llvmlite.LLVMType | t.CPtr = None
|
||||
vnt_m: str = self._extract_variant_name_from_cls(pat)
|
||||
if vnt_m is not None and renum_entry is not None \
|
||||
and renum_entry.Name is not None:
|
||||
mem_ty_m = HandlesClassDef._lookup_renum_member_ty(
|
||||
renum_entry.Name, vnt_m, payload_idx)
|
||||
if mem_ty_m is not None:
|
||||
mem_ptr_m: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||||
pool, mem_ty_m)
|
||||
if mem_ptr_m is not None:
|
||||
cast_m: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, elem_ptr, mem_ptr_m)
|
||||
if cast_m is not None:
|
||||
elem_ptr = cast_m
|
||||
HandlesVar.define_var(
|
||||
trans.SymTab, bind_name, elem_ptr)
|
||||
j = j + 1
|
||||
|
||||
@@ -28,11 +28,12 @@ import lib.core.VLogger as VLogger
|
||||
# ============================================================
|
||||
|
||||
STRUCT_MAX: t.CDefine = 512
|
||||
# 字段槽位上限制(对象化后 Generator 多继承组合可达 50+ 字段,48 会截断丢失)
|
||||
FIELD_MAX: t.CDefine = 64
|
||||
# 字段槽位上限制(Generator 12 Mixin 展平 ~97 字段;2026-08-16 追加78:64
|
||||
# 截断导致第 9+ 父类字段丢失 → __init__ 写 self.DiagStmtCount "属性写入失败")
|
||||
FIELD_MAX: t.CDefine = 128
|
||||
FIELD_NAME_MAX: t.CDefine = 64
|
||||
# 多继承(MRO)支持:单类最大父类数 / MRO 链最大长度
|
||||
PARENT_MAX: t.CDefine = 8
|
||||
# 多继承(MRO)支持:单类最大父类数 / MRO 链最大长度(Generator 12 父类)
|
||||
PARENT_MAX: t.CDefine = 16
|
||||
MRO_MAX: t.CDefine = 16
|
||||
|
||||
|
||||
@@ -219,6 +220,16 @@ def get_struct_count() -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def reset_module_methods_emitted(sha1: str) -> int:
|
||||
"""回滚指定模块注册类的 MethodsEmitted 标志(Phase A _deps_pending 重试
|
||||
前调用,防 MethodsEmitted 跨遍残留导致类方法缺失——追加87,委托到 gen.reset_module_methods_emitted)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.reset_module_methods_emitted(sha1)
|
||||
return 0
|
||||
|
||||
|
||||
def find_struct(name: str) -> StructEntry | t.CPtr:
|
||||
"""按类名查找结构体,返回 StructEntry 或 None(委托到 gen.find_struct)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
|
||||
@@ -47,7 +47,7 @@ import lib.Projectrans.Config as Config
|
||||
# ============================================================
|
||||
|
||||
# 常量
|
||||
MAX_VARS: t.CDefine = 256
|
||||
MAX_VARS: t.CDefine = 1024
|
||||
MAX_FUNCS: t.CDefine = 1024
|
||||
MAX_GLOBAL_NAMES: t.CDefine = 32
|
||||
|
||||
@@ -129,6 +129,25 @@ class Translator:
|
||||
# *args 参数名(如 "args"),用于符号表注册
|
||||
_vararg_name: str
|
||||
|
||||
# OOP iter 协议:当前 __next__ 方法的隐藏 stop-flag 参数(i1*)。
|
||||
# _translate_method 注入 __stop_iter_flag__ 参数时设置;translate_raise
|
||||
# 检测 raise StopIteration 时对该指针 store 1(对齐 TPC HandlesRaise.py)。
|
||||
# 非 __next__ 函数中为 None。
|
||||
_stop_iter_flag_ptr: llvmlite.Value | t.CPtr
|
||||
|
||||
# try-except 机制(对齐 TPC HandlesTry.py):当前最内层 try 的
|
||||
# 分发块 + 异常编码/消息 alloca。translate_try 设置,translate_raise
|
||||
# 与调用侧 EH 检测写入/跳转。try 外为 None。
|
||||
_eh_dispatch_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_eh_code_ptr: llvmlite.Value | t.CPtr
|
||||
_eh_msg_ptr: llvmlite.Value | t.CPtr
|
||||
# 当前函数的 __eh_msg_out__(i8**)/__eh_code_out__(i32*)输出参数
|
||||
# (函数签名含 raise 时由 translate_function_def/_translate_method 注入)。
|
||||
# 无 EH 参数时 _cur_func_has_eh == 0。
|
||||
_eh_msg_out_param: llvmlite.Value | t.CPtr
|
||||
_eh_code_out_param: llvmlite.Value | t.CPtr
|
||||
_cur_func_has_eh: int
|
||||
|
||||
# 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间)
|
||||
ModuleSha1: str
|
||||
# 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...)
|
||||
@@ -203,6 +222,13 @@ class Translator:
|
||||
self._cur_func_name = None
|
||||
self._va_list_ptr = None
|
||||
self._vararg_name = None
|
||||
self._stop_iter_flag_ptr = None
|
||||
self._eh_dispatch_bb = None
|
||||
self._eh_code_ptr = None
|
||||
self._eh_msg_ptr = None
|
||||
self._eh_msg_out_param = None
|
||||
self._eh_code_out_param = None
|
||||
self._cur_func_has_eh = 0
|
||||
self.ModuleSha1 = None
|
||||
self.CurrentPackage = None
|
||||
self._closure_env_offsets = 0
|
||||
|
||||
@@ -66,6 +66,46 @@ def set_global_gen(gen: t.CVoid | t.CPtr) -> None:
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 类编译期元数据(__provides__/__requires__/__require_must__)
|
||||
#
|
||||
# _fakeduck.vp 的 _str 用 __requires__ = ['__mbuddy__'] 声明 with 上下文
|
||||
# 依赖字段;with 提供者用 __provides__ 声明注入字段。这些是编译期
|
||||
# 元数据,不生成运行字段(FakeDuck 移植点 1)。
|
||||
# ============================================================
|
||||
CLASS_META_PROVIDES: t.CDefine = 1
|
||||
CLASS_META_REQUIRES: t.CDefine = 2
|
||||
CLASS_META_REQUIRE_MUST: t.CDefine = 3
|
||||
|
||||
|
||||
def register_class_meta(pool: memhub.MemBuddy | t.CPtr,
|
||||
kind: int, cls: str, field: str) -> int:
|
||||
"""注册类编译期元数据字段(委托到 gen.register_class_meta),0=成功"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.register_class_meta(pool, kind, cls, field)
|
||||
return 1
|
||||
|
||||
|
||||
def class_meta_count(kind: int, cls: str) -> int:
|
||||
"""返回某类某元数据类型的字段数(委托到 gen.class_meta_count)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.class_meta_count(kind, cls)
|
||||
return 0
|
||||
|
||||
|
||||
def class_meta_field_at(kind: int, cls: str, idx: int) -> str:
|
||||
"""返回某类某元数据类型的第 idx 个字段名(委托到 gen.class_meta_field_at)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.class_meta_field_at(kind, cls, idx)
|
||||
return None
|
||||
|
||||
|
||||
def _ensure_trace_init() -> int:
|
||||
"""确保调用栈已初始化(委托到 gen._ensure_trace_init)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
@@ -140,7 +180,7 @@ def _dbg_check_ast_floats(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
|
||||
def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, value: int) -> None:
|
||||
name: str, value: t.CInt64T) -> None:
|
||||
"""注册 CDefine 编译期常量到本地表(委托到 gen.register_cdefine_constant)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
@@ -166,7 +206,7 @@ def register_cdefine_string(pool: memhub.MemBuddy | t.CPtr,
|
||||
g.register_cdefine_string(pool, name, value)
|
||||
|
||||
|
||||
def lookup_cdefine_constant(name: str) -> int:
|
||||
def lookup_cdefine_constant(name: str) -> t.CInt64T:
|
||||
"""查找 CDefine 编译期常量(委托到 gen.lookup_cdefine_constant)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
|
||||
@@ -31,7 +31,9 @@ SCOPE_FUNCTION: t.CDefine = 1
|
||||
SCOPE_BLOCK: t.CDefine = 2
|
||||
|
||||
# 每个作用域最大变量数
|
||||
MAX_VARS: t.CDefine = 256
|
||||
# 256 太小:NewAstTest main() 有 289 个局部变量,add_var 超限静默失败
|
||||
# 导致变量未注册,后续使用报"未定义名称"(与 Gen/VarGenMixin 保持一致)。
|
||||
MAX_VARS: t.CDefine = 1024
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
+30
-12
@@ -388,7 +388,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔)
|
||||
# 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist,实现按需编译
|
||||
# 声明在 if 块外,确保 Phase B+ 和清理代码能访问
|
||||
APP_DEPS_BUF_SIZE: t.CSizeT = 8192
|
||||
# 65536 与 StubMerger.REACH_WORKLIST_BUF 对齐:全量 App imports 拼接
|
||||
# 超 8192(追加82 同源溢出),8192 会静默丢依赖致 Phase B+ 可达集合不全
|
||||
APP_DEPS_BUF_SIZE: t.CSizeT = 65536
|
||||
app_deps_buf: bytes = None
|
||||
app_deps_len: t.CSizeT = 0
|
||||
if do_phase1 != 0:
|
||||
@@ -552,10 +554,6 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
string.memset(done_flags, 0, file_count)
|
||||
# 二分诊断:Phase A 开始前主池用量——若已接近 1GB 说明
|
||||
# pre-inc/pre 阶段的 reset_to(mark2) 未回收(记录栈/realloc 失效);
|
||||
# 若用量低则泄漏发生在 Phase A 自身。
|
||||
stdio.printf("[MEM] Phase A 前主池 used=%zu\n", mb.used_bytes())
|
||||
PHASE_A_MAX_PASSES: t.CInt = 32
|
||||
for pass_a in range(PHASE_A_MAX_PASSES):
|
||||
completed_this_pass: int = 0
|
||||
@@ -564,9 +562,6 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
continue
|
||||
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||
# OOM 二分诊断:翻译前 used —— 若逐文件递增 → reset_to(mark2) 未回收;
|
||||
# 若单文件翻译中暴涨 → 单文件瞬时峰值/泄漏(定位 Phase A OOM)
|
||||
stdio.printf("[MEM] PhaseA 翻译前 i=%d/%d used=%zu\n", i, file_count, mb.used_bytes())
|
||||
if ent is None or ent.Path is None:
|
||||
done_flags[i] = 1
|
||||
completed_this_pass += 1
|
||||
@@ -600,7 +595,17 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if fb_dp is not None:
|
||||
viperlib.snprintf(fb_dp, 1024,
|
||||
"Phase A 依赖未就绪,下遍重试: %s", ent.Path)
|
||||
VLogger.warning(fb_dp, "PhaseA-DBG")
|
||||
# --nowarn-register 亦抑制此类 Phase A 依赖重试 WARN(刷屏收敛)
|
||||
if VLogger.nowarn_register() == 0:
|
||||
VLogger.warning(fb_dp, "PhaseA-DBG")
|
||||
# 回滚本文件已注册类的 MethodsEmitted:第 1 遍 _translate_oop_methods
|
||||
# 发射方法体前已置 MethodsEmitted=1(防重入),但方法体内跨模块调用
|
||||
# 依赖 text.ll 未生成触发 _deps_pending → 本遍作废;若不回滚,
|
||||
# 下遍重译 existing 分支被 MethodsEmitted==1 防重复检查拦截 → 类方法
|
||||
# 永不发射 → 链接 undefined symbol(追加87 根因)。
|
||||
# 必须先于 mb.reset_to(mark2)(MethodsEmitted 在 perm_pool 上跨 reset 存活)。
|
||||
if ent.Sha1 is not None:
|
||||
HandlesStruct.reset_module_methods_emitted(ent.Sha1)
|
||||
# OOM 清理:本文件翻译已产生瞬时数据(下遍会重新翻译),立即回收
|
||||
mb.reset_to(mark2)
|
||||
continue
|
||||
@@ -655,9 +660,6 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# OOM 清理:stub/text/deps 已写盘,回收本文件翻译瞬时数据
|
||||
# (AST/tokens/lexer/IR/Handler);app_deps_buf 已深拷贝依赖,不受影响
|
||||
mb.reset_to(mark2)
|
||||
# OOM 二分诊断:reset 后 used —— 应回落到 mark2 水位(3MB 级),
|
||||
# 若仍高 → reset 失效(记录栈缺失/coalesce 未归还)
|
||||
stdio.printf("[MEM] PhaseA 翻译后 reset i=%d/%d used=%zu\n", i, file_count, mb.used_bytes())
|
||||
# 收敛检查:所有文件完成则结束
|
||||
all_done: int = 1
|
||||
for i_ck in range(file_count):
|
||||
@@ -1128,6 +1130,22 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
string.strcpy(final_obj_paths, main_obj_path)
|
||||
fop_pos = mlen
|
||||
|
||||
# 合并 Phase B/B+ 编译的 App 非 main 模块 .obj(obj_paths,空格分隔)。
|
||||
# 此前 final_obj_paths 只含 main_obj + reachable includes,App 依赖文件
|
||||
# (main import 的 syslibtest_impl/os_backend 等)的 .obj 从未入链——追加28
|
||||
# 前靠 reachable 误含 App 时从 includes.binary 的重复 obj 兜底(undefined
|
||||
# symbol: ae2038ced7b4634f.run 根因)。obj_paths 同时含 Phase B+ 本次
|
||||
# 新编译的 includes obj(与下方 reachable 收集重复,--allow-multiple-
|
||||
# definition 容忍,仅本次编译的少量文件)。
|
||||
if obj_pos > 0:
|
||||
if fop_pos + obj_pos + 1 < OBJ_PATHS_SIZE + 512:
|
||||
if fop_pos > 0:
|
||||
final_obj_paths[fop_pos] = ' '
|
||||
fop_pos += 1
|
||||
string.strcpy(final_obj_paths + fop_pos, obj_paths)
|
||||
fop_pos += obj_pos
|
||||
final_obj_paths[fop_pos] = '\0'
|
||||
|
||||
# 按图链接:遍历 reachable_set,只收集可达 includes 的 .obj
|
||||
# 不再全量收集 includes.binary 下的所有 .obj
|
||||
if reachable_set is not None and reachable_count > 0:
|
||||
|
||||
+101
-91
@@ -44,6 +44,9 @@ MAX_INCLUDES_SHA1: t.CDefine = 1024
|
||||
STUB_READ_BUF_SIZE: t.CDefine = 1048576
|
||||
# 最大 includes 条目数
|
||||
MAX_INCLUDES: t.CDefine = 1024
|
||||
# 可达性分析 worklist/processed 缓冲区大小(8192 不够:递归扫描 source_dir
|
||||
# 后 worklist 含全部 App 文件 imports 的拼接 + BFS 依赖展开,追加82 溢出)
|
||||
REACH_WORKLIST_BUF: t.CDefine = 65536
|
||||
|
||||
# 全局 SHA1 映射存储器(内存中,不依赖 _sha1_map.txt 文件)
|
||||
# Phase1 扫描完成后填充,供所有函数使用
|
||||
@@ -1015,6 +1018,29 @@ def _CommentOutGlobalInBuf(out_buf: bytes, global_name: str) -> int:
|
||||
return commented
|
||||
|
||||
|
||||
def _HasGlobalInBuf(out_buf: bytes, global_name: str) -> int:
|
||||
"""检测 out_buf 中是否已有同名全局变量行(行首匹配,未注释)
|
||||
|
||||
用于跳过重复追加依赖全局强定义:stub 注入已提供 external 声明,
|
||||
依赖 text.ll 的强定义只需在定义模块存在一份,复制进每个依赖方
|
||||
会导致 ld.lld duplicate symbol(如 _op_head、MemBuddy.vtable)。
|
||||
"""
|
||||
if out_buf is None or global_name is None:
|
||||
return 0
|
||||
name_len: t.CSizeT = string.strlen(global_name)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
if name_len == 0 or out_len == 0 or name_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
while pos + name_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, global_name, name_len) == 0:
|
||||
# 确认是行首(前一个是换行或 pos==0)
|
||||
if pos == 0 or out_buf[pos - 1] == '\n':
|
||||
return 1
|
||||
pos += 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _CommentOutOpaqueTypeInBuf - 将 out_buf 中匹配类型名的 opaque 声明行注释掉
|
||||
#
|
||||
@@ -1501,16 +1527,24 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
# 截断到 '=' 之前(不含 '='),得到全局变量名 @name
|
||||
saved_gv: t.CChar = dep_buf[eq_gv]
|
||||
dep_buf[eq_gv] = '\0'
|
||||
# 注释掉 out_buf 中的同名行(external 声明或旧定义)
|
||||
_CommentOutGlobalInBuf(out_buf, dep_buf + ls)
|
||||
dep_buf[eq_gv] = saved_gv
|
||||
# 追加完整定义
|
||||
if out_pos + ll + 2 < out_size:
|
||||
string.strncpy(out_buf + out_pos, dep_buf + ls, ll)
|
||||
out_pos += ll
|
||||
out_buf[out_pos] = '\n'
|
||||
out_pos += 1
|
||||
out_buf[out_pos] = '\0'
|
||||
# 依赖方已有同名全局(stub 注入的 external 声明或先前依赖的定义)
|
||||
# 时跳过:跨模块全局(如 _op_head、MemBuddy.vtable)只需一份
|
||||
# 强定义(在定义模块的 text.ll 中),复制进每个依赖方会导致
|
||||
# ld.lld duplicate symbol(NewAstTest _op_head/MemBuddy.vtable 根因)。
|
||||
# 仅当依赖方完全没有该全局(既无 external 也无定义)时才需要补充。
|
||||
if _HasGlobalInBuf(out_buf, dep_buf + ls) == 0:
|
||||
# 注释掉 out_buf 中的同名行(external 声明或旧定义)
|
||||
_CommentOutGlobalInBuf(out_buf, dep_buf + ls)
|
||||
dep_buf[eq_gv] = saved_gv
|
||||
# 追加完整定义
|
||||
if out_pos + ll + 2 < out_size:
|
||||
string.strncpy(out_buf + out_pos, dep_buf + ls, ll)
|
||||
out_pos += ll
|
||||
out_buf[out_pos] = '\n'
|
||||
out_pos += 1
|
||||
out_buf[out_pos] = '\0'
|
||||
else:
|
||||
dep_buf[eq_gv] = saved_gv
|
||||
continue
|
||||
|
||||
# 跳过其他行
|
||||
@@ -1679,7 +1713,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
VLogger.debug(fb, "Reachable")
|
||||
|
||||
# 工作列表(空格分隔的模块名)
|
||||
worklist: bytes = stdlib.malloc(8192)
|
||||
worklist: bytes = stdlib.malloc(REACH_WORKLIST_BUF)
|
||||
if worklist is None:
|
||||
stdlib.free(sha1_arr)
|
||||
stdlib.free(mod_arr)
|
||||
@@ -1693,67 +1727,33 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
# 否则,回退到自己的非递归扫描(source_dir/*.py,只扫描顶层)
|
||||
if app_deps is not None and app_deps[0] != '\0':
|
||||
ad_len: t.CSizeT = string.strlen(app_deps)
|
||||
if ad_len > 0 and ad_len < 8192:
|
||||
if ad_len > 0 and ad_len < REACH_WORKLIST_BUF:
|
||||
string.strcpy(worklist, app_deps)
|
||||
wl_len = ad_len
|
||||
else:
|
||||
VLogger.error("app_deps 过长,无法构建可达集合", "StubMerger")
|
||||
else:
|
||||
# app_deps 缺失:Phase1 场景(未翻译 App 源文件)为设计性回退,
|
||||
# 显式 warning 暴露回退,不再静默
|
||||
VLogger.warning("app_deps 缺失,回退非递归扫描 source_dir", "Reachable")
|
||||
# 回退到自己的非递归扫描
|
||||
dir_len: t.CSizeT = string.strlen(source_dir)
|
||||
pattern: bytes = stdlib.malloc(dir_len + 8)
|
||||
if pattern is None:
|
||||
stdlib.free(sha1_arr)
|
||||
stdlib.free(mod_arr)
|
||||
stdlib.free(worklist)
|
||||
return -1
|
||||
viperlib.snprintf(pattern, dir_len + 8, "%s/*", source_dir)
|
||||
|
||||
find_data_size: t.CSizeT = win32file.WIN32_FIND_DATAA.__sizeof__()
|
||||
find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(find_data_size + 16)
|
||||
if find_data is None:
|
||||
stdlib.free(pattern)
|
||||
stdlib.free(sha1_arr)
|
||||
stdlib.free(mod_arr)
|
||||
stdlib.free(worklist)
|
||||
return -1
|
||||
string.memset(find_data, 0, find_data_size + 16)
|
||||
|
||||
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
|
||||
if handle == win32base.INVALID_HANDLE_VALUE:
|
||||
fb_fd: str = VLogger.fmt_buf()
|
||||
if fb_fd is not None:
|
||||
viperlib.snprintf(fb_fd, 1024, "未找到源文件(.vp/.py): %s", pattern)
|
||||
VLogger.warning(fb_fd, "Reachable")
|
||||
stdlib.free(pattern)
|
||||
stdlib.free(find_data)
|
||||
stdlib.free(sha1_arr)
|
||||
stdlib.free(mod_arr)
|
||||
stdlib.free(worklist)
|
||||
return -1
|
||||
|
||||
while True:
|
||||
fname: str = find_data.cFileName
|
||||
if fname is None:
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
fname_len: t.CSizeT = string.strlen(fname)
|
||||
if Utils.is_vp_or_py_at(fname, 0, fname_len) == 0:
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
full_path: bytes = Utils.JoinPath(source_dir, fname)
|
||||
if full_path is None:
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
sbuf: bytes = Utils.read_file_to_buf(full_path, SRC_BUF_SIZE_R)
|
||||
if sbuf is not None:
|
||||
# 解析 AST 获取 _imported_modules
|
||||
# 显式 warning 暴露回退,不再静默。
|
||||
# 原实现仅非递归扫描 source_dir 顶层("%s/*"),漏掉 lib/ 等子目录的
|
||||
# App 文件 → 其依赖(如 lib/Projectrans/Config.vp 的 json)不进入
|
||||
# worklist → json 不可达 → Phase1 不 stub 不翻译 → Phase2 Phase A
|
||||
# 翻译 Config.vp 时 root.is_object() 跨模块调用无 stub 可查 → 静默
|
||||
# translate_value 返回 None → "if 条件表达式翻译失败"(追加82 根因)。
|
||||
# 改为递归扫描(复用 IncludesScanner.scan_includes),覆盖全部子目录。
|
||||
VLogger.warning("app_deps 缺失,递归扫描 source_dir", "Reachable")
|
||||
scan_res_r: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, source_dir)
|
||||
if scan_res_r is not None:
|
||||
es_r: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
for e_i_r in range(scan_res_r.Count):
|
||||
e_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(
|
||||
t.CVoid(t.CUInt64T(scan_res_r.Entries) + t.CUInt64T(e_i_r) * es_r, t.CPtr))
|
||||
if e_r is None or e_r.Path is None:
|
||||
continue
|
||||
sbuf: bytes = Utils.read_file_to_buf(e_r.Path, SRC_BUF_SIZE_R)
|
||||
if sbuf is None:
|
||||
continue
|
||||
# 解析 AST 获取 _imported_modules(与原顶层扫描一致)
|
||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||
if lx is not None:
|
||||
ast._lexer_init(lx, sbuf, mb)
|
||||
@@ -1763,21 +1763,18 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
|
||||
if tr is not None:
|
||||
tr._declare_only = 2
|
||||
# 源文件包名:fname 是顶级文件名(无目录分隔符),包为 None
|
||||
tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, fname)
|
||||
# 源文件包名:用 RelPath(相对 source_dir,支持子目录),
|
||||
# 保证 from .xxx import 相对导入解析正确
|
||||
tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, e_r.RelPath)
|
||||
HandlesStruct.reset_visible_structs(mb, 0)
|
||||
tr.translate(tree)
|
||||
# 容器使用检测:App 源文件用 list/dict(裸名注解/构造/[]
|
||||
# /{} 字面量)时注入 _list/_dict 依赖(与 Phase1 对 includes
|
||||
# 层的 _ScanTreeForContainers 对齐)。否则 dict/list 类未被
|
||||
# 纳入可达集合 → 不编译 → 跨模块方法(如 dict.set_int)返回
|
||||
# 类型函数/text.ll/vpi 均未命中 → _fail_method_ret_ty 误杀
|
||||
# (DictTest 8/13 重现根因)。
|
||||
# /{} 字面量)时注入 _list/_dict 依赖(与原实现一致)
|
||||
tr._inject_auto_container_visibility(mb, tree)
|
||||
# 获取 _imported_modules
|
||||
if tr._imported_modules is not None:
|
||||
im_len: t.CSizeT = string.strlen(tr._imported_modules)
|
||||
if im_len > 0 and wl_len + im_len + 1 < 8192:
|
||||
if im_len > 0 and wl_len + im_len + 1 < REACH_WORKLIST_BUF:
|
||||
string.strcpy(worklist + wl_len, tr._imported_modules)
|
||||
wl_len += im_len
|
||||
worklist[wl_len] = ' '
|
||||
@@ -1785,23 +1782,14 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
worklist[wl_len] = '\0'
|
||||
# 计算 App 源文件 SHA1,填充依赖到内存存储器
|
||||
# worklist 遍历时,LookupIncludesDeps 能找到 App 源文件的依赖
|
||||
app_sha1_r: str = IncludesScanner.compute_file_sha1(mb, full_path)
|
||||
if app_sha1_r is not None:
|
||||
PopulateIncludesDeps(app_sha1_r, tr._imported_modules)
|
||||
stdlib.free(app_sha1_r)
|
||||
if e_r.Sha1 is not None:
|
||||
PopulateIncludesDeps(e_r.Sha1, tr._imported_modules)
|
||||
# 释放 Translator 资源
|
||||
if tr._global_names is not None:
|
||||
stdlib.free(tr._global_names)
|
||||
if tr._nonlocal_names is not None:
|
||||
stdlib.free(tr._nonlocal_names)
|
||||
stdlib.free(sbuf)
|
||||
stdlib.free(full_path)
|
||||
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
win32base.FindClose(handle)
|
||||
stdlib.free(pattern)
|
||||
stdlib.free(find_data)
|
||||
|
||||
# 去掉末尾多余空格
|
||||
if wl_len > 0 and worklist[wl_len - 1] == ' ':
|
||||
@@ -1822,7 +1810,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
if HandlesImports.is_module_imported(worklist, "builtins") == 0:
|
||||
bsha1_b: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, "builtins")
|
||||
if bsha1_b is not None:
|
||||
if wl_len + 9 < 8192:
|
||||
if wl_len + 9 < REACH_WORKLIST_BUF:
|
||||
if wl_len > 0:
|
||||
worklist[wl_len] = ' '
|
||||
wl_len += 1
|
||||
@@ -1837,7 +1825,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
VLogger.debug(fb, "Reachable")
|
||||
|
||||
# 3. 工作列表算法:递归收集可达 SHA1
|
||||
processed: bytes = stdlib.malloc(8192)
|
||||
processed: bytes = stdlib.malloc(REACH_WORKLIST_BUF)
|
||||
if processed is None:
|
||||
stdlib.free(sha1_arr)
|
||||
stdlib.free(mod_arr)
|
||||
@@ -1874,7 +1862,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
if already == 0:
|
||||
# 加入 processed(嵌套 if 拆分 + 用 = 代替 += 绕过 TPC AUGASGN bug)
|
||||
if processed is not None:
|
||||
if proc_len + name_len + 1 < 8192:
|
||||
if proc_len + name_len + 1 < REACH_WORKLIST_BUF:
|
||||
string.strcpy(processed + proc_len, mod_buf)
|
||||
proc_len = proc_len + name_len
|
||||
processed[proc_len] = ' '
|
||||
@@ -1886,8 +1874,22 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
# 查找 SHA1
|
||||
found_sha1: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, mod_buf)
|
||||
if found_sha1 is not None:
|
||||
# 加入 reachable_set
|
||||
reachable_count = _AddSha1ToSet(reachable_set, reachable_count, found_sha1)
|
||||
# App 源文件(Sha1Store 中 IncDir 为空,AppendToSha1MapStore 规则)
|
||||
# 不加入 reachable_set:Phase B 已编译其 .obj,若加入会导致 Phase B+
|
||||
# 把 App 文件重复编译进 includes.binary,Phase C 链接时与 Phase B 的
|
||||
# App obj 重复符号(SysLibTest ld.lld duplicate symbol: _mbuddy 根因)。
|
||||
# 依赖仍继续展开(App 文件是依赖图中间节点,其 includes 依赖必须可达)。
|
||||
is_app_r: int = 0
|
||||
if _sha1_store_incdir is not None:
|
||||
for ai_r in range(_sha1_store_count):
|
||||
asi_r: t.CSizeT = t.CSizeT(ai_r) * 17
|
||||
if string.strcmp(_sha1_store_arr + asi_r, found_sha1) == 0:
|
||||
aii_r: t.CSizeT = t.CSizeT(ai_r) * MAX_INC_DIR_LEN
|
||||
if _sha1_store_incdir[aii_r] == '\0':
|
||||
is_app_r = 1
|
||||
break
|
||||
if is_app_r == 0:
|
||||
reachable_count = _AddSha1ToSet(reachable_set, reachable_count, found_sha1)
|
||||
|
||||
# 从内存查找依赖(不读 deps.txt 过程文件)
|
||||
# Phase B+ 前用 declare_only 翻译所有 includes 文件,提取 _imported_modules 存入内存
|
||||
@@ -1895,7 +1897,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
if deps_str is not None:
|
||||
dl: t.CSizeT = string.strlen(deps_str)
|
||||
if dl > 0:
|
||||
if wl_len + dl + 2 < 8192:
|
||||
if wl_len + dl + 2 < REACH_WORKLIST_BUF:
|
||||
if wl_len > 0 and worklist[wl_len - 1] != ' ':
|
||||
worklist[wl_len] = ' '
|
||||
wl_len = wl_len + 1
|
||||
@@ -2052,6 +2054,14 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
else:
|
||||
deps_buf[4095] = '\0'
|
||||
deps_loaded = 1
|
||||
elif deps_br == 0:
|
||||
# 空 deps.txt:无 import 的包标记文件(如 lib/core/Gen/__init__.vp、
|
||||
# lib/StubGen/__init__.vp 纯注释)合法——deps_loaded 置 1 视为
|
||||
# "已加载且无依赖",避免下方"deps.txt 缺失"误报(追加85 根因)。
|
||||
# deps_buf 是 malloc 未初始化内存,必须显式置空串,
|
||||
# 否则后续 strlen(deps_buf) 读到垃圾长度遍历越界。
|
||||
deps_buf[0] = '\0'
|
||||
deps_loaded = 1
|
||||
df_deps.close()
|
||||
stdlib.free(deps_path)
|
||||
|
||||
|
||||
@@ -234,6 +234,26 @@ def set_logger(logger: Logger | t.CPtr) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# --nowarn-register 开关(追加):抑制 Phase A 依赖类 WARN 输出——
|
||||
# ①"外部函数返回类型未登记"(HandlesExprCall)②"Phase A 依赖未就绪,
|
||||
# 下遍重试"(PhaseA-DBG)。自举编译中大量出现,刷屏影响日志收敛。
|
||||
# 仅抑制输出,不影响内部逻辑(默认 i32 推断、标记重试等照常执行)。
|
||||
# ============================================================
|
||||
_nowarn_register_flag: t.CInt = 0
|
||||
|
||||
|
||||
def set_nowarn_register(flag: int) -> None:
|
||||
"""设置 --nowarn-register(1=抑制 Phase A 依赖类 WARN 输出)"""
|
||||
global _nowarn_register_flag
|
||||
_nowarn_register_flag = flag
|
||||
|
||||
|
||||
def nowarn_register() -> int:
|
||||
"""查询 --nowarn-register 开关状态(1=抑制)"""
|
||||
return _nowarn_register_flag
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块级便捷函数(与 TPC 的 lib.core.VLogger 对齐)
|
||||
#
|
||||
|
||||
+88
-82
@@ -1,17 +1,3 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import argparse
|
||||
import w32.win32console as w32cmd
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import sys
|
||||
import ast
|
||||
import lib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
@@ -43,37 +29,41 @@ import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.Generator as GenGenerator
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib
|
||||
from stdint import *
|
||||
import stdio
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import argparse
|
||||
import w32.win32console as w32cmd
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import sys
|
||||
import ast
|
||||
import llvmlite
|
||||
import subprocess
|
||||
import viperlib
|
||||
import hashlib
|
||||
import t, c
|
||||
|
||||
|
||||
# 内存大小: fl_bytes=264 (33*8)。
|
||||
# 主池 1.5GB(1.5×2^30 + 264 = 1610613000):memhub 二进制分解为 2^30+2^29 两块。
|
||||
# 曾试 2GB(2^31+264):当前机器物理内存可用不足 1GB(已提交 76.6GB/81.3GB),
|
||||
# 主池 2GB + perm_pool 512MB = 2.5GB 提交导致 malloc 失败 → TPV 启动即退出。
|
||||
# 1.5GB + 512MB = 2GB 整提交,留 2.7GB 提交余量,稳妥且比 1.2GB 多 0.3GB。
|
||||
# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件,512MB 不足导致 Phase2 崩溃
|
||||
# 2026-08-13: NewAstTest 依赖 ast 模块(98 includes),Phase2 的 Phase A-pre-inc/Phase A
|
||||
# 无 mark/reset 回收,98 个 includes 的 AST/IR 全量累积 pool 超 1GB → 曾增大到 2GB。
|
||||
# → 已在 Phase2 对齐 Phase1 的 mark1/reset_to 清理机制(每文件翻译后回收瞬时数据),
|
||||
# 峰值回落至单文件水平;1.5GB 主池给单文件峰值与 Phase A 高并发翻译留足余量。
|
||||
POOL_SIZE: t.CDefine = 1610613000
|
||||
# 永久内存池大小:2^29 + 264 = 512MB usable(存跨 mark 持久数据:泛型模板
|
||||
# 表/节点、struct/union/REnum 类型树、枚举 BaseTy、spec 缓存等)。
|
||||
# 与主 pool 独立(MemBuddy 第二实例),永不 reset_to,不占主 pool 配额。
|
||||
# Main Pool 1 GiB
|
||||
POOL_SIZE: t.CDefine = 1073741824
|
||||
# Permanent memory pool size: 2^29 + 264 = 512MB usable
|
||||
PERM_POOL_SIZE: t.CDefine = 536871176
|
||||
# 语言编码页
|
||||
# Code page: UTF-8 (Windows 65001)
|
||||
CODE_PAGE: t.CDefine = 65001
|
||||
# 源代码缓冲区大小(1MB)
|
||||
# Source code buffer size (1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
|
||||
# Version (dev/beta/rc)
|
||||
VIPER_VERSION: t.CDefine = "1.0.3-dev.27 2026-05-27 Non-LTS"
|
||||
TPV_VERSION: t.CDefine = "0.0.2-dev.173"
|
||||
RUNTIME_VERSION: t.CDefine = "0.2.2+3-Non-LTS"
|
||||
|
||||
# ============================================================
|
||||
# main: 命令行入口
|
||||
#
|
||||
# 解析参数 → 加载配置 → AST 解析 → LLVM IR 翻译 → 编译管线 → 可选执行
|
||||
# main: Command-line entry
|
||||
# ============================================================
|
||||
def main() -> int:
|
||||
w32cmd.SetConsoleOutputCP(CODE_PAGE)
|
||||
@@ -89,9 +79,6 @@ def main() -> int:
|
||||
return 1
|
||||
|
||||
# 创建全局永久内存池(perm_pool,512MB):存放跨 mark/reset 持久数据
|
||||
# (泛型模板表/节点、struct/union/REnum 类型树、枚举 BaseTy、spec 缓存
|
||||
# 等),替代 stdlib.malloc 深拷贝(buddy 分配更快),永不 reset,不占
|
||||
# 主 pool 配额。经 CompilerFactory 单例分发(不改通用库 memhub)。
|
||||
perm_arena: bytes = stdlib.malloc(PERM_POOL_SIZE)
|
||||
if perm_arena is None:
|
||||
stdio.printf("FAIL: malloc for perm_pool arena failed\n")
|
||||
@@ -155,8 +142,8 @@ def main() -> int:
|
||||
|
||||
# 初始化 VLogger 并打印启动日志
|
||||
log: VLogger.Logger | t.CPtr = VLogger.get_logger()
|
||||
if log is not None:
|
||||
log.info("TransPyV 启动")
|
||||
if log is None:
|
||||
log.error("TransPyV Failed to parse parameters")
|
||||
|
||||
# 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline)
|
||||
sys._init_argv()
|
||||
@@ -188,6 +175,10 @@ def main() -> int:
|
||||
argparse.STORE_TRUE, "清除 .transpyc_cache 全局缓存")
|
||||
parser.add_argument("--asan", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "ASan 模式:.ll 先 opt -passes=asan 插桩,链接加 -fsanitize=address")
|
||||
parser.add_argument("--nowarn-register", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "抑制 Phase A 依赖类 WARN(外部函数返回类型未登记 / 依赖未就绪重试)输出(保留逻辑,仅不打印)")
|
||||
parser.add_argument("--version", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "显示版本,指定此参数后忽略其它所有参数")
|
||||
|
||||
# 解析命令行参数
|
||||
args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv)
|
||||
@@ -197,69 +188,75 @@ def main() -> int:
|
||||
return 1
|
||||
|
||||
# 打印解析结果
|
||||
if log is not None:
|
||||
log.banner("TransPyV 参数解析结果")
|
||||
#if log is not None:
|
||||
# log.banner("TransPyV 参数解析结果")
|
||||
|
||||
# 字符串参数
|
||||
project: str = args.get_str("project")
|
||||
if project is not None:
|
||||
stdio.printf(" --project: %s\n", project)
|
||||
else:
|
||||
stdio.printf(" --project: (未指定)\n")
|
||||
#if project is not None:
|
||||
# stdio.printf(" --project: %s\n", project)
|
||||
#else:
|
||||
# stdio.printf(" --project: (未指定)\n")
|
||||
|
||||
src: str = args.get_str("src")
|
||||
if src is not None:
|
||||
stdio.printf(" --src: %s\n", src)
|
||||
else:
|
||||
stdio.printf(" --src: (未指定)\n")
|
||||
#if src is not None:
|
||||
# stdio.printf(" --src: %s\n", src)
|
||||
#else:
|
||||
# stdio.printf(" --src: (未指定)\n")
|
||||
|
||||
temp: str = args.get_str("temp")
|
||||
if temp is not None:
|
||||
stdio.printf(" --temp: %s\n", temp)
|
||||
else:
|
||||
stdio.printf(" --temp: (未指定)\n")
|
||||
#if temp is not None:
|
||||
# stdio.printf(" --temp: %s\n", temp)
|
||||
#else:
|
||||
# stdio.printf(" --temp: (未指定)\n")
|
||||
|
||||
output: str = args.get_str("output")
|
||||
if output is not None:
|
||||
stdio.printf(" --output: %s\n", output)
|
||||
else:
|
||||
stdio.printf(" --output: (未指定)\n")
|
||||
#if output is not None:
|
||||
# stdio.printf(" --output: %s\n", output)
|
||||
#else:
|
||||
# stdio.printf(" --output: (未指定)\n")
|
||||
|
||||
phase: str = args.get_str("phase")
|
||||
if phase is not None:
|
||||
stdio.printf(" --phase: %s\n", phase)
|
||||
else:
|
||||
stdio.printf(" --phase: (未指定,默认 all)\n")
|
||||
#if phase is not None:
|
||||
# stdio.printf(" --phase: %s\n", phase)
|
||||
#else:
|
||||
# stdio.printf(" --phase: (未指定,默认 all)\n")
|
||||
|
||||
cc: str = args.get_str("cc")
|
||||
if cc is not None:
|
||||
stdio.printf(" --cc: %s\n", cc)
|
||||
else:
|
||||
stdio.printf(" --cc: (未指定)\n")
|
||||
#if cc is not None:
|
||||
# stdio.printf(" --cc: %s\n", cc)
|
||||
#else:
|
||||
# stdio.printf(" --cc: (未指定)\n")
|
||||
|
||||
# 布尔参数
|
||||
_gb_clean: INT = args.get_bool("clean")
|
||||
if _gb_clean:
|
||||
stdio.printf(" --clean: True\n")
|
||||
else:
|
||||
stdio.printf(" --clean: False\n")
|
||||
#if _gb_clean:
|
||||
# stdio.printf(" --clean: True\n")
|
||||
#else:
|
||||
# stdio.printf(" --clean: False\n")
|
||||
|
||||
if args.get_bool("run"):
|
||||
stdio.printf(" --run: True\n")
|
||||
else:
|
||||
stdio.printf(" --run: False\n")
|
||||
#if args.get_bool("run"):
|
||||
# stdio.printf(" --run: True\n")
|
||||
#else:
|
||||
# stdio.printf(" --run: False\n")
|
||||
|
||||
if args.get_bool("rebuild-includes"):
|
||||
stdio.printf(" --rebuild-includes: True\n")
|
||||
else:
|
||||
stdio.printf(" --rebuild-includes: False\n")
|
||||
#if args.get_bool("rebuild-includes"):
|
||||
# stdio.printf(" --rebuild-includes: True\n")
|
||||
#else:
|
||||
# stdio.printf(" --rebuild-includes: False\n")
|
||||
|
||||
if args.get_bool("clear-cache"):
|
||||
stdio.printf(" --clear-cache: True\n")
|
||||
else:
|
||||
stdio.printf(" --clear-cache: False\n")
|
||||
#if args.get_bool("clear-cache"):
|
||||
# stdio.printf(" --clear-cache: True\n")
|
||||
#else:
|
||||
# stdio.printf(" --clear-cache: False\n")
|
||||
|
||||
stdio.printf("\n参数解析完成。\n")
|
||||
#stdio.printf("\n参数解析完成。\n")
|
||||
|
||||
if args.get_bool("version"): # 疑问,\n?
|
||||
stdio.printf("""Viper %s
|
||||
GVSDS(TM) SE Runtime Environment and Library %s
|
||||
Viper Frontend Compiler TransPyV %s\n\n""", VIPER_VERSION, RUNTIME_VERSION, TPV_VERSION)
|
||||
return 0
|
||||
|
||||
# ASan 模式:设置 BuildPipeline 全局标志(compile_ll_to_obj 先 opt 插桩,链接 asan 库)
|
||||
# includes 缓存用独立目录 .binary_asan 隔离 asan 插桩 obj,避免与非 asan obj 混链
|
||||
@@ -282,6 +279,15 @@ def main() -> int:
|
||||
BuildPipeline.set_asan_mode(0)
|
||||
Config.set_inc_bin_suffix(".binary")
|
||||
|
||||
# --nowarn-register:抑制"外部函数返回类型未登记"类 WARN 输出
|
||||
# (自举编译中大量出现刷屏,仅抑制打印,默认 i32 推断/标记重试逻辑保留)
|
||||
# 注意:argparse 的 dest 保留短横线("--nowarn-register" → "nowarn-register"),
|
||||
# 读取时必须用破折号 key,否则 get_bool 查不到 → 开关永不置位 → WARN 照打。
|
||||
if args.get_bool("nowarn-register"):
|
||||
VLogger.set_nowarn_register(1)
|
||||
if log is not None:
|
||||
log.info("--nowarn-register 已启用:抑制注册类 WARN 输出", "vlogger")
|
||||
|
||||
# 加载 project.vpj 配置
|
||||
proj_loaded: int = 0
|
||||
proj_path: str = project
|
||||
|
||||
Reference in new issue
Block a user