This commit is contained in:
2026-07-30 13:34:26 +08:00
parent a2cc28a6ab
commit f79c8ca643
43 changed files with 1690 additions and 1016 deletions

View File

@@ -1,28 +0,0 @@
"""
Auto-generated Python stub file from stdio.py
Module: stdio
"""
import t, c
def printf(fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
def puts(s: t.CConst | str) -> t.CInt | t.State: pass
def fputs(s: t.CConst | str, stream: bytes) -> t.CInt | t.State: pass
def fgets(buf: bytes, size: t.CInt, stream: bytes) -> bytes | t.State: pass
def fflush(stream: bytes) -> t.CInt | t.State: pass
stdin: t.CExtern | bytes
stdout: t.CExtern | bytes
stderr: t.CExtern | bytes

View File

@@ -1,20 +0,0 @@
"""
Auto-generated Python stub file from stdlib.py
Module: stdlib
"""
import c
from stdint import *
import t
def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
def free(p: t.CVoid | t.CPtr) -> t.State: pass
def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass

0
1.txt
View File

0
2.txt
View File

2
TODO
View File

@@ -34,3 +34,5 @@ __iter__ 期望 for a, b in __iter__
init_set 构造
不在乎编译器时间的大小优化(无关符号剔除)
给 linkedlist 库改成 node 库,或者拆分 linkedlist 库
TPV 的 typedef 名是硬编码的,后期尝试修正

Binary file not shown.

View File

@@ -282,8 +282,76 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
return 0
def _CollectObjFilesImpl(base_dir: str, bd_len: t.CSizeT,
out_buf: bytes, out_pos: t.CSizeT, out_size: t.CSizeT) -> t.CSizeT:
"""递归扫描 base_dir收集 .obj 文件路径到 out_buf返回新的 out_pos
支持切片子目录(如 dir/43/{sha1}.obj
"""
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
if find_data is None:
return out_pos
string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
pattern: bytes = _mbuddy.alloc(bd_len + 8)
if pattern is None:
return out_pos
viperlib.snprintf(pattern, bd_len + 8, "%s/*", base_dir)
handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data)
_mbuddy.free(pattern)
if handle == w32.win32base.INVALID_HANDLE_VALUE:
return out_pos
while True:
fname: str = find_data.cFileName
if fname is not None:
fname_len: t.CSizeT = string.strlen(fname)
if fname_len > 0:
# 跳过 . 和 ..
is_dot: int = 0
if fname_len == 1 and fname[0] == '.':
is_dot = 1
elif fname_len == 2 and fname[0] == '.' and fname[1] == '.':
is_dot = 1
if is_dot == 0:
attrs: ULONG = find_data.dwFileAttributes
is_dir: int = 0
if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
is_dir = 1
if is_dir != 0:
# 递归扫描子目录
sub_dir: bytes = _mbuddy.alloc(bd_len + fname_len + 2)
if sub_dir is not None:
viperlib.snprintf(sub_dir, bd_len + fname_len + 2, "%s/%s", base_dir, fname)
sub_len: t.CSizeT = string.strlen(sub_dir)
out_pos = _CollectObjFilesImpl(sub_dir, sub_len, out_buf, out_pos, out_size)
_mbuddy.free(sub_dir)
else:
# 检查是否是 .obj 文件
if fname_len > 4:
if fname[fname_len - 4] == '.' and fname[fname_len - 3] == 'o' and fname[fname_len - 2] == 'b' and fname[fname_len - 1] == 'j':
need: t.CSizeT = bd_len + 1 + fname_len + 2
if out_pos + need < out_size:
if out_pos > 0:
out_buf[out_pos] = ' '
out_pos += 1
viperlib.snprintf(out_buf + out_pos, need, "%s/%s", base_dir, fname)
out_pos += bd_len + 1 + fname_len
else:
break
if w32.win32file.FindNextFileA(handle, find_data) == 0:
break
w32.win32file.FindClose(handle)
return out_pos
def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT:
"""扫描 includes_binary_dir 目录,收集所有 .obj 文件路径到 out_buf
"""递归扫描 includes_binary_dir 目录,收集所有 .obj 文件路径到 out_buf
支持切片子目录(如 includes_binary_dir/43/{sha1}.obj
Args:
includes_binary_dir: includes.binary 目录路径
@@ -297,47 +365,8 @@ def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: t.CSiz
return 0
out_buf[0] = '\0'
out_pos: t.CSizeT = 0
# 构造搜索模式: dir/*.obj
dir_len: t.CSizeT = string.strlen(includes_binary_dir)
pattern: bytes = _mbuddy.alloc(dir_len + 8)
if pattern is None:
return 0
viperlib.snprintf(pattern, dir_len + 8, "%s/*.obj", includes_binary_dir)
# FindFirstFileA
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
if find_data is None:
return 0
string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data)
if handle == w32.win32base.INVALID_HANDLE_VALUE:
return 0
# 需要 win32base 的 INVALID_HANDLE_VALUE
while True:
fname: str = find_data.cFileName
if fname is not None:
fname_len: t.CSizeT = string.strlen(fname)
# 构造完整路径并追加到 out_buf
# 路径格式: "dir/fname "
need: t.CSizeT = dir_len + 1 + fname_len + 2
if out_pos + need < out_size:
if out_pos > 0:
out_buf[out_pos] = ' '
out_pos += 1
viperlib.snprintf(out_buf + out_pos, need, "%s/%s", includes_binary_dir, fname)
out_pos += dir_len + 1 + fname_len
else:
# 缓冲区不足,停止
break
if w32.win32file.FindNextFileA(handle, find_data) == 0:
break
w32.win32file.FindClose(handle)
out_pos: t.CSizeT = _CollectObjFilesImpl(includes_binary_dir, dir_len, out_buf, 0, out_size)
out_buf[out_pos] = '\0'
return out_pos
@@ -509,13 +538,23 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s",
linker_cmd, obj_paths, linker_output, linker_flags)
# 用 stdlib.system() 直接在控制台运行链接,输出直接显示
# 避免 subprocess 管道捕获丢失输出TransPyV 标准句柄可能无效)
sys_ret: int = stdlib.system(cmd)
if sys_ret != 0:
# 用 subprocess.run 捕获 clang++ 的 stdout/stderr 输出
# 之前用 stdlib.system() 无法捕获具体错误undefined reference 等),
# 导致 1.txt 中只看到"链接失败,返回码: 1"而看不到未解析符号
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
if result is None:
VLogger.error("subprocess.run 返回 None", "link")
return 1
if result.returncode != 0:
# 先用 stdio.printf 直接输出 clang++ 的完整错误输出(含 undefined reference
# 必须在 VLogger.error 之前输出,因为 VLogger.error 会调用 sys.exit(1) 终止进程
if result.stdout is not None:
stdio.printf("=== clang++ 链接错误输出 ===\n%s\n", result.stdout)
if result.stderr is not None:
stdio.printf("=== clang++ stderr ===\n%s\n", result.stderr)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", sys_ret, cmd)
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", result.returncode, cmd)
VLogger.error(fb, "link")
return 1
return 0

View File

