fix(Phase2): Phase A 多遍重试修复同项目依赖翻译顺序
main.vp 先于其 import 的 mbuddytest.vp 翻译(文件系统顺序),跨模块函数返回类型精确解析因依赖 text.ll 未生成而 fail-fast。新增 Translator._deps_pending + text.ll 存在性探测区分依赖未翻译/真错误,Phase A 循环改多遍,依赖就绪后下遍重译命中。
This commit is contained in:
1 parent
b5657b3790
commit
120a2d7ad7
3 files changed
+314
-82
No files matched your search
@@ -243,6 +243,13 @@ class CallGenMixin:
|
|||||||
# 第二遍:后缀匹配(.name)
|
# 第二遍:后缀匹配(.name)
|
||||||
# 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到
|
# 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到
|
||||||
# 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名
|
# 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名
|
||||||
|
#
|
||||||
|
# 修复:本模块 define 优先于跨模块 stub declare。
|
||||||
|
# 根因:跨模块同名函数(如 lexer.vp 的 _advance 与 parser.vp 的 _advance)
|
||||||
|
# 的 stub declare 在 stub 注入时排在 FuncHead 前面,裸名调用 _advance 后缀
|
||||||
|
# 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被
|
||||||
|
# bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针,
|
||||||
|
# cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。
|
||||||
cur = mod.FuncHead
|
cur = mod.FuncHead
|
||||||
while cur is not None:
|
while cur is not None:
|
||||||
cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
|
cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
|
||||||
@@ -257,6 +264,24 @@ class CallGenMixin:
|
|||||||
match = 0
|
match = 0
|
||||||
break
|
break
|
||||||
if match == 1:
|
if match == 1:
|
||||||
|
if cur.IsDeclared == 0:
|
||||||
|
return cur
|
||||||
|
cur = llvmlite.function_get_next(cur)
|
||||||
|
# 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用)
|
||||||
|
cur = mod.FuncHead
|
||||||
|
while cur is not None:
|
||||||
|
cur_name3: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
|
||||||
|
if cur_name3 is not None:
|
||||||
|
cur_len3: t.CSizeT = string.strlen(cur_name3)
|
||||||
|
if cur_len3 > name_len + 1:
|
||||||
|
suffix_start3: t.CSizeT = cur_len3 - name_len
|
||||||
|
if cur_name3[suffix_start3 - 1] == '.':
|
||||||
|
match3: int = 1
|
||||||
|
for i in range(name_len):
|
||||||
|
if cur_name3[suffix_start3 + i] != name[i]:
|
||||||
|
match3 = 0
|
||||||
|
break
|
||||||
|
if match3 == 1:
|
||||||
return cur
|
return cur
|
||||||
cur = llvmlite.function_get_next(cur)
|
cur = llvmlite.function_get_next(cur)
|
||||||
return None
|
return None
|
||||||
@@ -564,6 +589,28 @@ class CallGenMixin:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _is_sha1_mangled_call(self, call_name: str) -> int:
|
||||||
|
"""判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式)
|
||||||
|
|
||||||
|
C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0,
|
||||||
|
不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。
|
||||||
|
"""
|
||||||
|
if call_name is None:
|
||||||
|
return 0
|
||||||
|
first_dot: t.CChar | t.CPtr = string.strchr(call_name, '.')
|
||||||
|
if first_dot is None:
|
||||||
|
return 0
|
||||||
|
pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name))
|
||||||
|
if pre_len != 16:
|
||||||
|
return 0
|
||||||
|
for hx in range(16):
|
||||||
|
ch: int = call_name[hx]
|
||||||
|
if ch < 48 or ch > 57:
|
||||||
|
if ch < 97 or ch > 102:
|
||||||
|
if ch < 65 or ch > 70:
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
|
||||||
def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr,
|
def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr,
|
||||||
builder: llvmlite.IRBuilder | t.CPtr,
|
builder: llvmlite.IRBuilder | t.CPtr,
|
||||||
mod: llvmlite.LLVMModule | t.CPtr,
|
mod: llvmlite.LLVMModule | t.CPtr,
|
||||||
@@ -2917,9 +2964,14 @@ class CallGenMixin:
|
|||||||
def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr,
|
def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr,
|
||||||
class_sha1: str,
|
class_sha1: str,
|
||||||
class_name: str,
|
class_name: str,
|
||||||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
method_name: str,
|
||||||
"""从依赖模块的 text.ll 中查找方法返回类型"""
|
use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr:
|
||||||
if pool is None or class_sha1 is None or class_name is None or method_name is None:
|
"""从依赖模块的 text.ll 中查找方法返回类型
|
||||||
|
|
||||||
|
use_bare: 1=按模块级函数查找(搜索 "{sha1}.{method_name}" define,
|
||||||
|
用于 new_lexer/tokenize 等模块函数;class_name 忽略)。
|
||||||
|
"""
|
||||||
|
if pool is None or class_sha1 is None or method_name is None:
|
||||||
return None
|
return None
|
||||||
if self.TempDir is None or self.TempDirLen == 0:
|
if self.TempDir is None or self.TempDirLen == 0:
|
||||||
return None
|
return None
|
||||||
@@ -2968,16 +3020,24 @@ class CallGenMixin:
|
|||||||
else:
|
else:
|
||||||
read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0'
|
read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0'
|
||||||
|
|
||||||
# 构造搜索模式: "{sha1}.{class_name}.{method_name}"
|
# 构造搜索模式: "{sha1}.{class_name}.{method_name}" 或 bare 模式 "{sha1}.{method_name}"
|
||||||
cls_len: t.CSizeT = string.strlen(class_name)
|
cls_len: t.CSizeT = 0
|
||||||
|
if class_name is not None:
|
||||||
|
cls_len = string.strlen(class_name)
|
||||||
meth_len: t.CSizeT = string.strlen(method_name)
|
meth_len: t.CSizeT = string.strlen(method_name)
|
||||||
search_len: t.CSizeT = sha1_len + cls_len + meth_len + 4
|
search_len: t.CSizeT = sha1_len + meth_len + 2
|
||||||
|
if use_bare == 0:
|
||||||
|
search_len = sha1_len + cls_len + meth_len + 4
|
||||||
search_buf: bytes = stdlib.malloc(search_len)
|
search_buf: bytes = stdlib.malloc(search_len)
|
||||||
if search_buf is None:
|
if search_buf is None:
|
||||||
stdlib.free(read_buf)
|
stdlib.free(read_buf)
|
||||||
return None
|
return None
|
||||||
viperlib.snprintf(search_buf, search_len, "%s.%s.%s",
|
if use_bare != 0:
|
||||||
class_sha1, class_name, method_name)
|
viperlib.snprintf(search_buf, search_len, "%s.%s",
|
||||||
|
class_sha1, method_name)
|
||||||
|
else:
|
||||||
|
viperlib.snprintf(search_buf, search_len, "%s.%s.%s",
|
||||||
|
class_sha1, class_name, method_name)
|
||||||
search_str_len: t.CSizeT = string.strlen(search_buf)
|
search_str_len: t.CSizeT = string.strlen(search_buf)
|
||||||
|
|
||||||
# 在 text.ll 中搜索 define 行包含 search_buf
|
# 在 text.ll 中搜索 define 行包含 search_buf
|
||||||
@@ -3010,8 +3070,15 @@ class CallGenMixin:
|
|||||||
# 检查是否匹配 search_buf
|
# 检查是否匹配 search_buf
|
||||||
if name_start + search_str_len <= ls + ll:
|
if name_start + search_str_len <= ls + ll:
|
||||||
if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0:
|
if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0:
|
||||||
# 匹配!提取返回类型: [ls+7, at_pos)
|
# 函数名边界检查:search 后必须是 '"'(带引号名)、'('(参数表)或行尾,
|
||||||
result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos)
|
# 否则 "sha1.func" 会误匹配 "sha1.func_helper" 等前缀同名函数
|
||||||
|
name_end: t.CSizeT = name_start + search_str_len
|
||||||
|
end_ch: int = 0
|
||||||
|
if name_end < ls + ll:
|
||||||
|
end_ch = read_buf[name_end]
|
||||||
|
if end_ch == 34 or end_ch == 40 or end_ch == 0:
|
||||||
|
# 匹配!提取返回类型: [ls+7, at_pos)
|
||||||
|
result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos)
|
||||||
|
|
||||||
pos = le + 1
|
pos = le + 1
|
||||||
|
|
||||||
@@ -3019,6 +3086,45 @@ class CallGenMixin:
|
|||||||
stdlib.free(read_buf)
|
stdlib.free(read_buf)
|
||||||
return result_ty
|
return result_ty
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成
|
||||||
|
#
|
||||||
|
# 用于区分跨模块返回类型精确解析失败的两种场景:
|
||||||
|
# 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失)
|
||||||
|
# 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译,
|
||||||
|
# main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍
|
||||||
|
# ============================================================
|
||||||
|
def _dep_text_ll_exists(self, pool: memhub.MemBuddy | t.CPtr,
|
||||||
|
sha1: str) -> int:
|
||||||
|
"""探测 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll 是否存在,1=存在"""
|
||||||
|
if self.TempDir is None or self.TempDirLen == 0 or sha1 is None:
|
||||||
|
return 0
|
||||||
|
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||||
|
if sha1_len < 2:
|
||||||
|
return 0
|
||||||
|
path_len: t.CSizeT = self.TempDirLen + sha1_len + 14
|
||||||
|
path_buf: bytes = stdlib.malloc(path_len)
|
||||||
|
subdir_buf: bytes = stdlib.malloc(3)
|
||||||
|
if path_buf is None or subdir_buf is None:
|
||||||
|
if path_buf is not None:
|
||||||
|
stdlib.free(path_buf)
|
||||||
|
if subdir_buf is not None:
|
||||||
|
stdlib.free(subdir_buf)
|
||||||
|
return 0
|
||||||
|
subdir_buf[0] = sha1[0]
|
||||||
|
subdir_buf[1] = sha1[1]
|
||||||
|
subdir_buf[2] = '\0'
|
||||||
|
viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll",
|
||||||
|
self.TempDir, subdir_buf, sha1)
|
||||||
|
stdlib.free(subdir_buf)
|
||||||
|
tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||||||
|
exists: int = 0
|
||||||
|
if not tf.closed:
|
||||||
|
tf.close()
|
||||||
|
exists = 1
|
||||||
|
stdlib.free(path_buf)
|
||||||
|
return exists
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
|
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
|
||||||
#
|
#
|
||||||
@@ -5997,6 +6103,71 @@ class CallGenMixin:
|
|||||||
re_inferred_ty: llvmlite.LLVMType | t.CPtr = self._infer_external_func_ret_ty(pool, orig_func_name)
|
re_inferred_ty: llvmlite.LLVMType | t.CPtr = self._infer_external_func_ret_ty(pool, orig_func_name)
|
||||||
if re_inferred_ty is not None:
|
if re_inferred_ty is not None:
|
||||||
call_ret_ty = re_inferred_ty
|
call_ret_ty = re_inferred_ty
|
||||||
|
# ============================================================
|
||||||
|
# 跨模块 Viper 函数返回类型精确解析(对齐方法路径,fail-fast)
|
||||||
|
# 根因:_infer_external_func_ret_ty 白名单未覆盖返回指针的模块函数
|
||||||
|
# (new_lexer→Lexer* / tokenize→Token* / parse_tokens→AST*),兜底 i32
|
||||||
|
# 导致 64 位指针被截断高 32 位 → inttoptr 无效指针 → 解引用崩溃
|
||||||
|
# (AstTest 的 _lexer_init 崩溃链)。declare 也可能是错误 i32(_ensure_method_declare
|
||||||
|
# 曾用兜底类型创建),因此不信任 found_func 的 declare 返回类型。
|
||||||
|
# 权威来源:text.ll define;次选:vpi stub 返回注解;均未命中立即终止。
|
||||||
|
# 仅对 mangled("{16位hex}.func")调用生效;C 库/Win32 裸名走原白名单。
|
||||||
|
# Phase 1a(declare_only)期间依赖 text.ll 未生成,保持原白名单行为不 fail-fast。
|
||||||
|
# ============================================================
|
||||||
|
if self._is_sha1_mangled_call(call_name) != 0:
|
||||||
|
if trans is None or trans._declare_only == 0:
|
||||||
|
cf_dot: t.CChar | t.CPtr = string.strchr(call_name, '.')
|
||||||
|
cf_last: t.CChar | t.CPtr = string.strrchr(call_name, '.')
|
||||||
|
if cf_dot is not None and cf_last is not None:
|
||||||
|
cf_sha1: t.CChar | t.CPtr = stdlib.malloc(17)
|
||||||
|
cf_bare_len: t.CSizeT = string.strlen(call_name) - \
|
||||||
|
(t.CSizeT(t.CUInt64T(cf_last) - t.CUInt64T(call_name))) - 1
|
||||||
|
cf_bare: t.CChar | t.CPtr = stdlib.malloc(cf_bare_len + 1)
|
||||||
|
if cf_sha1 is not None and cf_bare is not None:
|
||||||
|
string.strncpy(cf_sha1, call_name, 16)
|
||||||
|
cf_sha1[16] = '\0'
|
||||||
|
string.strcpy(cf_bare, cf_last + 1)
|
||||||
|
cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||||||
|
pool, cf_sha1, None, cf_bare, 1)
|
||||||
|
if cf_ret is not None:
|
||||||
|
call_ret_ty = cf_ret
|
||||||
|
else:
|
||||||
|
cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||||||
|
pool, cf_sha1, None, cf_bare)
|
||||||
|
if cf_vpi is not None:
|
||||||
|
call_ret_ty = cf_vpi
|
||||||
|
else:
|
||||||
|
# 区分两种失败场景:
|
||||||
|
# 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast
|
||||||
|
# 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按
|
||||||
|
# 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp
|
||||||
|
# (同项目多源文件)。此时标记 trans._deps_pending=1,
|
||||||
|
# 保持白名单类型继续,Phase A 多遍循环下遍重译——
|
||||||
|
# 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。
|
||||||
|
if self._dep_text_ll_exists(pool, cf_sha1) != 0:
|
||||||
|
cf_err: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if cf_err is not None:
|
||||||
|
viperlib.snprintf(
|
||||||
|
cf_err, 1024,
|
||||||
|
"跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中),"
|
||||||
|
"默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name)
|
||||||
|
VLogger.error(cf_err, "HandlesExprCall")
|
||||||
|
HandlesType.fatal_error(
|
||||||
|
node,
|
||||||
|
f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}",
|
||||||
|
"TypeError")
|
||||||
|
else:
|
||||||
|
if trans is not None:
|
||||||
|
trans._deps_pending = 1
|
||||||
|
cf_dbg: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if cf_dbg is not None:
|
||||||
|
viperlib.snprintf(
|
||||||
|
cf_dbg, 1024,
|
||||||
|
"跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序),"
|
||||||
|
"标记重试,本遍保持默认类型", call_name)
|
||||||
|
VLogger.warning(cf_dbg, "HandlesExprCall")
|
||||||
|
stdlib.free(cf_sha1)
|
||||||
|
stdlib.free(cf_bare)
|
||||||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can)
|
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can)
|
||||||
# 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升
|
# 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升
|
||||||
|
|||||||
@@ -132,6 +132,11 @@ class Translator:
|
|||||||
# Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译
|
# Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译
|
||||||
_declare_only: t.CInt
|
_declare_only: t.CInt
|
||||||
|
|
||||||
|
# Phase A 依赖未就绪标志:1=本文件翻译时依赖模块的 text.ll 尚未生成
|
||||||
|
# (同项目源文件按顺序翻译,main.vp 先于其 import 的 mbuddytest.vp),
|
||||||
|
# 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。
|
||||||
|
_deps_pending: t.CInt
|
||||||
|
|
||||||
# 子 Handle 指针(每个 Handle 一个槽,通过 Mixin 回指针访问本结构体)
|
# 子 Handle 指针(每个 Handle 一个槽,通过 Mixin 回指针访问本结构体)
|
||||||
AssignH: HandlesAssign.AssignHandle | t.CPtr
|
AssignH: HandlesAssign.AssignHandle | t.CPtr
|
||||||
ReturnH: HandlesReturn.ReturnHandle | t.CPtr
|
ReturnH: HandlesReturn.ReturnHandle | t.CPtr
|
||||||
@@ -175,6 +180,7 @@ class Translator:
|
|||||||
self.GenericTypeParamNames = None
|
self.GenericTypeParamNames = None
|
||||||
self.GenericTypeArgs = None
|
self.GenericTypeArgs = None
|
||||||
self._declare_only = 0
|
self._declare_only = 0
|
||||||
|
self._deps_pending = 0
|
||||||
self.AssignH = None
|
self.AssignH = None
|
||||||
self.ReturnH = None
|
self.ReturnH = None
|
||||||
self.ImportsH = None
|
self.ImportsH = None
|
||||||
|
|||||||
+127
-72
@@ -415,84 +415,139 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
if app_deps_buf is not None:
|
if app_deps_buf is not None:
|
||||||
app_deps_buf[0] = '\0'
|
app_deps_buf[0] = '\0'
|
||||||
|
|
||||||
for i in range(file_count):
|
# Phase A 多遍重试:同项目多源文件时,main.vp 可能先于其 import 的
|
||||||
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
# mbuddytest.vp 翻译(文件系统顺序),跨模块函数返回类型精确解析会因
|
||||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
# 依赖 text.ll 未生成而标记 _deps_pending=1(见 CallGenMixin 跨模块
|
||||||
if ent is None or ent.Path is None:
|
# 返回类型解析段)。下遍重译即可命中(依赖已生成 text.ll)。
|
||||||
continue
|
# 每遍至少完成一个文件,最多 file_count 遍收敛。
|
||||||
fb_loop: t.CChar | t.CPtr = VLogger.fmt_buf()
|
done_flags: bytes = stdlib.malloc(file_count)
|
||||||
if fb_loop is not None:
|
if done_flags is None:
|
||||||
viperlib.snprintf(fb_loop, 1024, "Phase A 开始翻译: %s", ent.Path)
|
VLogger.error("Phase A done_flags 分配失败", "PhaseA")
|
||||||
VLogger.info(fb_loop, "PhaseA-DBG")
|
stdlib.free(entries)
|
||||||
# 计算源文件的包名(相对 source_dir 的目录部分)
|
return 1
|
||||||
src_dir_len_pa: t.CSizeT = string.strlen(source_dir)
|
string.memset(done_flags, 0, file_count)
|
||||||
pkg_pa: str = None
|
PHASE_A_MAX_PASSES: t.CInt = 32
|
||||||
if string.strlen(ent.Path) > src_dir_len_pa + 1:
|
for pass_a in range(PHASE_A_MAX_PASSES):
|
||||||
rel_path_pa: str = ent.Path + src_dir_len_pa + 1
|
completed_this_pass: int = 0
|
||||||
pkg_pa = HandlesImports.compute_package_from_relpath(mb, rel_path_pa)
|
for i in range(file_count):
|
||||||
tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir)
|
if done_flags[i] != 0:
|
||||||
if tr_a is None:
|
continue
|
||||||
continue
|
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||||
fb_ok: t.CChar | t.CPtr = VLogger.fmt_buf()
|
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||||
if fb_ok is not None:
|
if ent is None or ent.Path is None:
|
||||||
viperlib.snprintf(fb_ok, 1024, "Phase A 翻译完成: %s", ent.Path)
|
done_flags[i] = 1
|
||||||
VLogger.info(fb_ok, "PhaseA-DBG")
|
completed_this_pass += 1
|
||||||
|
continue
|
||||||
|
fb_loop: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_loop is not None:
|
||||||
|
viperlib.snprintf(fb_loop, 1024, "Phase A 开始翻译: %s", ent.Path)
|
||||||
|
VLogger.info(fb_loop, "PhaseA-DBG")
|
||||||
|
# 计算源文件的包名(相对 source_dir 的目录部分)
|
||||||
|
src_dir_len_pa: t.CSizeT = string.strlen(source_dir)
|
||||||
|
pkg_pa: str = None
|
||||||
|
if string.strlen(ent.Path) > src_dir_len_pa + 1:
|
||||||
|
rel_path_pa: str = ent.Path + src_dir_len_pa + 1
|
||||||
|
pkg_pa = HandlesImports.compute_package_from_relpath(mb, rel_path_pa)
|
||||||
|
tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir)
|
||||||
|
if tr_a is None:
|
||||||
|
# 翻译失败(语法/解析错误):记录待下遍重试,收敛检查统一报错
|
||||||
|
continue
|
||||||
|
# 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)。
|
||||||
|
# 依赖在翻译早期已填充,即使 _deps_pending 也收集。
|
||||||
|
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 tr_a._deps_pending != 0:
|
||||||
|
# 依赖模块 text.ll 未生成(同项目文件顺序),不写盘,下遍重试
|
||||||
|
fb_dp: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_dp is not None:
|
||||||
|
viperlib.snprintf(fb_dp, 1024,
|
||||||
|
"Phase A 依赖未就绪,下遍重试: %s", ent.Path)
|
||||||
|
VLogger.warning(fb_dp, "PhaseA-DBG")
|
||||||
|
continue
|
||||||
|
fb_ok: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_ok is not None:
|
||||||
|
viperlib.snprintf(fb_ok, 1024, "Phase A 翻译完成: %s", ent.Path)
|
||||||
|
VLogger.info(fb_ok, "PhaseA-DBG")
|
||||||
|
|
||||||
# dump stub IR (declarations only)
|
# dump stub IR (declarations only)
|
||||||
stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||||
if stub_buf_a is None:
|
if stub_buf_a is None:
|
||||||
continue
|
continue
|
||||||
tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB)
|
tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB)
|
||||||
stub_len_a: t.CSizeT = string.strlen(stub_buf_a)
|
stub_len_a: t.CSizeT = string.strlen(stub_buf_a)
|
||||||
|
|
||||||
# save stub.ll (切片路径: temp_dir/{sha1前缀}/{sha1}.stub.ll)
|
# save stub.ll (切片路径: temp_dir/{sha1前缀}/{sha1}.stub.ll)
|
||||||
stub_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "stub.ll")
|
stub_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "stub.ll")
|
||||||
if stub_path_a is not None:
|
if stub_path_a is not None:
|
||||||
sf_a: fileio.File | t.CPtr = fileio.File(stub_path_a, fileio.MODE.W)
|
sf_a: fileio.File | t.CPtr = fileio.File(stub_path_a, fileio.MODE.W)
|
||||||
if not sf_a.closed:
|
if not sf_a.closed:
|
||||||
sf_a.write(stub_buf_a, stub_len_a)
|
sf_a.write(stub_buf_a, stub_len_a)
|
||||||
sf_a.close()
|
sf_a.close()
|
||||||
stdlib.free(stub_path_a)
|
stdlib.free(stub_path_a)
|
||||||
stdlib.free(stub_buf_a)
|
stdlib.free(stub_buf_a)
|
||||||
|
|
||||||
# dump text IR (definitions only)
|
# dump text IR (definitions only)
|
||||||
text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||||
if text_buf_a is None:
|
if text_buf_a is None:
|
||||||
continue
|
continue
|
||||||
tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
||||||
text_len_a: t.CSizeT = string.strlen(text_buf_a)
|
text_len_a: t.CSizeT = string.strlen(text_buf_a)
|
||||||
|
|
||||||
# save text.ll (切片路径)
|
# save text.ll (切片路径)
|
||||||
text_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "text.ll")
|
text_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "text.ll")
|
||||||
if text_path_a is not None:
|
if text_path_a is not None:
|
||||||
tf_a: fileio.File | t.CPtr = fileio.File(text_path_a, fileio.MODE.W)
|
tf_a: fileio.File | t.CPtr = fileio.File(text_path_a, fileio.MODE.W)
|
||||||
if not tf_a.closed:
|
if not tf_a.closed:
|
||||||
tf_a.write(text_buf_a, text_len_a)
|
tf_a.write(text_buf_a, text_len_a)
|
||||||
tf_a.close()
|
tf_a.close()
|
||||||
stdlib.free(text_path_a)
|
stdlib.free(text_path_a)
|
||||||
stdlib.free(text_buf_a)
|
stdlib.free(text_buf_a)
|
||||||
|
|
||||||
# save dependencies (_imported_modules) for Phase B (切片路径)
|
# save dependencies (_imported_modules) for Phase B (切片路径)
|
||||||
deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "deps.txt")
|
deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "deps.txt")
|
||||||
if deps_path_a is not None:
|
if deps_path_a is not None:
|
||||||
df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W)
|
df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W)
|
||||||
if not df_a.closed:
|
if not df_a.closed:
|
||||||
if tr_a._imported_modules is not None:
|
if tr_a._imported_modules is not None:
|
||||||
dl_a: t.CSizeT = string.strlen(tr_a._imported_modules)
|
dl_a: t.CSizeT = string.strlen(tr_a._imported_modules)
|
||||||
df_a.write(tr_a._imported_modules, dl_a)
|
df_a.write(tr_a._imported_modules, dl_a)
|
||||||
df_a.close()
|
df_a.close()
|
||||||
stdlib.free(deps_path_a)
|
stdlib.free(deps_path_a)
|
||||||
|
|
||||||
# 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)
|
done_flags[i] = 1
|
||||||
if tr_a._imported_modules is not None and app_deps_buf is not None:
|
completed_this_pass += 1
|
||||||
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:
|
all_done: int = 1
|
||||||
if app_deps_len > 0:
|
for i_ck in range(file_count):
|
||||||
app_deps_buf[app_deps_len] = ' '
|
if done_flags[i_ck] == 0:
|
||||||
app_deps_len = app_deps_len + 1
|
all_done = 0
|
||||||
string.strcpy(app_deps_buf + app_deps_len, tr_a._imported_modules)
|
break
|
||||||
app_deps_len = app_deps_len + im_len_a
|
if all_done != 0:
|
||||||
app_deps_buf[app_deps_len] = '\0'
|
break
|
||||||
|
if completed_this_pass == 0:
|
||||||
|
# 无进展:剩余文件无法完成(真实编译错误),终止并列出未完成文件
|
||||||
|
for i_err in range(file_count):
|
||||||
|
if done_flags[i_err] == 0:
|
||||||
|
ea_err: t.CUInt64T = t.CUInt64T(entries) + i_err * entry_size
|
||||||
|
ent_err: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_err, t.CPtr))
|
||||||
|
if ent_err is not None and ent_err.Path is not None:
|
||||||
|
fb_err: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_err is not None:
|
||||||
|
viperlib.snprintf(fb_err, 1024,
|
||||||
|
"Phase A 无法完成翻译: %s(请检查依赖模块是否已编译/注册)", ent_err.Path)
|
||||||
|
VLogger.error(fb_err, "PhaseA")
|
||||||
|
stdlib.free(done_flags)
|
||||||
|
VLogger.error("Phase A 多遍收敛失败,终止编译", "PhaseA")
|
||||||
|
stdlib.free(entries)
|
||||||
|
return 1
|
||||||
|
stdlib.free(done_flags)
|
||||||
|
|
||||||
if do_phase2 == 0:
|
if do_phase2 == 0:
|
||||||
VLogger.info("Phase A 完成(仅 stub 生成)", "project")
|
VLogger.info("Phase A 完成(仅 stub 生成)", "project")
|
||||||
|
|||||||
Reference in new issue
Block a user