Fixed
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
2
TODO
2
TODO
@@ -34,3 +34,5 @@ __iter__ 期望 for a, b in __iter__
|
||||
init_set 构造
|
||||
|
||||
不在乎编译器时间的大小优化(无关符号剔除)
|
||||
给 linkedlist 库改成 node 库,或者拆分 linkedlist 库
|
||||
TPV 的 typedef 名是硬编码的,后期尝试修正
|
||||
BIN
TransPyV.exe.bak
BIN
TransPyV.exe.bak
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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:
|
||||
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,
|
||||
"rhs_val is None [sha1=%s lineno=%d kind=%d]",
|
||||
sha1, val_line, val_kind)
|
||||
"赋值右侧为 None: %s:%d '%s.%s' 属性访问失败",
|
||||
rel_path, val_line, target_nm, attr_nm)
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"rhs_val is None [lineno=%d kind=%d]",
|
||||
val_line, val_kind)
|
||||
"赋值右侧为 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:
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
# 兜底: 创建外部全局 @_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)
|
||||
# 创建外部全局 @_mbuddy(external 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)
|
||||
|
||||
# 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6)
|
||||
# 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中,
|
||||
# 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules
|
||||
if mod_name_raw is None:
|
||||
stdio.printf("[XMCD] FAIL name=%s reason=lookup_from_import_returned_none\n", name)
|
||||
# from_imports 完全没有匹配(精确和 star 都失败)
|
||||
# 直接进入 imported_modules 遍历(步骤 9.6)
|
||||
if imported_modules is None:
|
||||
return -1
|
||||
# 跳过 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
|
||||
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)
|
||||
|
||||
# 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,8 +2351,31 @@ 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:
|
||||
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)
|
||||
@@ -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 可能是 i8(X|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 可能是 i8,ensure 无效)
|
||||
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 可能是 i8(X|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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
# 解析初始值(支持整数、列表字面量、字符串字面量)
|
||||
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
|
||||
has_init = 1
|
||||
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:
|
||||
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
|
||||
has_init = 1
|
||||
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"
|
||||
|
||||
@@ -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(包含正确的 Ty),None=未找到
|
||||
"""
|
||||
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 类型
|
||||
# ============================================================
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(必须是整数常量、None 或 CDefine 常量名)
|
||||
# 解析 count(支持整数常量、None、CDefine 常量名、常量表达式如 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)
|
||||
|
||||
@@ -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 1a(struct 注册)之前执行,确保所有泛型类模板
|
||||
#(如 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 路径翻译方法体)
|
||||
|
||||
@@ -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/union(declare_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
|
||||
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:
|
||||
# 按需编译过滤:只处理 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
|
||||
viperlib.snprintf(check_pat_mi, ibd_len_mi + 35, "%s/%s*.obj", includes_binary_dir, inc_sha1_mi)
|
||||
# 检查 .obj 是否已存在于 includes.binary(切片子目录)
|
||||
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
|
||||
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 == 1);text.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
|
||||
|
||||
# 尝试 BuildCombinedIR(stub/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_buf(Phase 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_set(Phase 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,
|
||||
|
||||
@@ -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 文件的 SHA1(16字符)
|
||||
# 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 文件的 SHA1(16字符)
|
||||
#
|
||||
# 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,12 +1419,32 @@ 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 文件,收集直接依赖
|
||||
# 工作列表(空格分隔的模块名)
|
||||
worklist: bytes = stdlib.malloc(8192)
|
||||
if worklist is None:
|
||||
stdlib.free(sha1_arr)
|
||||
stdlib.free(mod_arr)
|
||||
return -1
|
||||
worklist[0] = '\0'
|
||||
wl_len: t.CSizeT = 0
|
||||
|
||||
reachable_count: int = 0
|
||||
|
||||
# 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)
|
||||
|
||||
@@ -1308,28 +1454,16 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
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)
|
||||
|
||||
# 工作列表(空格分隔的模块名)
|
||||
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
|
||||
worklist[0] = '\0'
|
||||
wl_len: t.CSizeT = 0
|
||||
|
||||
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")
|
||||
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)
|
||||
@@ -1383,6 +1517,12 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
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)
|
||||
@@ -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:
|
||||
# 从内存查找依赖(不读 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_buf)
|
||||
string.strcpy(worklist + wl_len, deps_str)
|
||||
wl_len = wl_len + dl
|
||||
worklist[wl_len] = ' '
|
||||
wl_len = wl_len + 1
|
||||
worklist[wl_len] = '\0'
|
||||
stdlib.free(deps_buf)
|
||||
# deps_str 为空字符串视为无依赖(合法情况,如叶子模块)
|
||||
else:
|
||||
df.close()
|
||||
stdlib.free(deps_path)
|
||||
# 依赖未在内存中找到
|
||||
# 按需过滤: 检查是否是 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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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.
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -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):
|
||||
"""创建指令行并追加到基本块"""
|
||||
|
||||
Reference in New Issue
Block a user