@@ -176,6 +176,77 @@ def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int:
return 0
# ============================================================
# _init_global_array_from_list — 从列表字面量初始化全局数组
#
# 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。
# 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。
#
# Args:
# builder: IRBuilder
# pool: 编译器内存池
# mod: LLVMModule
# array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*
# list_node: ast.List 节点
# trans: Translator 对象
#
# Returns:
# 0 成功1 失败
# ============================================================
def _init_global_array_from_list(builder: llvmlite.IRBuilder | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
array_alloca: llvmlite.Value | t.CPtr,
list_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""从列表字面量初始化全局数组,为每个元素生成 GEP + store"""
if builder is None or array_alloca is None or list_node is None:
return 1
# 获取数组类型Pointee of [N x elem_ty]*
arr_ty: llvmlite.LLVMType | t.CPtr = None
if array_alloca.Ty is not None:
arr_ty = array_alloca.Ty.Pointee
if arr_ty is None:
return 1
# 匹配数组类型获取元素类型
elem_ty: llvmlite.LLVMType | t.CPtr = None
match arr_ty:
case llvmlite.LLVMType.Array(et, _):
elem_ty = et
if elem_ty is None:
return 1
# 获取列表元素
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
if lst is None or lst.elts is None:
return 1
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
elts_count: t.CSizeT = elts.__len__()
# 为每个元素生成 GEP + store
i: t.CSizeT = 0
while i < elts_count:
elem_node: ast.AST | t.CPtr = elts.get(i)
elem_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, elem_node, None, 0, trans)
if elem_val is not None:
idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i)
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, array_alloca, idx_val)
if elem_ptr is not None:
# 类型转换(如 i32 → i8 截断)
store_val: llvmlite.Value | t.CPtr = elem_val
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
store_val = HandlesExpr.coerce_to_type(
builder, elem_val, elem_ptr.Ty.Pointee)
llvmlite.build_store(builder, store_val, elem_ptr)
i += 1
return 0
@t.NoVTable
class AnnAssignHandle(HandlesBase.Mixin):
"""AnnAssign 语句处理器:继承 Mixin 获得 Trans 回指针"""
@@ -221,6 +292,11 @@ class AnnAssignHandle(HandlesBase.Mixin):
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
return 0
# 模块级全局变量已由 handle_module_level_var 注册到模块作用域,
# 不需要创建局部 alloca否则会导致局部变量遮蔽全局变量
if HandlesVar.lookup_module_var(self.Trans.SymTab, nm.id) is not None:
return 0
# 检查是否已存在
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
self.Trans.SymTab, nm.id)
@@ -350,6 +426,29 @@ class AnnAssignHandle(HandlesBase.Mixin):
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
return 0
# 模块级全局变量(由 handle_module_level_var 注册到模块作用域)
# 非函数内 global 声明,但变量已在模块作用域中(如模块级 t.CArray 初始化)
mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if mod_glob is not None:
if aa.value is not None:
# 列表字面量 → 逐元素 GEP + store 初始化数组
if aa.value.kind() == ast.ASTKind.List:
_init_global_array_from_list(
builder, pool, mod, mod_glob, aa.value, self.Trans)
else:
rhs_val_mg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aa.value,
None, 0, self.Trans)
if rhs_val_mg is not None:
target_ty_mg: llvmlite.LLVMType | t.CPtr = None
if mod_glob.Ty is not None:
target_ty_mg = mod_glob.Ty.Pointee
if target_ty_mg is not None:
rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg)
llvmlite.build_store(builder, rhs_val_mg, mod_glob)
return 0
# 普通局部变量
# 创建 alloca
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(

View File

@@ -15,6 +15,7 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.StubMerger as StubMerger
# ============================================================
@@ -62,23 +63,70 @@ 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:
# 增强错误信息:包含 sha1 + lineno + AST 节点类型,便于定位
# 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None and asgn.value is not None:
sha1: str = self.Trans.ModuleSha1
val_kind: int = asgn.value.kind()
val_line: t.CInt = asgn.value.lineno
# 通过 sha1 查找文件名(人类可读)
rel_path: str = None
if sha1 is not None:
viperlib.snprintf(fb, 1024,
"rhs_val is None [sha1=%s lineno=%d kind=%d]",
sha1, val_line, val_kind)
rel_path = StubMerger.LookupSha1RelPath(sha1)
# 根据 AST 节点类型提取详情
if val_kind == ast.ASTKind.Attribute:
at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value)
attr_nm: str = at_nv.attr
target_nm: str = "?"
if at_nv.value is not None:
if at_nv.value.kind() == ast.ASTKind.Name:
tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value)
target_nm = tn_nm.id
if rel_path is not None:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: %s:%d '%s.%s' 属性访问失败",
rel_path, val_line, target_nm, attr_nm)
else:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败",
sha1, val_line, target_nm, attr_nm)
elif val_kind == ast.ASTKind.Name:
nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value)
if rel_path is not None:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: %s:%d 变量 '%s' 未找到",
rel_path, val_line, nm_nv.id)
else:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到",
sha1, val_line, nm_nv.id)
elif val_kind == ast.ASTKind.Call:
cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value)
func_nm: str = "?"
if cl_nv.func is not None:
if cl_nv.func.kind() == ast.ASTKind.Name:
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func)
func_nm = fn_nm.id
if rel_path is not None:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None",
rel_path, val_line, func_nm)
else:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None",
sha1, val_line, func_nm)
else:
viperlib.snprintf(fb, 1024,
"rhs_val is None [lineno=%d kind=%d]",
val_line, val_kind)
if rel_path is not None:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: %s:%d [kind=%d]",
rel_path, val_line, val_kind)
else:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: sha1=%s:%d [kind=%d]",
sha1, val_line, val_kind)
VLogger.error(fb, "ASGN")
else:
VLogger.error("rhs_val is None", "ASGN")
VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN")
return 0
new_vars: int = 0

View File

@@ -1700,15 +1700,14 @@ _generic_class_nodes: list[ast.ClassDef | t.CPtr] | t.CPtr = None
_generic_class_sha1s: list[str] | t.CPtr = None
def _is_generic_class(cd: ast.ClassDef | t.CPtr) -> int:
"""检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否"""
if cd is None:
return 0
tp: list[str] | t.CPtr = cd.type_params
def _is_generic_class(tp: list[str] | t.CPtr) -> int:
"""检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否
接收 type_params 而非 cd避免 cd.type_params 属性访问
因跨模块类型推断失败返回 None。
"""
if tp is None:
return 0
if tp.__len__() == 0:
return 0
return 1
@@ -1721,29 +1720,37 @@ def _register_generic_template(pool: memhub.MemBuddy | t.CPtr,
_generic_class_names = list[str](pool, 8)
_generic_class_nodes = list[ast.ClassDef | t.CPtr](pool, 8)
_generic_class_sha1s = list[str](pool, 8)
# 检查是否已注册
cn: t.CSizeT = _generic_class_names.__len__()
# 用局部变量接收 global list触发类型推断避免 global 变量 __len__ 失败)
names_local: list[str] | t.CPtr = _generic_class_names
cn: t.CSizeT = names_local.__len__()
i: t.CSizeT
for i in range(cn):
nm: str = _generic_class_names.get(i)
nm: str = names_local.get(i)
if nm is not None and string.strcmp(nm, cd.name) == 0:
return
_generic_class_names.append(cd.name)
_generic_class_nodes.append(cd)
_generic_class_sha1s.append(module_sha1)
# 诊断日志:确认泛型模板注册
fb_rg: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_rg is not None:
viperlib.snprintf(fb_rg, 1024, "注册泛型模板: %s (module=%s)", cd.name, module_sha1)
VLogger.info(fb_rg, "SPEC")
def _find_generic_template(class_name: str) -> ast.ClassDef | t.CPtr:
"""查找泛型类模板,返回 ClassDef 节点或 None"""
if _generic_class_names is None or class_name is None:
return None
cn: t.CSizeT = _generic_class_names.__len__()
# 用局部变量接收 global list触发类型推断避免 global 变量 __len__ 失败)
names_local: list[str] | t.CPtr = _generic_class_names
nodes_local: list[ast.ClassDef | t.CPtr] | t.CPtr = _generic_class_nodes
cn: t.CSizeT = names_local.__len__()
i: t.CSizeT
for i in range(cn):
nm: str = _generic_class_names.get(i)
nm: str = names_local.get(i)
if nm is not None and string.strcmp(nm, class_name) == 0:
# 用局部变量接收 list.get() 结果,触发旧编译器 inttoptr 类型转换
node: ast.ClassDef | t.CPtr = _generic_class_nodes.get(i)
node: ast.ClassDef | t.CPtr = nodes_local.get(i)
return node
return None
@@ -1752,13 +1759,15 @@ def _find_generic_template_sha1(class_name: str) -> str:
"""查找泛型类模板的来源模块 SHA1未找到返回 None"""
if _generic_class_names is None or class_name is None:
return None
cn: t.CSizeT = _generic_class_names.__len__()
# 用局部变量接收 global list触发类型推断
names_local: list[str] | t.CPtr = _generic_class_names
sha1s_local: list[str] | t.CPtr = _generic_class_sha1s
cn: t.CSizeT = names_local.__len__()
i: t.CSizeT
for i in range(cn):
nm: str = _generic_class_names.get(i)
nm: str = names_local.get(i)
if nm is not None and string.strcmp(nm, class_name) == 0:
# 用局部变量接收 list.get() 结果,触发旧编译器 inttoptr 类型转换
sha1_val: str = _generic_class_sha1s.get(i)
sha1_val: str = sha1s_local.get(i)
return sha1_val
return None
@@ -2191,7 +2200,9 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
return _translate_renum_def(trans, cd)
# 泛型类:存储为模板,不发射 IR等实例化时特化
if _is_generic_class(cd) == 1:
# 用局部变量接收 cd.type_params触发类型推断
tp_val: list[str] | t.CPtr = cd.type_params
if _is_generic_class(tp_val) == 1:
_register_generic_template(pool, cd, trans.ModuleSha1)
return 0

View File

@@ -420,7 +420,14 @@ def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr,
# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb"
# ============================================================
def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""查找上下文中的 pool 变量,返回 alloca 或 None"""
"""查找上下文中的 pool 变量,返回 alloca 或 None
查找顺序: pool → _mbuddy → mbuddy → mb
兜底: 若都未找到,注册外部全局 @_mbuddy (i8*) 供函数内动态 list 创建使用。
注意: 模块级 t.CArray 初始化不走此路径(由 _init_global_array_from_list 处理),
此兜底仅用于函数内的动态 list 字面量(如 op=[...])。
@_mbuddy 由入口模块(如 Phase2.py定义并初始化其他模块以 external 引用。
"""
if trans is None:
return None
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool")
@@ -435,7 +442,32 @@ def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
alloca = HandlesVar.lookup_var(trans.SymTab, "mb")
if alloca is not None:
return alloca
return None
# 兜底: 创建外部全局 @_mbuddy 引用i8** 类型)
# 仅用于函数内动态 list 字面量,@_mbuddy 由入口模块定义并初始化
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if pool is None or trans.Module is None or trans.SymTab is None:
return None
# 先检查是否已注册到模块作用域(避免重复创建全局变量)
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, "_mbuddy")
if existing is not None:
return existing
# 创建 i8* 类型t.CVoid | t.CPtr = i8*
i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb)
# 创建外部全局 @_mbuddyexternal linkage无初始值
gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, "_mbuddy", i8_ptr_ty_fb)
if gv_ext is not None:
gv_ext.Linkage = "external"
llvmlite.module_add_global(trans.Module, gv_ext)
# 创建 Value 引用(@_mbuddy, 类型为 i8**
i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb)
ref_name_fb: t.CChar | t.CPtr = pool.alloc(16)
if ref_name_fb is not None:
string.strcpy(ref_name_fb, "@_mbuddy")
gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb)
# 注册到模块作用域,避免重复创建
HandlesVar.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb)
return gv_ref_fb
# ============================================================
@@ -1115,29 +1147,73 @@ def _build_source_path_from_sha1(sha1: str) -> str:
# ============================================================
def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
name: str,
from_imports: str) -> int:
"""跨模块查找 CDefine 常量,返回值或 -1未找到"""
if name is None or from_imports is None:
stdio.printf("[XMCD] FAIL name=%s reason=from_imports_is_none\n", name)
from_imports: str,
imported_modules: str = None) -> int:
"""跨模块查找 CDefine 常量,返回值或 -1未找到
查找顺序:
1. from_imports 精确匹配from X import NAME
2. from_imports star 回退from X import *
3. imported_modules 遍历import X当通过 import X 导入模块时,
模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用)
"""
if name is None:
return -1
if from_imports is None:
from_imports = ""
# 1. 从 from_imports 查找名称对应的模块名
# 先尝试精确匹配allow_star_fallback=0避免 CDefine 常量被 star import 误导
mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 0)
if mod_name_raw is None:
# 精确匹配失败:尝试 star import 回退
# CDefine 常量(如 INVALID_HANDLE_VALUE通过 from w32.win32base import * 导入,
# 不会作为精确条目出现在 from_imports 中,而是作为 *:w32.win32base 条目。
mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1)
if mod_name_raw is None:
stdio.printf("[XMCD] FAIL name=%s reason=lookup_from_import_returned_none\n", name)
# 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6
# 注意star fallback 可能返回错误模块(如 stdint常量实际不在其中
# 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules
if mod_name_raw is None:
# from_imports 完全没有匹配(精确和 star 都失败)
# 直接进入 imported_modules 遍历(步骤 9.6
if imported_modules is None:
return -1
stdio.printf("[XMCD] star_fallback name=%s mod=%s\n", name, mod_name_raw)
# 打印 from_imports 用于诊断精确匹配失败原因
fi_len: t.CSizeT = string.strlen(from_imports)
stdio.printf("[XMCD] from_imports (len=%d): %s\n", fi_len, from_imports)
else:
stdio.printf("[XMCD] exact_match name=%s mod=%s\n", name, mod_name_raw)
# 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历
# 设置 result_found=0 跳过步骤 3-9直接到 9.6
HandlesType.set_cdefine_found(0)
# 直接遍历 imported_modules
im_len: t.CSizeT = string.strlen(imported_modules)
im_ci: t.CSizeT = 0
while im_ci < im_len:
while im_ci < im_len and imported_modules[im_ci] == ' ':
im_ci += 1
if im_ci >= im_len:
break
im_start: t.CSizeT = im_ci
while im_ci < im_len and imported_modules[im_ci] != ' ':
im_ci += 1
im_end: t.CSizeT = im_ci
im_nlen: t.CSizeT = im_end - im_start
if im_nlen > 0 and im_nlen < 256:
im_buf: str = pool.alloc(im_nlen + 1)
if im_buf is not None:
mk: t.CSizeT = 0
while mk < im_nlen:
im_buf[mk] = imported_modules[im_start + mk]
mk += 1
im_buf[im_nlen] = '\0'
sub_fi: str = pool.alloc(im_nlen + 3)
if sub_fi is not None:
sub_fi[0] = '*'
sub_fi[1] = ':'
mk2: t.CSizeT = 0
while mk2 < im_nlen:
sub_fi[2 + mk2] = im_buf[mk2]
mk2 += 1
sub_fi[2 + im_nlen] = '\0'
sub_val: int = _lookup_cross_module_cdefine(pool, name, sub_fi, None)
if HandlesType.is_cdefine_found() != 0:
return sub_val
return -1
# 2. 复制模块名到新缓冲区lookup_from_import 返回的是内部指针)
# 截断于空格、null、或 ':'(别名格式的分隔符)
@@ -1161,7 +1237,6 @@ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
if sha1 is None:
sha1 = HandlesExprCall._lookup_module_sha1_suffix(base_mod)
if sha1 is None:
stdio.printf("[XMCD] FAIL name=%s base_mod=%s reason=sha1_not_found\n", name, base_mod)
return -1
# 5. 获取 temp_dir
@@ -1529,6 +1604,45 @@ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
stdlib.free(pyi_buf)
# 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历
# 当 `from stdint import *` 导致 star fallback 返回 stdint但目标常量
# (如 SHARE_READ实际在 `import w32.fileio` 导入的模块中时,
# 需要遍历 imported_modules 逐个查找
if result_found == 0 and imported_modules is not None:
im2_len: t.CSizeT = string.strlen(imported_modules)
im2_ci: t.CSizeT = 0
while im2_ci < im2_len and result_found == 0:
while im2_ci < im2_len and imported_modules[im2_ci] == ' ':
im2_ci += 1
if im2_ci >= im2_len:
break
im2_start: t.CSizeT = im2_ci
while im2_ci < im2_len and imported_modules[im2_ci] != ' ':
im2_ci += 1
im2_end: t.CSizeT = im2_ci
im2_nlen: t.CSizeT = im2_end - im2_start
if im2_nlen > 0 and im2_nlen < 256:
im2_buf: str = pool.alloc(im2_nlen + 1)
if im2_buf is not None:
mk3: t.CSizeT = 0
while mk3 < im2_nlen:
im2_buf[mk3] = imported_modules[im2_start + mk3]
mk3 += 1
im2_buf[im2_nlen] = '\0'
sub_fi2: str = pool.alloc(im2_nlen + 3)
if sub_fi2 is not None:
sub_fi2[0] = '*'
sub_fi2[1] = ':'
mk4: t.CSizeT = 0
while mk4 < im2_nlen:
sub_fi2[2 + mk4] = im2_buf[mk4]
mk4 += 1
sub_fi2[2 + im2_nlen] = '\0'
sub_val2: int = _lookup_cross_module_cdefine(pool, name, sub_fi2, None)
if HandlesType.is_cdefine_found() != 0:
result_val = sub_val2
result_found = 1
# 10. 缓存到当前模块的 CDefine 表中
if result_found != 0:
HandlesType.register_cdefine_constant(pool, name, result_val)
@@ -1592,8 +1706,9 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr,
# 仅对符合 CDefine 命名约定ALL_CAPS的名字触发跨模块查找
# 避免对普通变量名mb/name/ptr/pool/self 等)误触发,造成严重性能损耗
if _is_cdefine_name_pattern(nm_id) != 0:
if trans is not None and trans._from_imports is not None:
cdef_val = _lookup_cross_module_cdefine(pool, nm_id, trans._from_imports)
if trans is not None:
cdef_val = _lookup_cross_module_cdefine(
pool, nm_id, trans._from_imports, trans._imported_modules)
if HandlesType.is_cdefine_found() != 0:
return llvmlite.const_int32(pool, cdef_val)
@@ -2121,6 +2236,92 @@ def make_global_ref(pool: memhub.MemBuddy | t.CPtr,
# ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退)
# 返回: Value 指针 (类型为 ty*),未识别为模块属性返回 None
# ============================================================
def _is_t_type_object_name(name: str) -> int:
"""检查 name 是否是 t.py 中的类型对象名CPtr/CInt/CDouble 等)
这些类型对象在运行时作为全局变量 @CPtr/@CInt 等被引用,
但 t.py 不被编译,需要在使用处生成带 null 初值的定义。
"""
if name is None:
return 0
# t.py 中的类型对象名PascalCase首字母大写
if string.strcmp(name, "CPtr") == 0:
return 1
if string.strcmp(name, "CInt") == 0:
return 1
if string.strcmp(name, "CChar") == 0:
return 1
if string.strcmp(name, "CShort") == 0:
return 1
if string.strcmp(name, "CLong") == 0:
return 1
if string.strcmp(name, "CLongLong") == 0:
return 1
if string.strcmp(name, "CDouble") == 0:
return 1
if string.strcmp(name, "CFloat") == 0:
return 1
if string.strcmp(name, "CBool") == 0:
return 1
if string.strcmp(name, "CVoid") == 0:
return 1
if string.strcmp(name, "CInt8T") == 0:
return 1
if string.strcmp(name, "CInt16T") == 0:
return 1
if string.strcmp(name, "CInt32T") == 0:
return 1
if string.strcmp(name, "CInt64T") == 0:
return 1
if string.strcmp(name, "CUInt8T") == 0:
return 1
if string.strcmp(name, "CUInt16T") == 0:
return 1
if string.strcmp(name, "CUInt32T") == 0:
return 1
if string.strcmp(name, "CUInt64T") == 0:
return 1
if string.strcmp(name, "CUnsigned") == 0:
return 1
if string.strcmp(name, "CUnsignedInt") == 0:
return 1
if string.strcmp(name, "CUnsignedChar") == 0:
return 1
if string.strcmp(name, "CUnsignedShort") == 0:
return 1
if string.strcmp(name, "CUnsignedLong") == 0:
return 1
if string.strcmp(name, "CUnsignedLongLong") == 0:
return 1
if string.strcmp(name, "CSizeT") == 0:
return 1
if string.strcmp(name, "CIntPtrT") == 0:
return 1
if string.strcmp(name, "CUIntPtrT") == 0:
return 1
if string.strcmp(name, "CPtrDiffT") == 0:
return 1
if string.strcmp(name, "CType") == 0:
return 1
if string.strcmp(name, "CDefine") == 0:
return 1
if string.strcmp(name, "CStatic") == 0:
return 1
if string.strcmp(name, "CExport") == 0:
return 1
if string.strcmp(name, "CArray") == 0:
return 1
if string.strcmp(name, "CTypedef") == 0:
return 1
if string.strcmp(name, "CNoVTable") == 0:
return 1
if string.strcmp(name, "CNeedPtr") == 0:
return 1
if string.strcmp(name, "CAutoPtr") == 0:
return 1
return 0
def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
trans: HT.Translator | t.CPtr,
@@ -2150,10 +2351,33 @@ def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr,
use_ty = llvmlite.Int8(pool)
# 确保 use_ty 中的跨模块结构体类型有 opaque 声明
llvmlite.module_ensure_opaque_for_type(mod, pool, use_ty)
# 特殊处理: t.py 中的类型对象CPtr/CInt/CDouble 等)
# t.py 不被编译,但这些类型对象在运行时被引用(如 va_arg(ap, t.CPtr))。
# 创建带 null 初值的 linkonce_odr 全局变量定义,避免链接时 undefined reference。
# LLVM 22+ 不允许 external linkage 全局变量带初值,使用 linkonce_odr 替代。
is_t_type_obj: int = 0
if string.strcmp(mod_nm.id, "t") == 0:
is_t_type_obj = _is_t_type_object_name(at.attr)
ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, at.attr, use_ty)
if ext_gv is not None:
ext_gv.Linkage = "external"
ext_gv.Initializer = None
if is_t_type_obj != 0:
# t.CPtr 等类型对象: 创建带 null 初值的定义linkonce_odr
ext_gv.Linkage = "linkonce_odr"
# i8* null 的初值文本
null_init: bytes = pool.alloc(8)
if null_init is not None:
null_init[0] = 'n'
null_init[1] = 'u'
null_init[2] = 'l'
null_init[3] = 'l'
null_init[4] = '\0'
ext_gv.Initializer = null_init
else:
ext_gv.Initializer = None
else:
# 普通模块属性: external 声明(由其他模块提供定义)
ext_gv.Linkage = "external"
ext_gv.Initializer = None
llvmlite.module_add_global(mod, ext_gv)
return make_global_ref(pool, at.attr, use_ty)
@@ -2302,6 +2526,24 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
is_submod = 1
if is_submod != 0:
return None # 是子模块,交给嵌套属性访问路径
# 特殊处理: t.ASM_DESCR 不是 CDefine是内联汇编约束命名空间
# t.ASM_DESCR.XXX 由 HandlesExprCall 的 _asm_resolve_constraint 处理
# 此处返回 None让上层嵌套属性访问路径处理
if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0:
return None
# CDefine 未找到且属性名符合 ALL_CAPS 约定: 报 FATAL 错误
# 不再创建未定义的外部全局变量引用(否则 llc 报 "use of undefined value"
if _is_cdefine_name_pattern(at.attr) != 0:
err_buf_sma: str = pool.alloc(256)
if err_buf_sma is not None:
cur_sha1_sma: str = "(unknown)"
if trans is not None and trans.ModuleSha1 is not None:
cur_sha1_sma = trans.ModuleSha1
viperlib.snprintf(err_buf_sma, 256,
"[CD] FATAL: Module attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n",
nm_ma.id, at.attr, cur_sha1_sma)
VLogger.error(err_buf_sma, "CD")
return None
# 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针)
i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
mod_gv_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global(
@@ -2347,14 +2589,21 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
cdef_val_nested = _lookup_cross_module_cdefine(pool, at.attr, tmp_fi)
if HandlesType.is_cdefine_found() != 0:
return llvmlite.const_int32(pool, cdef_val_nested)
# CDefine 未找到: 创建前向引用 (CDefine 通常是 i32)
i32_ty_fwd: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
gv_ref_fwd: llvmlite.Value | t.CPtr = make_global_ref(
pool, at.attr, i32_ty_fwd)
if gv_ref_fwd is not None and gv_ref_fwd.Ty is not None:
load_ty_fwd: llvmlite.LLVMType | t.CPtr = gv_ref_fwd.Ty.Pointee
if load_ty_fwd is not None:
return llvmlite.build_load(builder, load_ty_fwd, gv_ref_fwd)
# CDefine 未找到: 报 FATAL 错误(不再创建未定义的全局变量引用)
# 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义,
# 导致 llc 报 "use of undefined value" 错误。
# 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。
if _is_cdefine_name_pattern(at.attr) != 0:
err_buf_ma: str = pool.alloc(256)
if err_buf_ma is not None:
cur_sha1_ma: str = "(unknown)"
if trans is not None and trans.ModuleSha1 is not None:
cur_sha1_ma = trans.ModuleSha1
viperlib.snprintf(err_buf_ma, 256,
"[CD] FATAL: Nested attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n",
qual_buf, at.attr, cur_sha1_ma)
VLogger.error(err_buf_ma, "CD")
return None
# 对于 Name 类型的 obj直接查找 alloca不 load 结构体)
obj_ptr: llvmlite.Value | t.CPtr = None
@@ -2401,7 +2650,7 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx)
if alias_ptr is not None:
return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr)
# 回退: 类型指针比较失败时,通过 AnnotClassName 按类名查找
# 按需过滤: struct_ty 为 i8简化联合类型时,通过 AnnotClassName 按类名查找
# 传递 SHA1 以区分跨模块同名类
if field_info is None:
if at.value.kind() == ast.ASTKind.Name and trans is not None:
@@ -2413,7 +2662,7 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
cur_sha1: str = trans.ModuleSha1
field_info = HandlesStruct.lookup_field_by_class(
var_entry.AnnotClassName, at.attr, cur_sha1)
# 回退 1 成功bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
# 按需过滤成功bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
# 原始 struct_ty 可能是 i8X|t.CPtr 简化为 Ptr(i8)
# 需用实际结构体类型做 GEP否则 GEP i8 失败
if field_info is not None:
@@ -2427,33 +2676,11 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
if casted_ptr is not None:
obj_ptr = casted_ptr
struct_ty = annot_se.Ty
# 回退 1 更新 struct_ty 后,需重新确保
# 按需过滤更新 struct_ty 后,需重新确保
# 注解类型结构体定义在当前模块可用
# (原始 struct_ty 可能是 i8ensure 无效)
HandlesStruct.ensure_struct_def_in_module(
pool, mod, annot_se.Ty)
# 回退 2: 子类搜索 — 注解类型是基类但实际值是派生类
# 如 node: AST | t.CPtr = If(...),访问 node.orelse
if field_info is None:
sub_entry: HandlesStruct.StructEntry | t.CPtr = \
HandlesStruct.find_subclass_with_field(
var_entry.AnnotClassName, at.attr)
if sub_entry is not None and sub_entry.Ty is not None:
sub_field: HandlesStruct.FieldEntry | t.CPtr = \
HandlesStruct.lookup_field(sub_entry.Ty, at.attr)
if sub_field is not None:
sub_ptr_ty: llvmlite.LLVMType | t.CPtr = \
llvmlite.Ptr(pool, sub_entry.Ty)
casted_ptr: llvmlite.Value | t.CPtr = \
llvmlite.build_bitcast(builder, obj_ptr, sub_ptr_ty)
if casted_ptr is not None:
sub_field_ptr: llvmlite.Value | t.CPtr = \
llvmlite.build_gep_struct(
builder, sub_entry.Ty, sub_field.Ty,
casted_ptr, sub_field.Index)
if sub_field_ptr is not None:
return llvmlite.build_load(
builder, sub_field.Ty, sub_field_ptr)
if field_info is not None:
field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty
# 联合体bitcast obj_ptr 到 field_ty* 后 load
@@ -2483,6 +2710,28 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty)
return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty)
return loaded_val
# fast-fail: 字段未找到,打印诊断信息
if trans is not None:
diag_annot: str = None
diag_var_nm: str = None
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
diag_var_nm = dnm.id
if dnm.id is not None:
dve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, dnm.id)
if dve is not None:
diag_annot = dve.AnnotClassName
fb_attr: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_attr is not None:
viperlib.snprintf(fb_attr, 1024,
"属性访问失败: .%s (var=%s annot=%s sha1=%s:%d)",
at.attr,
diag_var_nm if diag_var_nm is not None else "?",
diag_annot if diag_annot is not None else "None",
trans.ModuleSha1 if trans.ModuleSha1 is not None else "?",
at.lineno if at.lineno is not None else 0)
VLogger.error(fb_attr, "ATTR")
return None
case _:
return None
@@ -2620,6 +2869,15 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
if obj_ptr is None and at.value.kind() == ast.ASTKind.Name and trans is not None:
nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if nm_wma.id is not None:
# CDefine 常量不可写: 报 FATAL 错误,不创建未定义全局
if _is_cdefine_name_pattern(at.attr) != 0:
err_buf_wma: str = pool.alloc(256)
if err_buf_wma is not None:
viperlib.snprintf(err_buf_wma, 256,
"[CD] FATAL: Cannot assign to CDefine constant '%s.%s'\n",
nm_wma.id, at.attr)
VLogger.error(err_buf_wma, "CD")
return None
# 使用 i8* 作为类型提示 (模块级变量通常存储指针)
i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
wma_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global(
@@ -2645,7 +2903,7 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
struct_ty, at.attr)
# 回退 1: 类型指针比较失败时,通过 AnnotClassName 按类名查找
# 按需过滤: struct_ty 为 i8简化联合类型时,通过 AnnotClassName 按类名查找
# 传递 SHA1 以区分跨模块同名类
if field_info is None:
if at.value.kind() == ast.ASTKind.Name and trans is not None:
@@ -2659,7 +2917,7 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
cur_sha1 = trans.ModuleSha1
field_info = HandlesStruct.lookup_field_by_class(
var_entry.AnnotClassName, at.attr, cur_sha1)
# 回退 1 成功bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
# 按需过滤成功bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
# 原始 struct_ty 可能是 i8X|t.CPtr 简化为 Ptr(i8)
# 需用实际结构体类型做 GEP否则 GEP i8 失败
if field_info is not None:
@@ -2673,32 +2931,10 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
if casted_ptr is not None:
obj_ptr = casted_ptr
struct_ty = annot_se.Ty
# 回退 1 更新 struct_ty 后,需重新确保
# 按需过滤更新 struct_ty 后,需重新确保
# 注解类型结构体定义在当前模块可用
HandlesStruct.ensure_struct_def_in_module(
pool, mod, annot_se.Ty)
# 回退 2: 子类搜索 — 注解类型是基类但实际值是派生类
# 如 node: AST | t.CPtr = If(...),访问 node.orelse
# orelse 在 If 上不在 AST 上,需搜索 AST 的子类
if field_info is None:
sub_entry: HandlesStruct.StructEntry | t.CPtr = \
HandlesStruct.find_subclass_with_field(
var_entry.AnnotClassName, at.attr)
if sub_entry is not None and sub_entry.Ty is not None:
sub_field: HandlesStruct.FieldEntry | t.CPtr = \
HandlesStruct.lookup_field(sub_entry.Ty, at.attr)
if sub_field is not None:
sub_ptr_ty: llvmlite.LLVMType | t.CPtr = \
llvmlite.Ptr(pool, sub_entry.Ty)
casted_ptr: llvmlite.Value | t.CPtr = \
llvmlite.build_bitcast(builder, obj_ptr, sub_ptr_ty)
if casted_ptr is not None:
# 确保子类结构体定义在当前模块可用
HandlesStruct.ensure_struct_def_in_module(
pool, mod, sub_entry.Ty)
return llvmlite.build_gep_struct(
builder, sub_entry.Ty, sub_field.Ty,
casted_ptr, sub_field.Index)
if field_info is not None:
# 联合体bitcast obj_ptr 到 field_ty*(字段指针用于 store
if HandlesStruct.is_union_by_type(struct_ty) == 1:
@@ -2707,6 +2943,28 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
# 普通结构体GEP 获取字段指针
return llvmlite.build_gep_struct(
builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index)
# fast-fail: 字段未找到,打印诊断信息
if trans is not None:
diag_annot_g: str = None
diag_var_nm_g: str = None
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
dnm_g: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
diag_var_nm_g = dnm_g.id
if dnm_g.id is not None:
dve_g: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, dnm_g.id)
if dve_g is not None:
diag_annot_g = dve_g.AnnotClassName
fb_attr_g: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_attr_g is not None:
viperlib.snprintf(fb_attr_g, 1024,
"属性写入失败: .%s (var=%s annot=%s sha1=%s:%d)",
at.attr,
diag_var_nm_g if diag_var_nm_g is not None else "?",
diag_annot_g if diag_annot_g is not None else "None",
trans.ModuleSha1 if trans.ModuleSha1 is not None else "?",
at.lineno if at.lineno is not None else 0)
VLogger.error(fb_attr_g, "ATTR")
return None
case _:
return None

View File

@@ -3763,6 +3763,28 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
if cargs is not None:
can = cargs.__len__()
# 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32
# 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x)
# 单参数str(val) → bitcast val to i8*
# int(val) → trunc/sext val to i32
if func_name is not None and can == 1:
if string.strcmp(func_name, "str") == 0 or string.strcmp(func_name, "bytes") == 0:
# str(x) / bytes(x) → i8* (bitcast)
cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
if cast_arg is not None:
i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
return _translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin)
return None
elif string.strcmp(func_name, "int") == 0:
# int(x) → i32
cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
if cast_arg_int is not None:
i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
return _translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin)
return None
# 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等
# 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用)
# 支持:
@@ -3907,11 +3929,6 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
# 模块属性前向引用回退为 i32)GEP base 会是 i32 而非指针,
# 导致 llc 报错 "base of getelementptr must be a pointer"
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
# 诊断: 输出节点类型信息帮助定位根本原因
len_node_kind: int = len_at.value.kind()
stdio.printf(
"[LEN-DIAG] __len__ on non-ptr (kind=%d), fallback to 0\n",
len_node_kind)
return llvmlite.const_int64(pool, 0)
i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
# 注意: 必须用 const_int64 而非 ConstInt(...,"0")

View File

@@ -143,12 +143,26 @@ class ForHandle(HandlesBase.Mixin):
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 5. 存储初始值 (类型对齐: start_val 可能是 i64需截断到 i32)
# 获取循环变量的实际元素类型alloca 是指针类型,需解引用 Pointee
# 当循环变量已声明为 i64如 t.CSizeT使用 i64 而非硬编码 i32
# 避免 load i32, i64* / store i32, i64* 类型不匹配
loop_var_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if var_alloca is not None and var_alloca.Ty is not None:
match var_alloca.Ty:
case llvmlite.LLVMType.Ptr(pointee_ty):
if pointee_ty is not None:
loop_var_ty = pointee_ty
loop_var_bits: int = HandlesExpr.get_llvm_type_bits(loop_var_ty)
# 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64需对齐到 loop_var_ty)
init_val: llvmlite.Value | t.CPtr = start_val
if start_val is not None and start_val.Ty is not None:
start_bits: int = HandlesExpr.get_llvm_type_bits(start_val.Ty)
if start_bits != 0 and start_bits != 32:
init_val = llvmlite.build_trunc(builder, start_val, i32_ty)
if start_bits != 0 and start_bits != loop_var_bits:
if start_bits < loop_var_bits:
init_val = llvmlite.build_sext(builder, start_val, loop_var_ty)
else:
init_val = llvmlite.build_trunc(builder, start_val, loop_var_ty)
llvmlite.build_store(builder, init_val, var_alloca)
# 6. 创建基本块: cond / body / incr / end使用 trans._label_counter不与 SSA 名共享)
@@ -173,7 +187,7 @@ class ForHandle(HandlesBase.Mixin):
# 8. cond 块: load i, icmp slt i, stop, cond_br body/end
llvmlite.position_at_end(builder, cond_bb)
cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, var_alloca)
cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca)
# 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型
cmp_lhs: llvmlite.Value | t.CPtr = cur_i
cmp_rhs: llvmlite.Value | t.CPtr = stop_val
@@ -184,7 +198,7 @@ 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, i32_ty)
cmp_rhs = llvmlite.build_trunc(builder, stop_val, loop_var_ty)
cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_SLT, cmp_lhs, cmp_rhs)
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
@@ -215,17 +229,17 @@ class ForHandle(HandlesBase.Mixin):
# 10. incr 块: i = i + step, 跳回 cond
llvmlite.position_at_end(builder, incr_bb)
cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, var_alloca)
# 类型对齐: step_val 可能是 i64需截断到 i32 与 cur_i2 类型一致
cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca)
# 类型对齐: step_val 可能是 i32/i64需对齐到 loop_var_ty 与 cur_i2 类型一致
incr_step: llvmlite.Value | t.CPtr = step_val
if step_val is not None and step_val.Ty is not None:
step_bits: int = HandlesExpr.get_llvm_type_bits(step_val.Ty)
cur2_bits: int = HandlesExpr.get_llvm_type_bits(cur_i2.Ty)
if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits:
if step_bits > cur2_bits:
incr_step = llvmlite.build_trunc(builder, step_val, i32_ty)
incr_step = llvmlite.build_trunc(builder, step_val, loop_var_ty)
else:
incr_step = llvmlite.build_sext(builder, step_val, i32_ty)
incr_step = llvmlite.build_sext(builder, step_val, loop_var_ty)
next_i: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step)
llvmlite.build_store(builder, next_i, var_alloca)
llvmlite.build_br(builder, cond_bb)

View File

@@ -559,21 +559,6 @@ class ImportsHandle(HandlesBase.Mixin):
resolved: str = _resolve_relative_module(
self.Trans.Pool, self.Trans.CurrentPackage,
impf.level, impf.module)
# [IFD] 诊断 from-import 名称处理
mod_dbg: str = "(null)"
if impf.module is not None:
mod_dbg = impf.module
pkg_dbg: str = "(null)"
if self.Trans.CurrentPackage is not None:
pkg_dbg = self.Trans.CurrentPackage
res_dbg: str = "(null)"
if resolved is not None:
res_dbg = resolved
names_dbg: t.CSizeT = 0
if impf.names is not None:
names_dbg = impf.names.__len__()
stdio.printf("[IFD] level=%d module=%s pkg=%s resolved=%s names=%d\n",
impf.level, mod_dbg, pkg_dbg, res_dbg, names_dbg)
if resolved is not None:
names: list[ast.AST | t.CPtr] | t.CPtr = impf.names
if names is not None:

View File

@@ -129,11 +129,136 @@ def translate_children(trans: HT.Translator | t.CPtr,
return added_total
# ============================================================
# _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器
#
# 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...]
# 用于模块级 t.CArray 列表字面量初始化(不依赖 builder直接生成常量初始化器
# ============================================================
def _build_array_initializer_text(pool: memhub.MemBuddy | t.CPtr,
var_ty: llvmlite.LLVMType | t.CPtr,
list_node: ast.List | t.CPtr) -> str:
"""从 AST List 节点生成 LLVM IR 数组初始化器文本None 失败"""
if var_ty is None or list_node is None:
return None
# 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型
# (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr
ln: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
if ln is None:
return None
# 从 var_ty 提取数组元素类型和数量
elem_ty: llvmlite.LLVMType | t.CPtr = None
arr_count: t.CInt = 0
match var_ty:
case llvmlite.LLVMType.Array(et, cnt):
elem_ty = et
arr_count = cnt
if elem_ty is None or arr_count <= 0:
return None
# 确定元素类型的 IR 表示
elem_ir_ty: str = "i8"
match elem_ty:
case llvmlite.LLVMType.Int(bits):
if bits == 8:
elem_ir_ty = "i8"
elif bits == 16:
elem_ir_ty = "i16"
elif bits == 32:
elem_ir_ty = "i32"
elif bits == 64:
elem_ir_ty = "i64"
# 获取列表元素(通过 ln.elts 而非 list_node.elts确保类型正确识别
elts: list[ast.AST | t.CPtr] | t.CPtr = ln.elts
if elts is None:
return None
elts_count: t.CSizeT = elts.__len__()
# 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符
buf_size: t.CSizeT = 64 + elts_count * 32
buf: t.CChar | t.CPtr = pool.alloc(buf_size)
if buf is None:
return None
# 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表)
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
pos: t.CSizeT = t.CSizeT(written)
# 逐个元素写入
i: t.CSizeT = 0
while i < elts_count:
elem_node: ast.AST | t.CPtr = elts.get(i)
# 直接从 Constant 节点提取 int_val避免 extract_cdefine_int_value 的 t.CInt 截断)
elem_val: t.CInt64T = 0
if elem_node is not None:
ek: int = elem_node.kind()
if ek == ast.ASTKind.Constant:
ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node)
if ec is not None and ec.const_kind == ast.CONST_INT:
elem_val = ec.int_val
elif ek == ast.ASTKind.UnaryOp:
# 负数: UnaryOp(USub, Constant)
elem_val = HandlesAnnAssign.extract_cdefine_int_value(elem_node)
if i > 0:
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
pos += t.CSizeT(written)
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val)
pos += t.CSizeT(written)
i += 1
# 写入后缀 "]"
viperlib.snprintf(buf + pos, buf_size - pos, "]")
return buf
# ============================================================
# _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量
#
# 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00"
# 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0)
# 用于 b64_tab: t.CArray[t.CChar, None] = "ABC..." 等字符串初始化指针类型
# ============================================================
def _build_string_ptr_initializer(pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
var_name: str,
str_val: str) -> str:
"""为字符串字面量创建内部常量全局并返回 GEP 初始化器文本None 失败"""
if str_val is None or var_name is None:
return None
# 构造内部字符串常量名称: .str.{var_name}
str_name_buf: t.CChar | t.CPtr = pool.alloc(64)
if str_name_buf is None:
return None
viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name)
# 调用 llvmlite.create_global_string 创建字符串常量全局
str_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_string(
pool, mod, str_name_buf, str_val)
if str_gv is None:
return None
# 生成 GEP 初始化器文本
str_len: t.CSizeT = string.strlen(str_val)
init_buf: t.CChar | t.CPtr = pool.alloc(128)
if init_buf is None:
return None
viperlib.snprintf(init_buf, 128,
"getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)",
str_len + 1, str_len + 1, str_name_buf)
return init_buf
# ============================================================
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
#
# 当用户已定义 main无 wrapper main builder模块级
# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域
# 支持整数、列表字面量、字符串字面量初始值
# ============================================================
def handle_module_level_var(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
@@ -163,7 +288,9 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
var_name: str = None
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
init_val: t.CInt64T = 0
has_init: int = 0
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str
init_str_val: str = None
init_list_node: ast.List | t.CPtr = None
if k == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
@@ -179,12 +306,20 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
if resolved is not None:
var_ty = resolved
# 解析初始值
if aa.value is not None and aa.value.kind() == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
if cn.const_kind == ast.CONST_INT:
init_val = cn.int_val
has_init = 1
# 解析初始值(支持整数、列表字面量、字符串字面量)
if aa.value is not None:
val_kind: int = aa.value.kind()
if val_kind == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
if cn.const_kind == ast.CONST_INT:
init_val = cn.int_val
init_kind = 1
elif cn.const_kind == ast.CONST_STR:
init_str_val = cn.str_val
init_kind = 3
elif val_kind == ast.ASTKind.List:
init_list_node = (ast.List | t.CPtr)(aa.value)
init_kind = 2
elif k == ast.ASTKind.Assign:
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
if asgn is None or asgn.targets is None:
@@ -197,11 +332,19 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
return 0
nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0)
var_name = nm2.id
if asgn.value is not None and asgn.value.kind() == ast.ASTKind.Constant:
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value)
if cn2.const_kind == ast.CONST_INT:
init_val = cn2.int_val
has_init = 1
if asgn.value is not None:
val_kind2: int = asgn.value.kind()
if val_kind2 == ast.ASTKind.Constant:
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value)
if cn2.const_kind == ast.CONST_INT:
init_val = cn2.int_val
init_kind = 1
elif cn2.const_kind == ast.CONST_STR:
init_str_val = cn2.str_val
init_kind = 3
elif val_kind2 == ast.ASTKind.List:
init_list_node = (ast.List | t.CPtr)(asgn.value)
init_kind = 2
if var_name is None:
return 0
@@ -225,11 +368,26 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
# 设置初始值(有初始值时清除 external linkage因为 LLVM 22+ 不允许 external global 带初始值)
gv.Linkage = None
if has_init != 0:
if init_kind == 1:
# 整数初始值
init_buf: t.CChar | t.CPtr = pool.alloc(48)
if init_buf is not None:
viperlib.snprintf(init_buf, 48, "%lld", init_val)
gv.Initializer = init_buf
elif init_kind == 2:
# 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...]
arr_init: str = _build_array_initializer_text(pool, var_ty, init_list_node)
if arr_init is not None:
gv.Initializer = arr_init
else:
gv.Initializer = "zeroinitializer"
elif init_kind == 3:
# 字符串字面量 → 创建字符串常量全局 + GEP 引用
str_init: str = _build_string_ptr_initializer(pool, mod, var_name, init_str_val)
if str_init is not None:
gv.Initializer = str_init
else:
gv.Initializer = "zeroinitializer"
else:
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer
# 整数/聚合类型也兼容 zeroinitializer避免 "integer constant must have integer type"

View File

@@ -2,6 +2,7 @@ import t, c
from stdint import *
import memhub
import string
import stdlib
import llvmlite
import stdio
import ast
@@ -521,10 +522,28 @@ def lookup_field_by_class(class_name: str,
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
entry = find_struct(class_name)
if entry is None:
# 诊断:遍历打印所有已注册结构体名,确认目标类是否在注册表中
for diag_i in range(_struct_count):
diag_entry: StructEntry | t.CPtr = _get_struct_entry(diag_i)
# 诊断:目标类未注册
fb_lfbc: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_lfbc is not None:
viperlib.snprintf(fb_lfbc, 1024,
"lookup_field_by_class: 类 '%s' 未注册 (struct_count=%d)",
class_name, _struct_count)
VLogger.error(fb_lfbc, "STRUCT")
return None
# 诊断:找到结构体但字段未找到,打印字段表
fb_fields: t.CChar | t.CPtr = 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)
VLogger.error(fb_fields, "STRUCT")
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
fb_fn: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_fn is not None:
viperlib.snprintf(fb_fn, 1024, " 字段[%d]: %s", fi, fe.Name)
VLogger.error(fb_fn, "STRUCT")
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
@@ -534,45 +553,6 @@ def lookup_field_by_class(class_name: str,
return None
# ============================================================
# find_subclass_with_field — 在基类的所有子类中搜索包含指定字段的结构体
#
# 用于处理 "注解类型是基类但实际值是派生类" 的场景:
# node: AST | t.CPtr = If(...)
# node.orelse = orelse ← orelse 在 If 上,不在 AST 上
#
# 遍历所有已注册结构体,通过 ParentName 链检查继承关系,
# 返回第一个包含 field_name 的子类 StructEntry。
# ============================================================
def find_subclass_with_field(base_class_name: str,
field_name: str) -> StructEntry | t.CPtr:
"""在 base_class_name 的所有子类中搜索包含 field_name 的结构体
返回第一个找到的 StructEntry包含正确的 TyNone=未找到
"""
if base_class_name is None or field_name is None:
return None
sc_i: int
for sc_i in range(_struct_count):
sc_entry: StructEntry | t.CPtr = _get_struct_entry(sc_i)
if sc_entry is None or sc_entry.Name is None:
continue
# 检查 sc_entry 是否是 base_class_name 的子类(传递性)
cur_parent: str = get_parent_name(sc_entry.Name)
while cur_parent is not None:
if string.strcmp(cur_parent, base_class_name) == 0:
# 是子类,检查是否有该字段
sc_fi: int
for sc_fi in range(sc_entry.FieldCount):
sc_fe: FieldEntry | t.CPtr = _get_field_entry(sc_entry, sc_fi)
if sc_fe is not None and sc_fe.Name is not None:
if string.strcmp(sc_fe.Name, field_name) == 0:
return sc_entry
break
cur_parent = get_parent_name(cur_parent)
return None
# ============================================================
# get_struct_type — 按类名获取结构体的 LLVM 类型
# ============================================================

View File

@@ -6,6 +6,7 @@ import memhub
import string
import stdio
import stdlib
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExprCall as HandlesExprCall

View File

@@ -9,6 +9,8 @@ import sys
import stdlib
import viperlib
import w32.fileio as fileio
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
@@ -143,6 +145,95 @@ def clear_cdefine_constants() -> None:
_g_cdefine_values = None
# 常量整数表达式计算成功标志(供 _eval_const_int_expr 使用)
_g_const_eval_ok: int = 0
# ============================================================
# _eval_const_int_expr - 递归计算常量整数表达式
#
# 支持:
# - Constant (CONST_INT): 整数字面量
# - Name: CDefine 常量名(通过 lookup_cdefine_constant 查找)
# - BinOp (Add/Sub/Mult/FloorDiv/BitOr/BitAnd): 递归计算左右操作数
#
# 成功: 设置 _g_const_eval_ok=1, 返回计算值
# 失败: 设置 _g_const_eval_ok=0, 返回 0
#
# 用于 t.CArray count 的静态计算,如 2 * ZHUFF_MAX_CODES
# ============================================================
def _eval_const_int_expr(node: ast.AST | t.CPtr) -> int:
"""递归计算常量整数表达式"""
global _g_const_eval_ok
if node is None:
_g_const_eval_ok = 0
return 0
k: int = node.kind()
# Constant: 整数字面量
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
if cn.const_kind == ast.CONST_INT:
_g_const_eval_ok = 1
return cn.int_val
_g_const_eval_ok = 0
return 0
# Name: CDefine 常量名
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm.id is None:
_g_const_eval_ok = 0
return 0
val: int = lookup_cdefine_constant(nm.id)
if is_cdefine_found() == 0:
_g_const_eval_ok = 0
return 0
_g_const_eval_ok = 1
return val
# BinOp: 算术/位运算
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
# 递归计算左操作数
lv: int = _eval_const_int_expr(bop.left)
if _g_const_eval_ok == 0:
return 0
# 递归计算右操作数
rv: int = _eval_const_int_expr(bop.right)
if _g_const_eval_ok == 0:
return 0
# 根据运算符执行计算
if bop.op == ast.OpKind.Add:
_g_const_eval_ok = 1
return lv + rv
if bop.op == ast.OpKind.Sub:
_g_const_eval_ok = 1
return lv - rv
if bop.op == ast.OpKind.Mult:
_g_const_eval_ok = 1
return lv * rv
if bop.op == ast.OpKind.FloorDiv:
if rv == 0:
_g_const_eval_ok = 0
return 0
_g_const_eval_ok = 1
return lv // rv
if bop.op == ast.OpKind.BitOr:
_g_const_eval_ok = 1
return lv | rv
if bop.op == ast.OpKind.BitAnd:
_g_const_eval_ok = 1
return lv & rv
# 不支持的运算符
_g_const_eval_ok = 0
return 0
# 不支持的节点类型
_g_const_eval_ok = 0
return 0
def set_generic_context(tp_names: list[str] | t.CPtr,
type_args: list[str] | t.CPtr):
"""设置泛型特化上下文(进入泛型类方法体翻译时调用)"""
@@ -850,6 +941,11 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
mod_name: str = HandlesImports.lookup_from_import(from_imports, nm.id)
if mod_name is not None:
return map_t_type(pool, nm.id)
# 兜底: 尝试 map_t_type 中的硬编码 typedef 映射VOIDPTR, HANDLE, ULONG 等)
# 这些是跨模块通用的 C typedef 名,即使 from-import 查找失败也能解析
mapped_ty_fallback: llvmlite.LLVMType | t.CPtr = map_t_type(pool, nm.id)
if mapped_ty_fallback is not None:
return mapped_ty_fallback
return None
# Attribute 节点: t.CInt, t.CUInt64T, namespace_defs.PlainStruct 等
@@ -874,6 +970,13 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
if mod_struct_ty is not None:
return mod_struct_ty
return None
# 嵌套 Attribute: w32.win32base.SECURITY_ATTRIBUTES 等三级及以上限定名
# at.value 是 Attribute 而非 Name递归提取最终类名at.attr查结构体表
# find_struct 支持模块限定名回退,此处用最外层 attr简单类名即可
if at.value is not None and at.value.kind() == ast.ASTKind.Attribute:
nested_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(at.attr)
if nested_struct_ty is not None:
return nested_struct_ty
return None
# BinOp 节点: 联合类型注解 A | B
@@ -929,7 +1032,11 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
# value 是 Name泛型类名slice 是类型实参
if sub.value.kind() == ast.ASTKind.Name:
gen_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
# tuple[...] 类型注解TransPyV 暂不支持 tuple 返回类型,返回 None 让上层默认处理
# 避免走到 list[str](pool, 4) 构造路径崩溃tuple 未定义为泛型类)
if gen_nm.id is not None:
if string.strcmp(gen_nm.id, "tuple") == 0:
return None
# 先收集类型实参名,再分配缓冲区拼接 mangled name
gen_arg_names: list[str] | t.CPtr = list[str](pool, 4)
if sub.slice.kind() == ast.ASTKind.Tuple:
@@ -1031,28 +1138,20 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
pool, elem_node, imported_modules, from_imports, trans)
if elem_ty is None:
fatal_type_error(elem_node, "t.CArray 元素类型解析失败")
# 解析 count必须是整数常量、NoneCDefine 常量名)
# 解析 count支持整数常量、NoneCDefine 常量名、常量表达式如 2*MAX
# t.CArray[elem_ty, None] 等价于单参数形式 → Ptr(elem_ty)
# t.CArray[elem_ty, NAME] 其中 NAME: t.CDefine = value → [value x elem_ty]
# t.CArray[elem_ty, 2 * MAX] 常量表达式静态计算 → [2*MAX x elem_ty]
count_val: int = 0
if count_node.kind() == ast.ASTKind.Constant:
cnt_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(count_node)
if cnt_cn.const_kind == ast.CONST_NONE:
return llvmlite.Ptr(pool, elem_ty)
if cnt_cn.const_kind != ast.CONST_INT:
fatal_type_error(count_node, "t.CArray count 必须是整数常量、None 或 CDefine 常量名")
count_val = cnt_cn.int_val
elif count_node.kind() == ast.ASTKind.Name:
# CDefine 常量名查找
cnt_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(count_node)
if cnt_nm.id is None:
fatal_type_error(count_node, "t.CArray count Name 节点 id 为 None")
looked_up: int = lookup_cdefine_constant(cnt_nm.id)
if is_cdefine_found() == 0:
fatal_type_error(count_node, "t.CArray count 不是已注册的 CDefine 常量")
count_val = looked_up
else:
fatal_type_error(count_node, "t.CArray count 必须是整数常量、None 或 CDefine 常量名")
# 统一用 _eval_const_int_expr 计算常量整数表达式
# 支持 Constant(INT)、Name(CDefine)、BinOp(2*MAX 等算术/位运算)
count_val = _eval_const_int_expr(count_node)
if _g_const_eval_ok == 0:
fatal_type_error(count_node, "t.CArray count 必须是整数常量、None、CDefine 常量名或常量表达式")
if count_val <= 0:
fatal_type_error(count_node, "t.CArray count 必须为正数")
# 创建 ArrayType不包装 Ptr

View File

@@ -73,7 +73,9 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
sha1_set: str, set_count: int,
class_names_buf: bytes,
parent_names_buf: bytes,
def_sha1s_buf: bytes) -> int:
def_sha1s_buf: bytes,
generic_file_indices: t.CPtr,
generic_file_count_box: t.CPtr) -> int:
"""预扫描 includes 文件,收集类继承关系"""
if result is None or class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None:
return -1
@@ -88,6 +90,7 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
continue
sha1_e: str = entry.Sha1
file_has_generic: int = 0
# 按需翻译过滤
in_set: int = 0
@@ -147,6 +150,22 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
if cd is None or cd.name is None:
continue
# 检测泛型类(有 type_params记录文件索引以供 Phase 1a 预注册
if file_has_generic == 0:
tp_scan: list[str] | t.CPtr = cd.type_params
if tp_scan is not None:
file_has_generic = 1
if generic_file_count_box is not None:
gfc_ptr_scan: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(generic_file_count_box, t.CPtr))
if gfc_ptr_scan is not None:
gfc_scan: int = gfc_ptr_scan[0]
if gfc_scan < MAX_FILE_DEPS and generic_file_indices is not None:
gi_addr_scan: t.CUInt64T = t.CUInt64T(generic_file_indices) + gfc_scan * 4
gi_ptr_scan: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(gi_addr_scan, t.CPtr))
if gi_ptr_scan is not None:
gi_ptr_scan[0] = i
gfc_ptr_scan[0] = gfc_scan + 1
if class_count >= MAX_CLASSES:
break
@@ -513,14 +532,15 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
continue
string.strcpy(sha1_set + set_count * 17, se_ent.Sha1)
set_count += 1
# 先填充全局 SHA1 映射存储器(即使 set_count==0 也填充,确保 Phase2 能获取 includes 条目)
# 注意PopulateSha1MapStore 会先 free 旧存储器再重新分配
StubMerger.PopulateSha1MapStore(result)
# 写入 _sha1_map.txt人类可读输出程序内部不读取机器分析使用 PopulateSha1MapStore 内存存储器)
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, None, 0)
if set_count <= 0:
VLogger.warning("扫描结果无有效 SHA1跳过 Phase1项目可能无 includes 依赖)", "Phase1")
stdlib.free(sha1_set)
return 0
# 写入 _sha1_map.txt人类可读输出程序内部不读取机器分析使用 PopulateSha1MapStore 内存存储器)
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, None, 0)
# 填充全局 SHA1 映射存储器(内存中,不依赖 _sha1_map.txt 文件)
StubMerger.PopulateSha1MapStore(result)
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
td_len_p1map: t.CSizeT = string.strlen(temp_dir)
p1_sha1_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
@@ -621,6 +641,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
p1a_registered += 1
# 生成 .deps.txt记录依赖模块名供依赖图按需翻译使用
# 同时填充内存依赖存储器PopulateIncludesDeps供 _BuildReachableSha1Set
# 直接从内存读取,不依赖 .deps.txt 过程文件
td_len_a: t.CSizeT = string.strlen(temp_dir)
deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_a, sha1_a, "deps.txt")
if deps_path_a is not None:
@@ -631,6 +653,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
df_a.write(tr_a._imported_modules, dl_a)
df_a.close()
stdlib.free(deps_path_a)
# 填充内存依赖存储器(供 _BuildReachableSha1Set 使用,不读 .deps.txt
if tr_a._imported_modules is not None:
StubMerger.PopulateIncludesDeps(sha1_a, tr_a._imported_modules)
# 释放 Translator 的 C malloc 资源
if tr_a._global_names is not None:
@@ -689,6 +714,12 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
def_sha1s_buf: bytes = mb.alloc(MAX_CLASSES * SHA1_LEN)
topo_order: t.CPtr = mb.alloc(4 * MAX_FILE_DEPS)
topo_count_box: t.CPtr = mb.alloc(4)
generic_file_indices: t.CPtr = mb.alloc(4 * MAX_FILE_DEPS)
generic_file_count_box: t.CPtr = mb.alloc(4)
if generic_file_indices is not None:
string.memset(generic_file_indices, 0, 4 * MAX_FILE_DEPS)
if generic_file_count_box is not None:
string.memset(generic_file_count_box, 0, 4)
topo_count: int = 0
if class_names_buf is not None and parent_names_buf is not None and def_sha1s_buf is not None and topo_order is not None and topo_count_box is not None:
@@ -697,11 +728,16 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
string.memset(def_sha1s_buf, 0, MAX_CLASSES * SHA1_LEN)
string.memset(topo_order, 0, 4 * MAX_FILE_DEPS)
string.memset(topo_count_box, 0, 4)
if generic_file_indices is not None:
string.memset(generic_file_indices, 0, 4 * MAX_FILE_DEPS)
if generic_file_count_box is not None:
string.memset(generic_file_count_box, 0, 4)
class_count_scanned: int = _ScanClassInheritance(
mb, result, reachable_set, reachable_count,
use_reachable, sha1_set, set_count,
class_names_buf, parent_names_buf, def_sha1s_buf)
class_names_buf, parent_names_buf, def_sha1s_buf,
generic_file_indices, generic_file_count_box)
if class_count_scanned > 0:
ret_topo: int = _TopoSortFiles(
@@ -726,6 +762,87 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1")
topo_count = 0
# ============================================================
# Phase 1a-pre-generic: 预注册所有泛型类模板
#
# 在 Phase 1astruct 注册)之前执行,确保所有泛型类模板
#(如 GSListNode[T]、GSList[T])已注册。这样当其他文件的
# 结构体字段使用 GSListNode[Value] 等特化类型时,模板能被找到。
# ============================================================
generic_file_count: int = 0
if generic_file_count_box is not None:
gfc_box_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(generic_file_count_box, t.CPtr))
if gfc_box_ptr is not None:
generic_file_count = gfc_box_ptr[0]
if generic_file_count > 0 and generic_file_indices is not None:
fb_gpre: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_gpre is not None:
viperlib.snprintf(fb_gpre, 1024, "预注册 %d 个泛型类模板文件", generic_file_count)
VLogger.info(fb_gpre, "Phase1")
for gi in range(generic_file_count):
gi_addr_p: t.CUInt64T = t.CUInt64T(generic_file_indices) + gi * 4
gi_ptr_p: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(gi_addr_p, t.CPtr))
if gi_ptr_p is None:
continue
file_idx_gen: int = gi_ptr_p[0]
gen_entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + file_idx_gen * entry_size
gen_entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(gen_entry_addr, t.CPtr))
if gen_entry is None or gen_entry.Sha1 is None:
continue
gen_path: str = gen_entry.Path
gen_f: fileio.File | t.CPtr = fileio.File(gen_path, fileio.MODE.R)
if gen_f.closed:
continue
gen_src: bytes = stdlib.malloc(SRC_BUF_SIZE)
if gen_src is None:
gen_f.close()
continue
gen_br: LONG = gen_f.read_all(gen_src, SRC_BUF_SIZE)
gen_f.close()
if gen_br <= 0:
stdlib.free(gen_src)
continue
if gen_br < SRC_BUF_SIZE:
gen_src[gen_br] = 0
else:
gen_src[SRC_BUF_SIZE - 1] = 0
gen_lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
if gen_lx is None:
stdlib.free(gen_src)
continue
ast._lexer_init(gen_lx, gen_src, mb)
gen_tokens: ast.Token | t.CPtr = ast.tokenize(gen_lx)
gen_tree: ast.AST | t.CPtr = ast.parse_tokens(mb, gen_tokens)
if gen_tree is None:
stdlib.free(gen_src)
continue
gen_tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
if gen_tr is None:
stdlib.free(gen_src)
continue
gen_tr.ModuleSha1 = gen_entry.Sha1
gen_tr._declare_only = 1
gen_tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, gen_entry.RelPath)
HandlesType.set_current_file(gen_path)
HandlesType.set_current_module_sha1(gen_entry.Sha1)
HandlesType.clear_cdefine_constants()
HandlesStruct.reset_visible_structs(mb, 0)
gen_tr.translate(gen_tree)
if gen_tr._global_names is not None:
stdlib.free(gen_tr._global_names)
if gen_tr._nonlocal_names is not None:
stdlib.free(gen_tr._nonlocal_names)
stdlib.free(gen_src)
# 遍历文件:优先使用拓扑顺序,回退到字母序
iter_count: int = topo_count if topo_count > 0 else result.Count
for i in range(iter_count):
@@ -834,6 +951,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
mb.free(topo_order)
if topo_count_box is not None:
mb.free(topo_count_box)
if generic_file_indices is not None:
mb.free(generic_file_indices)
if generic_file_count_box is not None:
mb.free(generic_file_count_box)
# ============================================================
# Phase 1b: 全量翻译struct 已注册,走 existing 路径翻译方法体)

View File

@@ -19,6 +19,7 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.BuildPipeline as BuildPipeline
import lib.core.IncludesScanner as IncludesScanner
import lib.core.StubMerger as StubMerger
import lib.Projectrans.Utils as Utils
import lib.Projectrans.Config as Config
@@ -207,6 +208,19 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
BuildPipeline.ensure_dir(temp_dir)
BuildPipeline.ensure_dir(output_dir)
# === 0.5 扫描 includes 目录填充 Sha1Store消除 Phase1 依赖)===
# Phase2 不依赖 Phase1 的副作用:如果 Sha1Store 为空Phase1 未运行或提前返回),
# 自行扫描 includes 目录并填充 Sha1Store确保后续"编译缺失 includes"逻辑能正常工作
if includes_dir is not None:
if StubMerger.GetSha1StoreCount() == 0:
inc_scan_result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
if inc_scan_result is not None:
inc_filled: int = StubMerger.PopulateSha1MapStore(inc_scan_result)
fb_inc: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_inc is not None:
viperlib.snprintf(fb_inc, 1024, "Phase2 自主填充 includes Sha1Store: %d", inc_filled)
VLogger.info(fb_inc, "project")
# 追加 App 源文件 SHA1 到 _sha1_map.txt人类可读输出程序内部不读取此文件
# 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.py
# 同步追加到内存存储器AppendToSha1MapStore供跨模块 CDefine 查找)
@@ -296,10 +310,62 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# === 2. Phase A: 为每个文件生成 stub + text ===
# app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔)
# 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist实现按需编译
# 声明在 if 块外,确保 Phase B+ 和清理代码能访问
APP_DEPS_BUF_SIZE: t.CSizeT = 8192
app_deps_buf: bytes = None
app_deps_len: t.CSizeT = 0
if do_phase1 != 0:
if log is not None:
log.banner("Phase A: 生成 stub + text")
# === Phase A-pre-inc: includes 预注册 struct + 依赖填充 ===
# 必须在 App 源文件预注册之前执行App 源文件strict_mode=1可能继承
# 或引用 includes 中的 struct如 ast.AST。若 includes struct 未注册,
# App 源文件翻译会失败 → .obj 缺失 → undefined reference。
# 同时填充 PopulateIncludesDeps供 Phase B+ 的 _BuildReachableSha1Set 使用。
# 多遍扫描:解决跨文件继承问题(如 Constant(AST) 在 AST 未注册时被跳过)。
if includes_dir is not None and includes_binary_dir is not None:
store_count_inc_pre: int = StubMerger.GetSha1StoreCount()
if store_count_inc_pre > 0:
store_sha1_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
store_rel_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
inc_dir_len_pre: t.CSizeT = string.strlen(includes_dir)
deps_filled_pre: int = 0
PHASE_A_INC_MAX_PASSES: t.CInt = 3
for pass_inc_i in range(PHASE_A_INC_MAX_PASSES):
struct_count_before_inc: int = HandlesStruct.get_struct_count()
for si_inc in range(store_count_inc_pre):
inc_sha1_pre: str = store_sha1_inc_pre + t.CSizeT(si_inc) * 17
inc_rel_pre: str = store_rel_inc_pre + t.CSizeT(si_inc) * StubMerger.MAX_REL_PATH_LEN
if inc_rel_pre is None or inc_rel_pre[0] == '\0':
continue
rel_len_pre: t.CSizeT = string.strlen(inc_rel_pre)
full_path_pre: bytes = stdlib.malloc(inc_dir_len_pre + rel_len_pre + 2)
if full_path_pre is None:
continue
viperlib.snprintf(full_path_pre, inc_dir_len_pre + rel_len_pre + 2,
"%s/%s", includes_dir, inc_rel_pre)
pkg_inc_pre: str = HandlesImports.compute_package_from_relpath(mb, inc_rel_pre)
tr_inc_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(
mb, full_path_pre, inc_sha1_pre, pkg_inc_pre, 1)
stdlib.free(full_path_pre)
if tr_inc_pre is not None:
# 依赖填充只在第一遍执行PopulateIncludesDeps 内部有去重)
if pass_inc_i == 0:
if tr_inc_pre._imported_modules is not None:
if StubMerger.PopulateIncludesDeps(inc_sha1_pre, tr_inc_pre._imported_modules) == 0:
deps_filled_pre = deps_filled_pre + 1
struct_count_after_inc: int = HandlesStruct.get_struct_count()
# 收敛检查:本遍没有新结构体注册 → 所有类已注册
if struct_count_after_inc == struct_count_before_inc:
break
fb_inc_pre: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_inc_pre is not None:
viperlib.snprintf(fb_inc_pre, 1024, "includes 预注册 + 依赖填充: %d/%d", deps_filled_pre, store_count_inc_pre)
VLogger.info(fb_inc_pre, "prePhaseA")
# === Phase A-pre: 预注册所有源文件的 struct/enum/union ===
# 解决循环引用问题circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义
# 仅注册 struct/enum/uniondeclare_only=1不翻译方法体
@@ -334,6 +400,14 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
PHASE_A_IR_SIZE: t.CSizeT = 1048576
td_len_pa: t.CSizeT = string.strlen(temp_dir)
# app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔)
# 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist 使用
# 声明已在 if 块外,此处仅赋值
app_deps_buf = stdlib.malloc(APP_DEPS_BUF_SIZE)
app_deps_len = 0
if app_deps_buf is not None:
app_deps_buf[0] = '\0'
for i in range(file_count):
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
@@ -394,8 +468,21 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
df_a.close()
stdlib.free(deps_path_a)
# 收集 _imported_modules 到 app_deps_buf供 Phase B+ 按需编译)
if tr_a._imported_modules is not None and app_deps_buf is not None:
im_len_a: t.CSizeT = string.strlen(tr_a._imported_modules)
if im_len_a > 0 and app_deps_len + im_len_a + 1 < APP_DEPS_BUF_SIZE:
if app_deps_len > 0:
app_deps_buf[app_deps_len] = ' '
app_deps_len = app_deps_len + 1
string.strcpy(app_deps_buf + app_deps_len, tr_a._imported_modules)
app_deps_len = app_deps_len + im_len_a
app_deps_buf[app_deps_len] = '\0'
if do_phase2 == 0:
VLogger.info("Phase A 完成(仅 stub 生成)", "project")
if app_deps_buf is not None:
stdlib.free(app_deps_buf)
stdlib.free(entries)
return 0
@@ -404,8 +491,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
if log is not None:
log.banner("Phase B: 编译 .obj")
# 收集 .obj 路径
OBJ_PATHS_SIZE: t.CSizeT = 8192
# 收集 .obj 路径(增大到 64KB避免 includes .obj 路径溢出导致链接丢失符号)
# reachable_set/reachable_count: Phase B+ 填充Phase C 用于按需链接
reachable_set: bytes = None
reachable_count: int = 0
OBJ_PATHS_SIZE: t.CSizeT = 65536
obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE)
if obj_paths is None:
return 1
@@ -457,6 +547,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
sys.exit(1)
compiled_count += 1
# 显示编译完成的文件
fb_comp: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_comp is not None:
viperlib.snprintf(fb_comp, 1024, "[%d/%d] 编译完成: %s", i + 1, file_count, ent.Path)
VLogger.info(fb_comp, "PhaseB")
# 构造 .obj 路径,检测是否是 main 模块test_main.py 或 main.py
od_len: t.CSizeT = string.strlen(output_dir)
is_main_mod: int = 0
@@ -497,39 +592,85 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(entries)
return 1
# === 3.5 编译缺失的 includes 文件 ===
# includes.binary 可能缺少某些 includes .obj如 testcheck.py
# 这些文件被用户项目导入但未被 TransPyV 自身依赖Projectrans.py 未编译它们
# 检测并编译缺失的 includes 文件到 output_dir加入链接命令。
# 数据来源StubMerger 全局内存存储器(不读取 _sha1_map.txt 文件)
# === 3.5 编译缺失的 includes 文件(按依赖图按需编译)===
# 只编译被 App 源文件直接/间接引用的 includes 文件(可达集合
# 而非遍历整个 includes 目录。通过 _BuildReachableSha1Set 构建依赖图
if includes_dir is not None and includes_binary_dir is not None:
inc_compiled: int = 0
td_len_mi: t.CSizeT = string.strlen(temp_dir)
# 诊断日志:确认 Phase B+ 入口和 Sha1Store 状态
fb_pbp_enter: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_pbp_enter is not None:
viperlib.snprintf(fb_pbp_enter, 1024,
"PhaseB+ 入口: store_count=%d includes_binary_dir=%s",
StubMerger.GetSha1StoreCount(), includes_binary_dir)
VLogger.info(fb_pbp_enter, "PhaseB+")
# 创建 includes_binary_dir 目录(确保 .obj 能写入和 collect_obj_files 能扫描)
BuildPipeline.ensure_dir(includes_binary_dir)
# declare_only 预处理已移至 Phase A 之前Phase A-pre-inc
# 确保 Phase A 翻译 App 源文件时 includes struct 已注册。
# PopulateIncludesDeps 已在 Phase A-pre-inc 中填充。
# 构建可达 SHA1 集合(依赖图遍历)
# app_deps_buf 为 None 时回退到扫描 source_dir非递归
REACHABLE_SET_SIZE: t.CSizeT = t.CSizeT(StubMerger.MAX_INCLUDES_SHA1) * 17
reachable_set: bytes = stdlib.malloc(REACHABLE_SET_SIZE)
reachable_count: int = 0
if reachable_set is not None:
string.memset(reachable_set, 0, REACHABLE_SET_SIZE)
reachable_count = StubMerger._BuildReachableSha1Set(
mb, source_dir, temp_dir, reachable_set, app_deps_buf)
fb_reach: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_reach is not None:
viperlib.snprintf(fb_reach, 1024, "可达 includes SHA1: %d", reachable_count)
VLogger.info(fb_reach, "PhaseB+")
# fast-fail: 可达集合构建失败(依赖未找到),永不回退,直接终止
if reachable_count < 0:
VLogger.error("可达集合构建失败fast-fail终止编译", "PhaseB+")
return 1
else:
VLogger.error("reachable_set 分配失败,终止编译", "PhaseB+")
return 1
# 释放 app_deps_buf已构建完 reachable_set不再需要
if app_deps_buf is not None:
stdlib.free(app_deps_buf)
app_deps_buf = None
# 从全局存储器获取 SHA1/模块名/rel_path 数组(直接访问器,避免 box 解引用问题)
store_count_mi: int = StubMerger.GetSha1StoreCount()
if store_count_mi > 0:
store_sha1_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
store_mod_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreModArrPtr()
store_rel_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
for si_mi in range(store_count_mi):
# 获取当前条目的 SHA1 和 rel_path
inc_sha1_mi: str = store_sha1_arr_mi + t.CSizeT(si_mi) * 17
inc_rel_mi: str = store_rel_arr_mi + t.CSizeT(si_mi) * StubMerger.MAX_REL_PATH_LEN
# 检查 .obj 是否已存在于 includes.binary
# 按需编译过滤:只处理 reachable_set 中的 includes
# 永不回退reachable_count > 0 时严格按可达集合过滤
if reachable_count > 0:
if StubMerger._is_in_sha1_set(inc_sha1_mi, reachable_set, reachable_count) == 0:
continue
# 检查 .obj 是否已存在于 includes.binary切片子目录
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
check_pat_mi: bytes = stdlib.malloc(ibd_len_mi + 35)
if check_pat_mi is None:
continue
viperlib.snprintf(check_pat_mi, ibd_len_mi + 35, "%s/%s*.obj", includes_binary_dir, inc_sha1_mi)
check_pat_mi: str = StubMerger._sliced_path(includes_binary_dir, ibd_len_mi, inc_sha1_mi, "obj")
check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
obj_exists_mi: int = 0
if check_fd_mi is not None:
if check_pat_mi is not None and check_fd_mi is not None:
string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
check_h_mi: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(check_pat_mi, check_fd_mi)
if check_h_mi != w32.win32base.INVALID_HANDLE_VALUE:
w32.win32file.FindClose(check_h_mi)
obj_exists_mi = 1
if obj_exists_mi != 0:
if check_pat_mi is not None:
stdlib.free(check_pat_mi)
stdlib.free(check_fd_mi)
continue
# .obj 不存在,需要编译
@@ -538,6 +679,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
inc_dir_len_mi: t.CSizeT = string.strlen(includes_dir)
src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1)
if src_fp_mi is None:
stdlib.free(check_pat_mi)
if check_fd_mi is not None:
stdlib.free(check_fd_mi)
continue
viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1,
"%s/%s", includes_dir, inc_rel_mi)
@@ -571,20 +715,35 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
tpos_mi += 1
if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0:
# 临时在行尾加 \0 供 strstr 使用
saved_mi: t.CChar = tbuf_mi[tls_mi + tll_mi]
tbuf_mi[tls_mi + tll_mi] = '\0'
# 仅当行尾不在缓冲区末尾时才需保存/恢复
# (缓冲区末尾已在上方 read_all 后截断为 '\0',直接用即可)
# 避免 tls_mi + tll_mi == tbr_mi 时越界写
end_pos_mi: t.CSizeT = tls_mi + tll_mi
saved_mi: t.CChar = '\0'
need_restore_mi: int = 0
if end_pos_mi < tbr_mi:
saved_mi = tbuf_mi[end_pos_mi]
tbuf_mi[end_pos_mi] = '\0'
need_restore_mi = 1
if string.strstr(tbuf_mi + tls_mi, "@\"") is not None:
tbuf_mi[tls_mi + tll_mi] = saved_mi
if need_restore_mi != 0:
tbuf_mi[end_pos_mi] = saved_mi
is_decl_mi = 0
break
tbuf_mi[tls_mi + tll_mi] = saved_mi
if need_restore_mi != 0:
tbuf_mi[end_pos_mi] = saved_mi
stdlib.free(tbuf_mi)
tf_mi.close()
stdlib.free(tpath_mi)
# is_decl_mi == -1: text.ll 不存在Phase1 未翻译此文件,可能不被项目导入
# is_decl_mi == -1: text.ll 不存在Phase1 未翻译此文件)
# is_decl_mi == 1: 声明文件(仅 declare 无 define
# 两种情况都跳过:不编译未被 Phase1 翻译的 includes 文件
if is_decl_mi != 0:
# is_decl_mi == 0: 实现文件(有 define
# 只跳过声明文件is_decl_mi == 1text.ll 不存在时继续,让后续翻译逻辑处理
if is_decl_mi == 1:
stdlib.free(check_pat_mi)
if check_fd_mi is not None:
stdlib.free(check_fd_mi)
stdlib.free(src_fp_mi)
continue
# 尝试 BuildCombinedIRstub/text 应已由 Phase1 生成)
@@ -633,19 +792,43 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
if inc_combined_len_mi == 0:
# 诊断:检查 stub.ll/text.ll 是否存在
diag_stub: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
diag_text: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
diag_stub_ex: int = 0
diag_text_ex: int = 0
if diag_stub is not None:
df_diag_s: fileio.File | t.CPtr = fileio.File(diag_stub, fileio.MODE.R)
if not df_diag_s.closed:
diag_stub_ex = 1
df_diag_s.close()
stdlib.free(diag_stub)
if diag_text is not None:
df_diag_t: fileio.File | t.CPtr = fileio.File(diag_text, fileio.MODE.R)
if not df_diag_t.closed:
diag_text_ex = 1
df_diag_t.close()
stdlib.free(diag_text)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", src_fp_mi)
viperlib.snprintf(fb, 1024,
"BuildCombinedIR 失败: %s (stub=%d text=%d is_decl=%d)",
src_fp_mi, diag_stub_ex, diag_text_ex, is_decl_mi)
VLogger.error(fb, "PhaseB+")
if inc_combined_mi is not None:
stdlib.free(inc_combined_mi)
stdlib.free(check_pat_mi)
if check_fd_mi is not None:
stdlib.free(check_fd_mi)
stdlib.free(src_fp_mi)
continue
# 编译为 .obj
# 编译为 .obj(输出到 includes_binary_dir与存在性检查和链接收集一致
inc_cret_mi: int = BuildPipeline.compile_module_to_obj(
inc_combined_mi, inc_combined_len_mi, temp_dir, output_dir, inc_sha1_mi,
inc_combined_mi, inc_combined_len_mi, temp_dir, includes_binary_dir, inc_sha1_mi,
cc_cmd, cc_flags)
stdlib.free(inc_combined_mi)
if inc_cret_mi != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
@@ -654,10 +837,16 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
sys.exit(1)
inc_compiled += 1
# 显示编译完成的 includes 文件
fb_inc_comp: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_inc_comp is not None:
viperlib.snprintf(fb_inc_comp, 1024, "[includes %d] 编译完成: %s", inc_compiled, src_fp_mi)
VLogger.info(fb_inc_comp, "PhaseB+")
# 添加到 obj_paths (切片路径,从 includes_binary_dir 取)
ibd_len_mi2: t.CSizeT = string.strlen(includes_binary_dir)
inc_obj_sliced: str = StubMerger._sliced_path(includes_binary_dir, ibd_len_mi2, inc_sha1_mi, "obj")
# 添加到 obj_paths (切片路径)
od_len_mi: t.CSizeT = string.strlen(output_dir)
inc_obj_sliced: str = StubMerger._sliced_path(output_dir, od_len_mi, inc_sha1_mi, "obj")
if inc_obj_sliced is not None:
inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced)
if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE:
@@ -669,11 +858,25 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
obj_paths[obj_pos] = '\0'
stdlib.free(inc_obj_sliced)
# 释放本次迭代的临时内存
if check_pat_mi is not None:
stdlib.free(check_pat_mi)
if check_fd_mi is not None:
stdlib.free(check_fd_mi)
stdlib.free(src_fp_mi)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "编译缺失 includes: %d", inc_compiled)
VLogger.info(fb, "PhaseB+")
# 释放 app_deps_bufPhase B+ 块未执行时此处兜底释放)
if app_deps_buf is not None:
stdlib.free(app_deps_buf)
app_deps_buf = None
# === 4. Phase C: 链接所有 .obj → .exe ===
if log is not None:
log.banner("Phase C: 链接")
@@ -708,6 +911,18 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
final_obj_paths[fop_pos] = '\0'
obj_paths_len: t.CSizeT = fop_pos
# 暂时禁用按图链接:始终全量链接 includes.binary 中的 .obj
# 按图链接在 --clean 后 deps.txt 缺失时无法正确工作(跨包传递依赖丢失)
# 按图编译Phase B+)仍保留:只编译 reachable_set 中的缺失 includes
# TODO: 待 deps.txt 生成机制完善后(如 Phase A 翻译所有 includes 的 imports重新启用按图链接
# 释放 reachable_setPhase B+ 已使用完毕)
if reachable_set is not None:
stdlib.free(reachable_set)
reachable_set = None
# 始终传 includes_binary_dir 给 link_objs_to_exe由其全量收集 .obj
lret: int = BuildPipeline.link_objs_to_exe(
final_obj_paths, obj_paths_len,
linker_cmd, linker_flags, exe_path,

View File

@@ -51,6 +51,19 @@ _sha1_store_mod: bytes # 模块名数组(每个 64 字节MAX_INCLUDES 个
_sha1_store_rel: bytes # 相对路径数组(每个 256 字节MAX_INCLUDES 个)
_sha1_store_count: int # 条目数
# 可达集合是否不完整1=有 includes deps.txt 缺失Phase C 应回退全量链接)
_g_reachable_incomplete: int
# includes 依赖内存存储(不依赖 deps.txt 过程文件)
# Phase B+ 前用 declare_only 翻译所有 includes 文件,提取 _imported_modules 存入此处
# _BuildReachableSha1Set 从此处读取依赖,不读 deps.txt
_includes_deps_sha1: bytes # SHA1 数组(每个 17 字节MAX_INCLUDES 个)
_includes_deps_str: bytes # 依赖字符串数组(每个 512 字节MAX_INCLUDES 个)
_includes_deps_count: int # 条目数
# 单条依赖字符串最大长度
MAX_DEPS_STR_LEN: t.CDefine = 512
# rel_path 最大长度
MAX_REL_PATH_LEN: t.CDefine = 256
@@ -493,6 +506,85 @@ def GetSha1StoreCount() -> int:
return _sha1_store_count
def IsReachableIncomplete() -> int:
"""返回可达集合是否不完整1=有 deps.txt 缺失,应回退全量链接)"""
return _g_reachable_incomplete
# ============================================================
# PopulateIncludesDeps - 将 includes 文件的依赖存入内存
#
# Phase B+ 前用 declare_only 翻译 includes 文件,提取 _imported_modules
# 后调用此函数存入内存。_BuildReachableSha1Set 从内存读取,不读 deps.txt。
#
# Args:
# sha1: includes 文件的 SHA116字符
# deps_str: 依赖模块名字符串(空格分隔,如 "t c stdint string"
#
# Returns:
# 0 成功,非 0 失败
# ============================================================
def PopulateIncludesDeps(sha1: str, deps_str: str) -> int:
"""将 includes 文件的依赖存入内存"""
global _includes_deps_sha1, _includes_deps_str, _includes_deps_count
if sha1 is None:
return 1
# 延迟初始化
if _includes_deps_sha1 is None:
_includes_deps_sha1 = stdlib.malloc(MAX_INCLUDES * 17)
_includes_deps_str = stdlib.malloc(MAX_INCLUDES * MAX_DEPS_STR_LEN)
if _includes_deps_sha1 is None or _includes_deps_str is None:
return 1
string.memset(_includes_deps_sha1, 0, MAX_INCLUDES * 17)
string.memset(_includes_deps_str, 0, MAX_INCLUDES * MAX_DEPS_STR_LEN)
_includes_deps_count = 0
if _includes_deps_count >= MAX_INCLUDES:
return 1
# 去重:若 SHA1 已存在则跳过
for i in range(_includes_deps_count):
sidx: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(_includes_deps_sha1 + sidx, sha1) == 0:
return 0
# 写入 SHA1
idx: t.CSizeT = t.CSizeT(_includes_deps_count) * 17
string.strcpy(_includes_deps_sha1 + idx, sha1)
# 写入依赖字符串
idx2: t.CSizeT = t.CSizeT(_includes_deps_count) * MAX_DEPS_STR_LEN
if deps_str is not None:
dl: t.CSizeT = string.strlen(deps_str)
if dl < MAX_DEPS_STR_LEN:
string.strcpy(_includes_deps_str + idx2, deps_str)
else:
string.strncpy(_includes_deps_str + idx2, deps_str, MAX_DEPS_STR_LEN - 1)
else:
_includes_deps_str[idx2] = '\0'
_includes_deps_count = _includes_deps_count + 1
return 0
# ============================================================
# LookupIncludesDeps - 从内存查找 includes 文件的依赖
#
# Args:
# sha1: includes 文件的 SHA116字符
#
# Returns:
# 依赖模块名字符串指针空格分隔None 表示未找到
# ============================================================
def LookupIncludesDeps(sha1: str) -> str:
"""从内存查找 includes 文件的依赖"""
if sha1 is None or _includes_deps_sha1 is None:
return None
if _includes_deps_count <= 0:
return None
for i in range(_includes_deps_count):
sidx: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(_includes_deps_sha1 + sidx, sha1) == 0:
idx2: t.CSizeT = t.CSizeT(i) * MAX_DEPS_STR_LEN
return _includes_deps_str + idx2
return None
def GetSha1StoreArrPtr() -> bytes | t.CPtr:
"""返回 SHA1 数组指针(每个条目 17 字节)"""
return _sha1_store_arr
@@ -538,6 +630,32 @@ def GetSha1StoreArr(out_sha1_arr: t.CPtr, out_mod_arr: t.CPtr, out_rel_arr: t.CP
return _sha1_store_count
# ============================================================
# LookupSha1RelPath - 通过 SHA1 查找相对路径
#
# 遍历全局存储器,返回 sha1 对应的相对路径指针(只读,不要 free
# 用于错误提示:将 sha1 转换为人类可读的文件路径。
#
# Args:
# sha1: SHA1 字符串16 字符)
#
# Returns:
# 相对路径字符串指针只读None=未找到
# ============================================================
def LookupSha1RelPath(sha1: str) -> str:
"""通过 SHA1 查找相对路径返回只读指针None=未找到"""
if sha1 is None:
return None
if _sha1_store_arr is None or _sha1_store_rel is None:
return None
for i in range(_sha1_store_count):
sidx: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(_sha1_store_arr + sidx, sha1) == 0:
ridx: t.CSizeT = t.CSizeT(i) * MAX_REL_PATH_LEN
return _sha1_store_rel + ridx
return None
# ============================================================
# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define
#
@@ -1265,11 +1383,19 @@ def _AddSha1ToSet(set_buf: t.CChar | t.CPtr, count: int, sha1: str) -> int:
# ============================================================
def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
temp_dir: str,
reachable_set: t.CChar | t.CPtr) -> int:
"""构建可达 SHA1 集合(依赖图按需翻译)"""
reachable_set: t.CChar | t.CPtr,
app_deps: str = None) -> int:
"""构建可达 SHA1 集合(依赖图按需翻译)
app_deps: App 源文件的直接依赖模块名(空格分隔),如果非空则跳过自己的扫描步骤
"""
global _g_reachable_incomplete
if source_dir is None or temp_dir is None or reachable_set is None:
return -1
# 重置不完整标志
_g_reachable_incomplete = 0
SRC_BUF_SIZE_R: t.CSizeT = 1048576
# 1. 构建 SHA1→module_name 映射
@@ -1293,29 +1419,9 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
viperlib.snprintf(fb, 1024, "SHA1 映射: %d", map_count)
VLogger.debug(fb, "Reachable")
# 2. 扫描 source_dir 下的 .py 文件,收集直接依赖
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)
return -1
viperlib.snprintf(pattern, dir_len + 8, "%s/*.py", 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)
return -1
string.memset(find_data, 0, find_data_size + 16)
# 工作列表(空格分隔的模块名)
worklist: bytes = stdlib.malloc(8192)
if worklist is None:
stdlib.free(pattern)
stdlib.free(find_data)
stdlib.free(sha1_arr)
stdlib.free(mod_arr)
return -1
@@ -1324,70 +1430,104 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
reachable_count: int = 0
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
if handle == win32base.INVALID_HANDLE_VALUE:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "未找到 .py 文件: %s", pattern)
VLogger.warning(fb, "Reachable")
stdlib.free(pattern)
stdlib.free(find_data)
stdlib.free(sha1_arr)
stdlib.free(mod_arr)
stdlib.free(worklist)
return -1
# 2. 如果 app_deps 非空,直接使用它作为初始 worklist跳过自己的非递归扫描
# 否则回退到自己的非递归扫描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:
string.strcpy(worklist, app_deps)
wl_len = ad_len
else:
# 回退到自己的非递归扫描
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/*.py", source_dir)
while True:
fname: str = find_data.cFileName
if fname is not None:
fname_len: t.CSizeT = string.strlen(fname)
if fname_len > 3:
is_py: int = 0
if fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y':
is_py = 1
if is_py != 0:
full_path: bytes = stdlib.malloc(dir_len + fname_len + 2)
if full_path is not None:
viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", source_dir, fname)
sf: fileio.File | t.CPtr = fileio.File(full_path, fileio.MODE.R)
if not sf.closed:
sbuf: bytes = stdlib.malloc(SRC_BUF_SIZE_R)
if sbuf is not None:
br: LONG = sf.read_all(sbuf, SRC_BUF_SIZE_R)
sf.close()
if br > 0:
if br < SRC_BUF_SIZE_R:
sbuf[br] = 0
else:
sbuf[SRC_BUF_SIZE_R - 1] = 0
# 解析 AST 获取 _imported_modules
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
if lx is not None:
ast._lexer_init(lx, sbuf, mb)
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
if tree is not None:
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)
HandlesStruct.reset_visible_structs(mb, 0)
tr.translate(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:
string.strcpy(worklist + wl_len, tr._imported_modules)
wl_len += im_len
worklist[wl_len] = ' '
wl_len += 1
worklist[wl_len] = '\0'
# 释放 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)
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: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_fd is not None:
viperlib.snprintf(fb_fd, 1024, "未找到 .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 not None:
fname_len: t.CSizeT = string.strlen(fname)
if fname_len > 3:
is_py: int = 0
if fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y':
is_py = 1
if is_py != 0:
full_path: bytes = stdlib.malloc(dir_len + fname_len + 2)
if full_path is not None:
viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", source_dir, fname)
sf: fileio.File | t.CPtr = fileio.File(full_path, fileio.MODE.R)
if not sf.closed:
sbuf: bytes = stdlib.malloc(SRC_BUF_SIZE_R)
if sbuf is not None:
br: LONG = sf.read_all(sbuf, SRC_BUF_SIZE_R)
sf.close()
if br > 0:
if br < SRC_BUF_SIZE_R:
sbuf[br] = 0
else:
sbuf[SRC_BUF_SIZE_R - 1] = 0
# 解析 AST 获取 _imported_modules
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
if lx is not None:
ast._lexer_init(lx, sbuf, mb)
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
if tree is not None:
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)
HandlesStruct.reset_visible_structs(mb, 0)
tr.translate(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:
string.strcpy(worklist + wl_len, tr._imported_modules)
wl_len += im_len
worklist[wl_len] = ' '
wl_len += 1
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)
# 释放 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)
else:
stdlib.free(sbuf)
@@ -1395,16 +1535,16 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
sf.close()
stdlib.free(full_path)
if win32file.FindNextFileA(handle, find_data) == 0:
break
win32base.FindClose(handle)
stdlib.free(pattern)
stdlib.free(find_data)
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] == ' ':
worklist[wl_len - 1] = '\0'
wl_len -= 1
# 去掉末尾多余空格
if wl_len > 0 and worklist[wl_len - 1] == ' ':
worklist[wl_len - 1] = '\0'
wl_len -= 1
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
@@ -1512,36 +1652,55 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
# 加入 reachable_set
reachable_count = _AddSha1ToSet(reachable_set, reachable_count, found_sha1)
# 读取 .deps.txt 追加到 worklist
deps_path: str = _sliced_path(temp_dir, td_len_r, found_sha1, "deps.txt")
if deps_path is not None:
df: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R)
if not df.closed:
deps_buf: bytes = stdlib.malloc(2048)
if deps_buf is not None:
dbr: t.CInt64T = df.read_all(deps_buf, 2048)
df.close()
if dbr > 0:
if dbr < 2048:
deps_buf[dbr] = '\0'
else:
deps_buf[2047] = '\0'
# 追加到 worklist嵌套 if 拆分 + 用 = 代替 += 绕过 TPC AUGASGN bug
dl: t.CSizeT = string.strlen(deps_buf)
if worklist is not None:
if dl > 0 and wl_len + dl + 2 < 8192:
if wl_len > 0 and worklist[wl_len - 1] != ' ':
worklist[wl_len] = ' '
wl_len = wl_len + 1
string.strcpy(worklist + wl_len, deps_buf)
wl_len = wl_len + dl
worklist[wl_len] = ' '
wl_len = wl_len + 1
worklist[wl_len] = '\0'
stdlib.free(deps_buf)
else:
df.close()
stdlib.free(deps_path)
# 从内存查找依赖(不读 deps.txt 过程文件)
# Phase B+ 前用 declare_only 翻译所有 includes 文件,提取 _imported_modules 存入内存
deps_str: str = LookupIncludesDeps(found_sha1)
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 > 0 and worklist[wl_len - 1] != ' ':
worklist[wl_len] = ' '
wl_len = wl_len + 1
string.strcpy(worklist + wl_len, deps_str)
wl_len = wl_len + dl
worklist[wl_len] = ' '
wl_len = wl_len + 1
worklist[wl_len] = '\0'
# deps_str 为空字符串视为无依赖(合法情况,如叶子模块)
else:
# 依赖未在内存中找到
# 按需过滤: 检查是否是 App 源文件source_dir 下的 .py 文件)
# App 源文件不需要加入 reachable_set只用于 includes 过滤),跳过
sd_len_ff: t.CSizeT = string.strlen(source_dir)
mb_len_ff: t.CSizeT = string.strlen(mod_buf)
app_mod_path: bytes = stdlib.malloc(sd_len_ff + mb_len_ff + 6)
is_app_src: int = 0
if app_mod_path is not None:
viperlib.snprintf(app_mod_path, sd_len_ff + mb_len_ff + 6, "%s/%s.py", source_dir, mod_buf)
af: fileio.File | t.CPtr = fileio.File(app_mod_path, fileio.MODE.R)
if not af.closed:
is_app_src = 1
af.close()
stdlib.free(app_mod_path)
if is_app_src != 0:
# App 源文件,跳过(不 fast-fail
fb_skip: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_skip is not None:
viperlib.snprintf(fb_skip, 1024, "跳过 App 源文件: %s (sha1=%s)", mod_buf, found_sha1)
VLogger.debug(fb_skip, "Reachable")
else:
# fast-fail: includes 文件依赖未在内存中找到Phase 1a-pre 未正确填充
fb_ff: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_ff is not None:
viperlib.snprintf(fb_ff, 1024, "依赖未找到 fast-fail: 模块 %s (sha1=%s) 的依赖未在内存中注册", mod_buf, found_sha1)
VLogger.error(fb_ff, "Reachable")
stdlib.free(sha1_arr)
stdlib.free(mod_arr)
stdlib.free(worklist)
stdlib.free(processed)
stdlib.free(mod_buf)
return -1
stdlib.free(mod_buf)
stdlib.free(sha1_arr)
stdlib.free(mod_arr)

View File

@@ -101,7 +101,7 @@ class Logger:
self._reset_color()
# category 可选
if category is not None and category[0] != 0:
stdio.printf("[%s]", category)
stdio.printf(" [%s]", category)
stdio.printf(": %s\n", msg)
return 0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,63 +0,0 @@
"""
Auto-generated Python stub file from linkedlist.py
Module: linkedlist
"""
import t, c
from stdint import *
@t.NoVTable
class LinkedNode:
next: 'LinkedNode' | t.CPtr
prev: 'LinkedNode' | t.CPtr
child: 'LinkedNode' | t.CPtr
last_child: 'LinkedNode' | t.CPtr
parent: 'LinkedNode' | t.CPtr
child_count: t.CSizeT
def append(self: LinkedNode, node: 'LinkedNode' | t.CPtr) -> t.CInt: pass
def prepend(self: LinkedNode, node: 'LinkedNode' | t.CPtr) -> t.CInt: pass
def insert_before(self: LinkedNode, node: 'LinkedNode' | t.CPtr, new_node: 'LinkedNode' | t.CPtr) -> t.CInt: pass
def insert_after(self: LinkedNode, node: 'LinkedNode' | t.CPtr, new_node: 'LinkedNode' | t.CPtr) -> t.CInt: pass
def remove_child(self: LinkedNode, node: 'LinkedNode' | t.CPtr) -> t.CInt: pass
def detach(self: LinkedNode) -> t.CInt: pass
def unlink(self: LinkedNode) -> t.CInt: pass
def has_children(self: LinkedNode) -> t.CInt: pass
def child_at(self: LinkedNode, index: t.CSizeT) -> 'LinkedNode' | t.CPtr: pass
def count_children(self: LinkedNode) -> t.CSizeT: pass
def first_sibling(self: LinkedNode) -> 'LinkedNode' | t.CPtr: pass
def last_sibling(self: LinkedNode) -> 'LinkedNode' | t.CPtr: pass
@t.NoVTable
class SListNode:
Next: 'SListNode' | t.CPtr
def append(self: SListNode, node: 'SListNode' | t.CPtr) -> 'SListNode' | t.CPtr: pass
def append_after(self: SListNode, node: 'SListNode' | t.CPtr) -> 'SListNode' | t.CPtr: pass
def count(self: SListNode) -> t.CSizeT: pass
def at(self: SListNode, index: t.CSizeT) -> 'SListNode' | t.CPtr: pass
def remove(self: SListNode, node: 'SListNode' | t.CPtr) -> 'SListNode' | t.CPtr: pass
@t.NoVTable
class GSListNode[T]:
Next: T | t.CPtr
@t.NoVTable
class GSList[T]:
Head: T | t.CPtr
Tail: T | t.CPtr
Count: t.CSizeT
def __init__(self: GSList) -> t.CInt: pass
def append(self: GSList, node: T) -> t.CInt: pass
def count(self: GSList) -> t.CSizeT: pass
def at(self: GSList, index: t.CSizeT) -> T | t.CPtr: pass
@t.NoVTable
class GTreeNode[T]:
Next: T | t.CPtr
Prev: T | t.CPtr
Child: T | t.CPtr
LastChild: T | t.CPtr
Parent: T | t.CPtr
Count: t.CSizeT
def append(self: GTreeNode, node: T | t.CPtr) -> t.CInt: pass
def prepend(self: GTreeNode, node: T | t.CPtr) -> t.CInt: pass
def detach(self: GTreeNode) -> t.CInt: pass
def has_children(self: GTreeNode) -> t.CInt: pass
def child_at(self: GTreeNode, index: t.CSizeT) -> T | t.CPtr: pass
def count_children(self: GTreeNode) -> t.CSizeT: pass

View File

@@ -1,33 +0,0 @@
"""
Auto-generated Python stub file from subprocess.py
Module: subprocess
"""
import t, c
from stdint import *
import platmacro
import memhub
import string
import w32.win32base
import w32.win32file
import w32.win32process
import w32.win32sync
import posix
OUTPUT_BUF_SIZE: t.CDefine = 65536
_mbuddy: t.CExtern | memhub.MemBuddy | t.CPtr
class CompletedProcess:
args: str
returncode: int
stdout: str
stderr: str
def __new__(self: CompletedProcess, args: str, returncode: int, stdout: str, stderr: str) -> t.CPtr: pass
def __init__(self: CompletedProcess, args: str, returncode: int, stdout: str, stderr: str) -> t.CInt: pass
def run(args: str, capture_output: bool = True, text: bool = True) -> CompletedProcess | t.CPtr: pass
def _run_win32(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr: pass
def _run_posix(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr: pass

View File

@@ -1,189 +0,0 @@
"""
Auto-generated Python stub file from posix.py
Module: posix
"""
import t, c
from stdint import *
DIR: t.CTypedef = t.CVoid | t.CPtr
mode_t: t.CTypedef = t.CUInt32T
pid_t: t.CTypedef = t.CInt32T
off_t: t.CTypedef = t.CInt64T
dev_t: t.CTypedef = t.CUInt64T
ino_t: t.CTypedef = t.CUInt64T
nlink_t: t.CTypedef = t.CUInt64T
uid_t: t.CTypedef = t.CUInt32T
gid_t: t.CTypedef = t.CUInt32T
blksize_t: t.CTypedef = t.CInt64T
blkcnt_t: t.CTypedef = t.CInt64T
time_t: t.CTypedef = t.CInt64T
O_RDONLY: t.CDefine = 0
O_WRONLY: t.CDefine = 1
O_RDWR: t.CDefine = 2
O_CREAT: t.CDefine = 0o100
O_EXCL: t.CDefine = 0o200
O_TRUNC: t.CDefine = 0o1000
O_APPEND: t.CDefine = 0o2000
O_NONBLOCK: t.CDefine = 0o4000
O_CLOEXEC: t.CDefine = 0o2000000
F_OK: t.CDefine = 0 # 文件存在
R_OK: t.CDefine = 4 # 可读
W_OK: t.CDefine = 2 # 可写
X_OK: t.CDefine = 1 # 可执行
S_IFMT: t.CDefine = 0o170000 # 类型掩码
S_IFSOCK: t.CDefine = 0o140000 # 套接字
S_IFLNK: t.CDefine = 0o120000 # 符号链接
S_IFREG: t.CDefine = 0o100000 # 普通文件
S_IFBLK: t.CDefine = 0o060000 # 块设备
S_IFDIR: t.CDefine = 0o040000 # 目录
S_IFCHR: t.CDefine = 0o020000 # 字符设备
S_IFIFO: t.CDefine = 0o010000 # FIFO/管道
S_ISUID: t.CDefine = 0o4000 # set-user-ID
S_ISGID: t.CDefine = 0o2000 # set-group-ID
S_ISVTX: t.CDefine = 0o1000 # sticky 位
S_IRWXU: t.CDefine = 0o700 # 用户读写执行
S_IRUSR: t.CDefine = 0o400 # 用户读
S_IWUSR: t.CDefine = 0o200 # 用户写
S_IXUSR: t.CDefine = 0o100 # 用户执行
S_IRWXG: t.CDefine = 0o070 # 组读写执行
S_IRGRP: t.CDefine = 0o040 # 组读
S_IWGRP: t.CDefine = 0o020 # 组写
S_IXGRP: t.CDefine = 0o010 # 组执行
S_IRWXO: t.CDefine = 0o007 # 其他读写执行
S_IROTH: t.CDefine = 0o004 # 其他读
S_IWOTH: t.CDefine = 0o002 # 其他写
S_IXOTH: t.CDefine = 0o001 # 其他执行
SEEK_SET: t.CDefine = 0
SEEK_CUR: t.CDefine = 1
SEEK_END: t.CDefine = 2
PATH_MAX: t.CDefine = 4096
NAME_MAX: t.CDefine = 255
_SC_NPROCESSORS_ONLN: t.CDefine = 84
_SC_PAGESIZE: t.CDefine = 30
_SC_CLK_TCK: t.CDefine = 2
DT_UNKNOWN: t.CDefine = 0
DT_FIFO: t.CDefine = 1
DT_CHR: t.CDefine = 2
DT_DIR: t.CDefine = 4
DT_BLK: t.CDefine = 6
DT_REG: t.CDefine = 8
DT_LNK: t.CDefine = 10
DT_SOCK: t.CDefine = 12
DT_WHT: t.CDefine = 14
WNOHANG: t.CDefine = 1
WUNTRACED: t.CDefine = 2
WCONTINUED: t.CDefine = 8
class Stat:
st_dev: dev_t
st_ino: ino_t
st_nlink: nlink_t
st_mode: mode_t
st_uid: uid_t
st_gid: gid_t
__pad0: INT
st_rdev: dev_t
st_size: off_t
st_blksize: blksize_t
st_blocks: blkcnt_t
st_atim_sec: time_t
st_atim_nsec: LONGLONG
st_mtim_sec: time_t
st_mtim_nsec: LONGLONG
st_ctim_sec: time_t
st_ctim_nsec: LONGLONG
__unused0: LONGLONG
__unused1: LONGLONG
__unused2: LONGLONG
class Dirent:
d_ino: ino_t
d_off: off_t
d_reclen: USHORT
d_type: BYTE
d_name: CHARPTR
def open(path: t.CConst | str, oflag: INT, *args) -> INT | t.State: pass
def close(fd: INT) -> INT | t.State: pass
def read(fd: INT, buf: bytes, count: t.CSizeT) -> ssize_t | t.State: pass
def write(fd: INT, buf: t.CConst | bytes, count: t.CSizeT) -> ssize_t | t.State: pass
def lseek(fd: INT, offset: off_t, whence: INT) -> off_t | t.State: pass
def unlink(path: t.CConst | str) -> INT | t.State: pass
def access(path: t.CConst | str, amode: INT) -> INT | t.State: pass
def realpath(path: t.CConst | str, resolved: CHARPTR) -> CHARPTR | t.State: pass
def rename(oldpath: t.CConst | str, newpath: t.CConst | str) -> INT | t.State: pass
def chmod(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass
def stat(path: t.CConst | str, buf: Stat | t.CPtr) -> INT | t.State: pass
def fstat(fd: INT, buf: Stat | t.CPtr) -> INT | t.State: pass
def opendir(name: t.CConst | str) -> DIR | t.CPtr | t.State: pass
def readdir(dirp: DIR | t.CPtr) -> Dirent | t.CPtr | t.State: pass
def closedir(dirp: DIR | t.CPtr) -> INT | t.State: pass
def mkdir(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass
def rmdir(path: t.CConst | str) -> INT | t.State: pass
def getcwd(buf: CHARPTR, size: t.CSizeT) -> CHARPTR | t.State: pass
def chdir(path: t.CConst | str) -> INT | t.State: pass
def fork() -> pid_t | t.State: pass
def execvp(file: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass
def execv(path: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass
def waitpid(pid: pid_t, status: INT | t.CPtr, options: INT) -> pid_t | t.State: pass
def pipe(fds: INT | t.CPtr) -> INT | t.State: pass
def dup2(oldfd: INT, newfd: INT) -> INT | t.State: pass
def _exit(status: INT) -> t.CVoid | t.State: pass
def getpid() -> pid_t | t.State: pass
def getenv(name: t.CConst | str) -> CHARPTR | t.State: pass
def setenv(name: t.CConst | str, value: t.CConst | str, overwrite: INT) -> INT | t.State: pass
def sysconf(name: INT) -> LONG | t.State: pass
def isatty(fd: INT) -> INT | t.State: pass
def S_ISREG(mode: mode_t) -> bool: pass
def S_ISDIR(mode: mode_t) -> bool: pass
def S_ISLNK(mode: mode_t) -> bool: pass
def S_ISCHR(mode: mode_t) -> bool: pass
def S_ISBLK(mode: mode_t) -> bool: pass
def S_ISFIFO(mode: mode_t) -> bool: pass
def S_ISSOCK(mode: mode_t) -> bool: pass
def WIFEXITED(status: INT) -> bool: pass
def WEXITSTATUS(status: INT) -> INT: pass
def WIFSIGNALED(status: INT) -> bool: pass
def WTERMSIG(status: INT) -> INT: pass

View File

@@ -1,28 +0,0 @@
"""
Auto-generated Python stub file from stdio.py
Module: stdio
"""
import t, c
def printf(fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> t.CInt | t.State: pass
def puts(s: t.CConst | str) -> t.CInt | t.State: pass
def fputs(s: t.CConst | str, stream: bytes) -> t.CInt | t.State: pass
def fgets(buf: bytes, size: t.CInt, stream: bytes) -> bytes | t.State: pass
def fflush(stream: bytes) -> t.CInt | t.State: pass
stdin: t.CExtern | bytes
stdout: t.CExtern | bytes
stderr: t.CExtern | bytes

View File

@@ -1,20 +0,0 @@
"""
Auto-generated Python stub file from stdlib.py
Module: stdlib
"""
import c
from stdint import *
import t
def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
def free(p: t.CVoid | t.CPtr) -> t.State: pass
def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass

View File

@@ -1,53 +0,0 @@
"""
Auto-generated Python stub file from platmacro.py
Module: platmacro
"""
import t, c
IS_WINDOWS: t.CDefine = 1
IS_WIN64: t.CDefine = 1
IS_X86_64: t.CDefine = 1
IS_LP64: t.CDefine = 1
IS_LITTLE_ENDIAN: t.CDefine = 1
IS_LINUX: t.CDefine = 0
IS_MACOS: t.CDefine = 0
IS_ARM64: t.CDefine = 0
IS_BIG_ENDIAN: t.CDefine = 0
IS_ILP32: t.CDefine = 0
PTR_SIZE: t.CDefine = t.CSizeT().Size
INT_SIZE: t.CDefine = 4
LONG_SIZE: t.CDefine = t.CLong().Size
WORD_SIZE: t.CDefine = t.CSizeT().Size
CACHE_LINE_SIZE: t.CDefine = 64
PAGE_SIZE: t.CDefine = 4096
STACK_ALIGN: t.CDefine = 16
MAX_PATH_LEN: t.CDefine = 260
PLATFORM_NAME: t.CDefine = 1
ARCH_NAME: t.CDefine = 1
WINVER: t.CDefine = 0x0A00
_WIN32_WINNT: t.CDefine = 0x0A00
NTDDI_VERSION: t.CDefine = 0x0A000006
HAS_SSE2: t.CDefine = 1
HAS_AVX: t.CDefine = 1
HAS_AVX2: t.CDefine = 1
HAS_FMA: t.CDefine = 1
HAS_NEON: t.CDefine = 0
ALIGNOF_INT: t.CDefine = 4
ALIGNOF_LONG: t.CDefine = t.CLong().Size // 8
ALIGNOF_PTR: t.CDefine = t.CSizeT().Size // 8
ALIGNOF_DOUBLE: t.CDefine = 8
ALIGNOF_LONG_DOUBLE: t.CDefine = 16
SIZEOF_SHORT: t.CDefine = 2
SIZEOF_INT: t.CDefine = 4
SIZEOF_LONG: t.CDefine = t.CLong().Size // 8
SIZEOF_LONG_LONG: t.CDefine = 8
SIZEOF_FLOAT: t.CDefine = 4
SIZEOF_DOUBLE: t.CDefine = 8
SIZEOF_LONG_DOUBLE: t.CDefine = 16
SIZEOF_POINTER: t.CDefine = t.CSizeT().Size // 8
SIZEOF_SIZE_T: t.CDefine = t.CSizeT().Size // 8
SIZEOF_PTRDIFF_T: t.CDefine = t.CPtrDiffT().Size // 8
BYTE_ORDER_LE: t.CDefine = 1
BYTE_ORDER_BE: t.CDefine = 0

File diff suppressed because one or more lines are too long

View File

@@ -1,80 +1,80 @@
067c78e9f121dce3:includes/w32\win32process.py
06f53cc594b4ac6c:includes/w32\win32sync.py
0c9a196ed8f137a8:includes/llvmlite\__function.py
0c67644125bea0fd:includes/sys.py
0df65b8ed15664b0:includes/hashlib\__sha1.py
1073ffca7e27aae5:lib/core/Handles/HandlesFunctions.py
134678d620920327:lib/core/Handles/HandlesImports.py
15bb32adb7093ed7:lib/core/Handles/HandlesAnnAssign.py
19f8024d10c828e8:includes/hashlib\__md5.py
1d74d1d3a174c684:includes/llvmlite\__init__.py
20cd49775c100a38:includes/json\__writer.py
22bc0df83b3f0e62:includes/ast\base.py
240a9a4157959a9f:includes/json\__parser.py
2703a899f26b771d:lib/core/Handles/HandlesReturn.py
271ea3decb810db2:includes/atom.py
2d39c6c7d3557b3e:includes/linkedlist.py
285b6aa29a34754d:includes/stdio.py
28de517e3820658a:includes/posix.py
2b59175b77f1304e:lib/core/Handles/HandlesAssign.py
2d523679d6b886ad:lib/core/Phase1.py
2d8debefda779c40:includes/llvmlite\__types.py
2da636c61863c815:includes/subprocess.py
2fbec3db55b30ad4:includes/hashtable.py
31e49accebfc8aac:lib/core/Handles/HandlesAugAssign.py
36f17e746044defb:lib/core/Handles/HandlesType.py
3a8870350b3cb1f7:lib/core/Handles/HandlesStruct.py
371fa89e15d8c015:lib/core/Handles/HandlesStruct.py
3aa6057398be5673:includes/stdlib.py
3c5f1c61545644a9:lib/StubGen/Converter.py
4337fb260448bbe2:includes/ast\astaux.py
456fb516ba3c5002:lib/core/Handles/HandlesFor.py
4650533467115342:lib/Projectrans/Utils.py
4a7b57e6bd18f65e:lib/core/Handles/HandlesMain.py
4daf5ed3f8e421a1:includes/string.py
4dd6b3f1427d1cc5:includes/ast\match.py
518fd98d3ebec951:lib/core/BuildPipeline.py
51f0144d6e8188d9:lib/core/Handles/HandlesWhile.py
57288496f7c2d1ad:includes/json\__init__.py
5a1d8c48f1243746:includes/llvmlite\__builder.py
5c482c6aac2ba83b:lib/core/Handles/HandlesExprCall.py
62805d8ad3e9b5ba:lib/core/Handles/HandlesTranslator.py
6282c9b745a35b8f:lib/core/IncludesScanner.py
6293eee0a5805aa5:lib/core/Handles/HandlesImports.py
63a3d17e96a083ac:lib/core/Handles/HandlesBase.py
647c596aeb1fd27c:lib/core/Handles/HandlesExprCall.py
6503c97dde0c79c4:includes/posix.py
657e182b27c2a022:includes/ast\stmts.py
668790e6c9efdbae:includes/_list.py
66de93aaeebc0601:lib/core/Handles/HandlesIf.py
68f2617198f5757f:lib/core/Handles/HandlesExpr.py
692919c5a194ac8d:includes/llvmlite\__module.py
6a19179426e9a883:lib/__init__.py
6b3bc463fd044545:includes/llvmlite\__verify.py
6be4daa5dc5fa7ce:includes/string.py
6d88e12d1fb0efee:lib/core/Phase2.py
6f62fe05c5ea1ceb:includes/stdio.py
6ff26590374ae6fc:includes/hashlib\__sha512.py
71e0a3ffcb3ebfad:includes/stdarg.py
727a218636fc49ab:lib/core/Handles/HandlesFor.py
72dbbb563aa943b0:includes/w32\fileio.py
7ba06a9edf0fa6c7:lib/core/Phase2.py
7cadfe07e983fd90:includes/_list.py
81eb28ba912467a6:lib/core/Handles/HandlesBody.py
88811298a7b47d02:lib/core/Handles/HandlesMain.py
8cf4461e82a4ecf2:lib/core/Handles/HandlesAssign.py
90c53dd6db8d41cf:includes/stdlib.py
93c1d18e35d188d6:includes/platmacro.py
874bac141c97bae9:includes/llvmlite\__function.py
96837bcc64032444:includes/hashlib\__init__.py
a299b2ce21d25f48:lib/StubGen/Converter.py
adde71d4f0a1f628:includes/llvmlite\__builder.py
a335eb99f2e34479:includes/subprocess.py
a5e9a83e9db303ad:includes/linkedlist.py
aa45364399b86a03:lib/core/Handles/HandlesClassDef.py
af1cc6aaab47a7d1:lib/core/Handles/HandlesType.py
af9484a65085bf4b:lib/core/Handles/HandlesNonlocal.py
b4d2098ceb689168:includes/ast\parser.py
b370d93b74bf55cc:includes/argparse.py
b543bc1dfb592119:includes/ast\exprs.py
b547ac4f380bddb6:includes/ast\tokens.py
b5a965302cded36b:includes/sys.py
b8c66c8ff44eb874:includes/hashtable.py
ba2b074357dcd3b5:includes/memhub.py
b57252077e6b596b:includes/platmacro.py
bbdf3bbd4c3bc28c:includes/w32\win32console.py
bdf5730851fb95f2:lib/core/VLogger.py
be8c2d7b882881c8:lib/core/Handles/HandlesExprOps.py
bfa1cc81748c0271:lib/core/Handles/HandlesClassDef.py
c0042adc0b7ec5df:lib/Projectrans/Config.py
c2010cffc6092ea2:main.py
c3b259b4059f8668:includes/viperlib.py
c6b0b8148dc63d5c:lib/core/Handles/HandlesExpr.py
c9d54a4158f7f5a8:includes/hashlib\__sha256.py
c9f4be41ca1cc2b4:includes/viperio.py
ca44e2bae615339f:includes/argparse.py
ca40915f11b8b6ad:includes/memhub.py
cae1b2c5898ed6e5:lib/core/StubMerger.py
cb1aa3a78af6f362:lib/core/Handles/HandlesVar.py
dda2d0326dda1ff5:lib/core/Handles/HandlesAnnAssign.py
e217def267d3d4a8:includes/ast\lexer.py
ec8cf4a355eb1a65:lib/core/Phase1.py
ede1b9cd3f28e8c8:lib/core/StubMerger.py
e307a2d809cef071:includes/viperlib.py
e991626c0aee9d7b:lib/core/BuildPipeline.py
f05b14a2ad5767a7:lib/core/Handles/HandlesEnum.py
f1e8dabe2ec63f05:lib/core/VLogger.py
f23f91ad42cb466f:includes/llvmlite\__init__.py
f331c46316ec1dd3:lib/core/Handles/HandlesTranslator.py
f3444ec56937284f:includes/ast\__init__.py
f5522571bcce7bcb:includes/stdint.py
f6b51804a0ba8ff0:includes/w32\win32file.py
f9e36e2cd6fa659f:includes/llvmlite\__values.py
fc980acec33d69a7:includes/w32\win32base.py
fde6db0747bdd959:includes/ast\parser.py

Binary file not shown.

View File

@@ -1,44 +0,0 @@
"""
Auto-generated Python stub file from sys.py
Module: sys
"""
import t, c
from stdint import *
import platmacro
import memhub
import string
import stdio
import w32.win32base
import w32.win32process
import posix
_mbuddy: t.CExtern | memhub.MemBuddy | t.CPtr
def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass
def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass
def exit(status: INT) -> VOID | t.CExtern | t.CExport: pass
maxsize: t.CDefine = 9223372036854775807
def platform() -> str: pass
def get_pid() -> int: pass
_argc: t.CExtern | INT
_argv: t.CExtern | str | t.CPtr
def _init_argv() -> t.CInt: pass
def _init_argv_win32() -> t.CInt: pass
def _init_argv_posix() -> t.CInt: pass
def argc() -> int: pass
def argv(index: int) -> str: pass

View File

@@ -1,46 +0,0 @@
"""
Auto-generated Python stub file from hashtable.py
Module: hashtable
"""
import t, c
import string
import memhub
from stdint import *
_HT_EMPTY: t.CDefine = 0
_HT_TOMBSTONE: t.CDefine = 1
_HT_INIT_CAP: t.CDefine = 16
_HT_SLOT_SIZE: t.CDefine = 24
_FNV_OFFSET: t.CExtern | t.CUInt64T
_FNV_PRIME: t.CExtern | t.CUInt64T
def _fnv1a_hash(key: str) -> t.CUInt64T: pass
class HashTable:
__slots__: t.CVoid | t.CPtr
__count__: t.CSizeT = 0
__capacity__: t.CSizeT = 16
__tombstones__: t.CSizeT = 0
__mbuddy__: memhub.MemBuddy | t.CPtr
__iter_index__: t.CSizeT = 0
def __new__(self: HashTable, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr: pass
def __init__(self: HashTable, mb: memhub.MemBuddy | t.CPtr) -> t.CInt: pass
def _slot_hash(self: HashTable, idx: t.CSizeT) -> t.CUInt64T: pass
def _slot_key(self: HashTable, idx: t.CSizeT) -> str: pass
def _slot_value(self: HashTable, idx: t.CSizeT) -> t.CPtr: pass
def _set_slot(self: HashTable, idx: t.CSizeT, h: t.CUInt64T, key: str, val: t.CPtr) -> t.CInt: pass
def _find_slot(self: HashTable, key: str, h: t.CUInt64T) -> t.CSizeT: pass
def _resize(self: HashTable, new_cap: t.CSizeT) -> t.CInt: pass
def __setitem__(self: HashTable, key: str, val: t.CNeedPtr) -> t.CInt: pass
def __getitem__(self: HashTable, key: str) -> t.CPtr: pass
def __contains__(self: HashTable, key: str) -> t.CInt: pass
def __delitem__(self: HashTable, key: str) -> t.CInt: pass
def __len__(self: HashTable) -> t.CSizeT: pass
def __iter__(self: HashTable) -> HashTable | t.CPtr: pass
def __next__(self: HashTable) -> str: pass
def get(self: HashTable, key: str, default: t.CPtr) -> t.CPtr: pass
def set_int(self: HashTable, key: str, val: int) -> t.CInt: pass
def set_str(self: HashTable, key: str, val: str) -> t.CInt: pass

View File

@@ -1,23 +0,0 @@
"""
Auto-generated Python stub file from viperlib.py
Module: viperlib
"""
import t, c
import viperio
from stdarg import arg, va_arg
TEMP_BUF_SIZE: t.CDefine = 68
def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt: pass
def sprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CVoid | t.CExport: pass
def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt: pass
def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt | t.CExport: pass
def _check_special_float(fv: t.CDouble) -> t.CInt: pass
def vsnprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) -> t.CInt | t.CExport: pass

View File

@@ -464,7 +464,11 @@ def release(args: ParsedArgs | t.CPtr):
if args.__mbuddy__ is None:
return
if args._ht is not None:
if args._ht.__slots__ is not None:
args.__mbuddy__.free(args._ht.__slots__)
args.__mbuddy__.free(t.CVoid(t.CUInt64T(args._ht), t.CPtr))
# 用临时变量拆分链式属性访问,避免 args._ht.__slots__ 跨模块类型推断失败
# 注意:类型注解必须用 hashtable.HashTable带模块前缀
# 否则编译器无法解析 HashTable 类型,导致 ht.__slots__ 属性访问失败
ht: hashtable.HashTable | t.CPtr = args._ht
if ht.__slots__ is not None:
args.__mbuddy__.free(ht.__slots__)
args.__mbuddy__.free(t.CVoid(t.CUInt64T(ht), t.CPtr))
args.__mbuddy__.free(t.CVoid(t.CUInt64T(args), t.CPtr))

View File

@@ -1740,7 +1740,7 @@ def _parse_if(ps: Parser | t.CPtr) -> AST | t.CPtr:
_expect_op(ps, TokOp.Colon)
# 先用空 orelse 构造,后面填充
empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
node: AST | t.CPtr = If(ps.pool, test, empty)
node: If | t.CPtr = If(ps.pool, test, empty)
_parse_suite_into_children(ps, node)
orelse: list[AST | t.CPtr] | t.CPtr = _parse_if_tail(ps)
node.orelse = orelse
@@ -1761,7 +1761,7 @@ def _parse_if_tail(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr:
elif_test: AST | t.CPtr = _parse_test(ps)
_expect_op(ps, TokOp.Colon)
empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
elif_node: AST | t.CPtr = If(ps.pool, elif_test, empty)
elif_node: If | t.CPtr = If(ps.pool, elif_test, empty)
_parse_suite_into_children(ps, elif_node)
elif_orelse: list[AST | t.CPtr] | t.CPtr = _parse_if_tail(ps)
elif_node.orelse = elif_orelse
@@ -1789,7 +1789,7 @@ def _parse_while(ps: Parser | t.CPtr) -> AST | t.CPtr:
test: AST | t.CPtr = _parse_test(ps)
_expect_op(ps, TokOp.Colon)
empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
node: AST | t.CPtr = While(ps.pool, test, empty)
node: While | t.CPtr = While(ps.pool, test, empty)
_parse_suite_into_children(ps, node)
if _cur_kw(ps) == Keyword.Else:
_advance(ps)
@@ -1813,7 +1813,7 @@ def _parse_for(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr:
iter_: AST | t.CPtr = _parse_or_test(ps)
_expect_op(ps, TokOp.Colon)
empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
node: AST | t.CPtr = For(ps.pool, target, iter_, empty, is_async)
node: For | t.CPtr = For(ps.pool, target, iter_, empty, is_async)
_fix_store_ctx(target)
_parse_suite_into_children(ps, node)
if _cur_kw(ps) == Keyword.Else:
@@ -1832,7 +1832,7 @@ def _parse_try(ps: Parser | t.CPtr) -> AST | t.CPtr:
_advance(ps) # try
_expect_op(ps, TokOp.Colon)
empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
node: AST | t.CPtr = Try(ps.pool, empty, empty, empty)
node: Try | t.CPtr = Try(ps.pool, empty, empty, empty)
_parse_suite_into_children(ps, node)
# handlers (except)
handlers: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8)
@@ -1895,7 +1895,7 @@ def _parse_with(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr:
if _cur_type(ps) == TokenType.NewLine or _cur_type(ps) == TokenType.Nl:
break
_expect_op(ps, TokOp.Colon)
node: AST | t.CPtr = With(ps.pool, items, is_async)
node: With | t.CPtr = With(ps.pool, items, is_async)
_parse_suite_into_children(ps, node)
_set_pos(node, lineno, col, 0, 0)
return node
@@ -1936,7 +1936,7 @@ def _parse_funcdef(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr:
_expect_op(ps, TokOp.Colon)
dec_list: list[AST | t.CPtr] | t.CPtr = ps.pending_decorators
ps.pending_decorators = None
node: AST | t.CPtr = FunctionDef(ps.pool, name, args, dec_list, returns, is_async)
node: FunctionDef | t.CPtr = FunctionDef(ps.pool, name, args, dec_list, returns, is_async)
_parse_suite_into_children(ps, node)
_set_pos(node, lineno, col, 0, 0)
return node
@@ -1991,7 +1991,7 @@ def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr:
_expect_op(ps, TokOp.Colon)
dec_list: list[AST | t.CPtr] | t.CPtr = ps.pending_decorators
ps.pending_decorators = None
node: AST | t.CPtr = ClassDef(ps.pool, name, bases, keywords, dec_list, type_params)
node: ClassDef | t.CPtr = ClassDef(ps.pool, name, bases, keywords, dec_list, type_params)
_parse_suite_into_children(ps, node)
_set_pos(node, lineno, col, 0, 0)
return node
@@ -2380,6 +2380,6 @@ def parse_tokens(pool: memhub.MemManager | t.CPtr,
ps: Parser | t.CPtr = new_parser(pool)
if ps is None: return None
_parser_init(ps, tokens, pool)
module_node: AST | t.CPtr = Module(pool)
module_node: Module | t.CPtr = Module(pool)
_parse_module_body(ps, module_node)
return module_node

View File

@@ -13,9 +13,8 @@ def __atomic_test_and_set(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> t.CBool:
result: t.CUInt8T = 1
c.Asm(f"""mov al, 1
xchg byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], al
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, al""",
mov $0, al""",
out = [c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)],
inp = [c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)],
op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return t.CBool(result)

View File

@@ -7,7 +7,7 @@ import stdio
from linkedlist import GSListNode, GSList
from .__types import LLVMType, TypePrint
from .__values import Value, new_value, SSAValue
from .__function import Function, BasicBlock, block_append_text, function_move_block_to_end, _ll_name_needs_quote
from .__function import Function, BasicBlock, block_append_text, block_set_terminated, block_get_terminated, function_move_block_to_end, _ll_name_needs_quote
# ============================================================
# IRBuilder: 游标式 IR 指令发射器
@@ -104,20 +104,19 @@ def _emit(builder: IRBuilder | t.CPtr, text: t.CChar | t.CPtr):
def _mark_terminated(builder: IRBuilder | t.CPtr):
"""标记当前块已终止"""
if builder is None or builder.CurBlock is None: return
builder.CurBlock.IsTerminated = 1
block_set_terminated(builder.CurBlock, 1)
def builder_cur_block_is_terminated(builder: IRBuilder | t.CPtr) -> t.CInt:
"""检查当前块的 IsTerminated 标志
供其他模块绕过 stub 类型限制使用:
builder.CurBlock.IsTerminated 在 stub 类型中 BasicBlock 为 opaque
直接访问会被 TransPyC 静默跳过(不生成 GEP不报错
导致返回寄存器残留值br 回边指令被错误跳过。
通过 block_get_terminated 辅助函数访问,避免链式属性
builder.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque
导致的 GEP 静默跳过问题。
"""
if builder is None or builder.CurBlock is None:
return 1
return builder.CurBlock.IsTerminated
return block_get_terminated(builder.CurBlock)
# ============================================================

View File

@@ -218,6 +218,19 @@ def block_append_line(block: BasicBlock | t.CPtr, line: Line | t.CPtr):
block.Lines.append(line)
def block_set_terminated(block: BasicBlock | t.CPtr, val: t.CInt):
"""设置块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)"""
if block is None: return
block.IsTerminated = val
def block_get_terminated(block: BasicBlock | t.CPtr) -> t.CInt:
"""获取块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)"""
if block is None:
return 1
return block.IsTerminated
def block_append_text(pool: memhub.MemBuddy | t.CPtr, block: BasicBlock | t.CPtr,
text: t.CChar | t.CPtr):
"""创建指令行并追加到基本块"""